From 5a3d796578fe944fe82cf71640484636701ce8ec Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Feb 2015 12:26:28 +0100 Subject: [PATCH 001/450] 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 000000000..404fddfcb --- /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 000000000..10fe223bc --- /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 002/450] 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 2a117d42d..fb5583bb2 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 003/450] 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 fb5583bb2..a0cf56ab4 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 a49e54dd3..f6b1c8cba 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 4f656f9c4..000000000 --- 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 7f9ebaae1..000000000 --- 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 0958c8f0c..bd6ea8075 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 017adf1e3..3024cb610 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 d06b3b485..000000000 --- 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 8c3fb7bef..000000000 --- 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 10fe223bc..318a02294 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 004/450] 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 | 95 ++++++++++++++++++----------------- 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, 187 insertions(+), 243 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0cf56ab4..cbe142fcc 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 f6b1c8cba..ecaeb115b 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 815aa7d3f..51890f069 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 9ae527e5a..718748c31 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 d9de12fb5..db5a5643d 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 cc1b0f41c..679557e25 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 4f3ee95cb..f7d864198 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)); - - // 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); - - /* The format for 10.0.1.0 seems to be a bit different. After the + 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); + + // 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 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; - - std::string rec = nif.getString(); - if(rec.empty()) - fail("Record number " + Ogre::StringConverter::toString(i) + " out of " + Ogre::StringConverter::toString(recNum) + " is blank."); + Record *r = NULL; + 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); - - if (entry != factories.end()) - { - r = entry->second.mCreate (); - r->recType = entry->second.mType; - } - else - fail("Unknown record type " + rec); + std::map::const_iterator entry = factories.find(rec); - assert(r != NULL); - assert(r->recType != RC_MISSING); - r->recName = rec; - r->recIndex = i; - records[i] = r; - r->read(&nif); + 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); } size_t rootNum = nif.getUInt(); diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index ceb9984fb..9f08f3f1d 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 e5699db7b..628541933 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 6c5e83eeb..b732c83af 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 786c48b65..864795afb 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 fb68da548..b0c5d990e 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 a26480d59..123b70cad 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 77f61d068..52ee7f6e1 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 005/450] 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 db5a5643d..656d27628 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 864795afb..4f6998200 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 123b70cad..7f94c0d05 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 52ee7f6e1..610f5427a 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 006/450] 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 404fddfcb..fddfa7e52 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 318a02294..069ceec58 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 007/450] 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 bbe475ff7..2762a1fc9 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 ebbc935f6..31fc3e32d 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 2df8e66ce..d9eb7290c 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 fddfa7e52..23eab2088 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 008/450] 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 98e18521e..3347aaf34 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 009/450] 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 ecaeb115b..43fca28e8 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 2762a1fc9..933d89099 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 d4d7c231a..000000000 --- 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 367defcbc..000000000 --- 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 010/450] 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 30c652b64..4b2e40dec 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 51890f069..ac75c3508 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 718748c31..73344e77b 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 4248b93d2..c4de1e1bf 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 656d27628..3b1244831 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 679557e25..fae1cd7f5 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 2913c62b0..1e5a8616d 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 b8b01513b..549ea3eb3 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 610f5427a..b06044e9f 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 07d7540f8..1022802cc 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 011/450] 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 cbe142fcc..d5b37a05b 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 000000000..265577d98 --- /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 000000000..fc82059fc --- /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 000000000..376a1fe12 --- /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 000000000..41dcb09de --- /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 000000000..b7e221668 --- /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 000000000..47c6d35b3 --- /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 000000000..4e600c3a1 --- /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 000000000..e45bc7fea --- /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 000000000..2eb57a4f8 --- /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 000000000..a089f7651 --- /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 012/450] 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 b06044e9f..2633b16c5 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 013/450] 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 2eb57a4f8..b895f8e13 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 014/450] Simplify controller classes --- components/nifosg/controller.cpp | 22 +++--- components/nifosg/controller.hpp | 118 +++++++++++++------------------ components/nifosg/nifloader.cpp | 8 +-- 3 files changed, 66 insertions(+), 82 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 4e600c3a1..086e679d6 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 e45bc7fea..d916f894f 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 { - 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 + 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; + osg::Quat mInitialQuat; + float mInitialScale; - using ValueInterpolator::interpKey; + using ValueInterpolator::interpKey; - osg::Quat interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time); + osg::Quat interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time); - osg::Quat getXYZRotation(float time) const; + 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); + 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, + osg::Quat initialQuat, float initialScale); - virtual osg::Vec3f getTranslation(float time) const; + 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; - - public: - Value(osg::StateSet* target, const Nif::NiUVData *data, std::set textureUnits); - - virtual void setValue(float value); - }; + UVControllerValue(osg::StateSet* target, const Nif::NiUVData *data, std::set textureUnits); + + virtual void setValue(float value); }; - class VisController + class VisControllerValue : public NodeTargetValue { - public: - class Value : public NodeTargetValue - { - private: - std::vector mData; + private: + std::vector mData; - bool calculate(float time) const; + bool calculate(float time) const; - public: - Value(osg::Node *target, const Nif::NiVisData *data) - : NodeTargetValue(target) - , mData(data->mVis) - { } + public: + VisControllerValue(osg::Node *target, const Nif::NiVisData *data) + : NodeTargetValue(target) + , mData(data->mVis) + { } - virtual osg::Vec3f getTranslation(float time) const - { return osg::Vec3f(); } + 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 b895f8e13..abeb17b6f 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 015/450] 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 086e679d6..8ac7f004c 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 d916f894f..af09bda64 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 abeb17b6f..ebc4911c8 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 a089f7651..3b2443eb9 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 016/450] 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 ebc4911c8..135578888 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 017/450] 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 8ac7f004c..041036e5b 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 af09bda64..421f00277 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 135578888..34c2f0ce0 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 3b2443eb9..7f4aa7ea4 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 018/450] 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 d5b37a05b..1059b1c3a 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 34c2f0ce0..feffe2cba 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 7f4aa7ea4..0535aa838 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 019/450] 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 fc82059fc..668bda373 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 020/450] 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 23eab2088..3e5d0c245 100644 --- a/components/files/constrainedfilestream.cpp +++ b/components/files/constrainedfilestream.cpp @@ -5,13 +5,16 @@ #include "lowlevelfile.hpp" -namespace Files +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 021/450] 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 1bcd2d31a..023f23815 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 022/450] 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 668bda373..16d1d58a3 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 023/450] 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 16d1d58a3..ef2ddd6b4 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 3024cb610..8a7576f92 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 feffe2cba..88c944e14 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 0535aa838..e52101525 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 000000000..b36c7117b --- /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 000000000..a527a6ad9 --- /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 000000000..961746947 --- /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 000000000..ad5150a44 --- /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 000000000..6c8e1b82b --- /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 000000000..82f4cd7be --- /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 000000000..31538cc99 --- /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 024/450] 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 ef2ddd6b4..05ed2408e 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 88c944e14..a1fcbcbc9 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 025/450] 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 05ed2408e..7f9649e2e 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 026/450] 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 7f9649e2e..4593217c8 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 027/450] 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 4593217c8..1c34afbc4 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 028/450] 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 d4a0a0df2..84a7ef568 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 dc08b352a..0c2635752 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 2ce3dce1e..1763f7777 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 a1fcbcbc9..1220bb258 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 029/450] 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 1c34afbc4..7f9a7ce3f 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 041036e5b..f6841ee61 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 421f00277..e82f49ec8 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 1220bb258..5cdaf13ce 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,44 +195,9 @@ namespace traverse(node,nv); } private: - 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); - } + // 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) @@ -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 e52101525..5a0c901c1 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 000000000..3fcc02bcf --- /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 000000000..0336d3392 --- /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 030/450] 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 e82f49ec8..cc176e76e 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 5cdaf13ce..a92baee79 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 031/450] 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 f6841ee61..bbb2f57fe 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 cc176e76e..c92a77816 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; + + 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; - osg::Vec3f interpKey(const Nif::Vector3KeyMap::MapType &keys, float time) const; + 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 3fcc02bcf..58501763b 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 0336d3392..13010fbac 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 032/450] 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 1d6b40d5f..3548c175a 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 1d31c8396..92fd40492 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); - - 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)); + //Ogre::Root::getSingleton().addResourceLocation ((mResources / "mygui").string(), + // "FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); - 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 273f0825b..da4d63985 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 b11561c13..eb5dcc64e 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 7dac660c3..0aa1cb4ad 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 13c8df84d..25fada93a 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 3607fb415..b54551c96 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 09f020354..000000000 --- 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 ec050cac4..000000000 --- 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 f565f5af0..000000000 --- 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 f8a78f329..000000000 --- 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 cf9edb548..90181a367 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 3db6ee4ed..22c6ed478 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 55cf039fc..3a660b5fd 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 699d6a7a5..c57038869 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 2cbe17dcf..4e23c185a 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 c5d969d0d..d0b52a9ff 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 475f9d01f..311b98039 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 1ef00a0e1..a0259a11f 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 033/450] 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 92fd40492..3c4ce6868 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 da4d63985..e973b9c55 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 9b807225c..ecff4bbed 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 25fada93a..158793173 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]!='\\')) - continue; - - if (extensions) - { - std::string::size_type index = iter->find_last_of ('.'); + std::string::size_type index = filepath.find_last_of ('.'); - if (index==std::string::npos) - continue; - - std::string extension = iter->substr (index+1); + if (index==std::string::npos) + continue; - int i = 0; + std::string extension = filepath.substr (index+1); - for (; extensions[i]; ++i) - if (extensions[i]==extension) - break; + int i = 0; - if (!extensions[i]) - continue; - } + for (; extensions[i]; ++i) + if (extensions[i]==extension) + break; - 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 9c1c76b6f..d6998da9f 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 50014f4b5..218937924 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 77f210c47..ee939389f 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 311b98039..a78f164a6 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 82f4cd7be..d0e0cf586 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 31538cc99..ebbec7d15 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 000000000..cd077356f --- /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 000000000..1ef13f0f9 --- /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 034/450] 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 | 482 ++---------------- 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, 115 insertions(+), 587 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1059b1c3a..17abedb4c 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 3548c175a..6976aec42 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 eb5dcc64e..e3d5d3cdd 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 a94f4f8ab..8edd9d58f 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 90181a367..84a5a5665 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 22c6ed478..1bc9c3c5c 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 da18e7c89..6982cad52 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 dd6a99c0f..7260ee242 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 3a660b5fd..82dc4c211 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" -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); - - 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())); -#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")); -#endif - - mWindow = Ogre::Root::getSingleton().createRenderWindow(windowTitle.str(), this->width(), this->height(), false, ¶ms); - - mViewport = mWindow->addViewport (mCamera); - mViewport->setBackgroundColour (Ogre::ColourValue (0.3,0.3,0.3,1)); - - Ogre::Real aspectRatio = Ogre::Real(width()) / Ogre::Real(height()); - mCamera->setAspectRatio(aspectRatio); - } - - SceneWidget::~SceneWidget() - { - if (mWindow) - Ogre::Root::getSingleton().destroyRenderTarget (mWindow); - - if (mSceneMgr) - Ogre::Root::getSingleton().destroySceneManager (mSceneMgr); - - } - - void SceneWidget::setVisibilityMask (unsigned int mask) - { - mViewport->setVisibilityMask (mask); - } - - void SceneWidget::setNavigation (Navigation *navigation) - { - if ((mNavigation = navigation)) - { - mNavigation->setFastModeFactor (mFast ? mFastFactor : 1); - if (mNavigation->activate (mCamera)) - mUpdate = true; - } - } - - void SceneWidget::addRenderTargetListener(Ogre::RenderTargetListener *listener) - { - mWindow->addListener(listener); - } - - void SceneWidget::removeRenderTargetListener(Ogre::RenderTargetListener *listener) - { - mWindow->removeListener(listener); - } +#include +#include - Ogre::Viewport *SceneWidget::getViewport() - { - if (!mWindow) - updateOgreWindow(); +#include - 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; +namespace CSVRender +{ - const QSize &newSize = e->size(); +SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) + : QWidget(parent, f) +{ - // TODO: Fix Ogre to handle this more consistently (fixed in 1.9) -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX - mWindow->resize(newSize.width(), newSize.height()); +#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 - mWindow->windowMovedOrResized(); + osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::CullDrawThreadPerContext; #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); + setThreadingModel(threadingModel); - break; + // disable the default setting of viewer.done() by pressing Escape. + setKeyEventSetsDone(0); - default: QWidget::keyReleaseEvent (event); - } - } + 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(); - void SceneWidget::wheelEvent (QWheelEvent *event) - { - if (mNavigation) - if (event->delta()) - if (mNavigation->wheelMoved (event->delta())) - mUpdate = true; - } + osgQt::GraphicsWindowQt* window = new osgQt::GraphicsWindowQt(traits.get()); + QLayout* layout = new QHBoxLayout(this); + layout->addWidget(window->getGLWidget()); + setLayout(layout); - void SceneWidget::leaveEvent (QEvent *event) - { - mDragging = false; - } + getCamera()->setGraphicsContext(window); - void SceneWidget::mouseMoveEvent (QMouseEvent *event) - { - if (event->buttons() & Qt::LeftButton) - { - if (mDragging) - { - QPoint diff = mOldPos-event->pos(); - mOldPos = event->pos(); + 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 ); - if (mNavigation) - if (mNavigation->mouseMoved (diff, mMod1 ? 1 : 0)) - mUpdate = true; - } - else - { - mDragging = true; - mOldPos = event->pos(); - } - } - } + osg::Node* root = new osg::Node; + setSceneData(root); - void SceneWidget::mouseReleaseEvent (QMouseEvent *event) - { - if (!(event->buttons() & Qt::LeftButton)) - mDragging = false; - } + setCameraManipulator(new osgGA::TrackballManipulator); - void SceneWidget::focusOutEvent (QFocusEvent *event) - { - mKeyForward = false; - mKeyBackward = false; - mKeyLeft = false; - mKeyRight = false; - mFast = false; - mMod1 = false; + // Only render when the camera position changed, or content flagged dirty + //setRunFrameScheme(osgViewer::ViewerBase::ON_DEMAND); - 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); - } + connect( &mTimer, SIGNAL(timeout()), this, SLOT(update()) ); + mTimer.start( 10 ); +} - void SceneWidget::updateUserSetting (const QString &key, const QStringList &list) - { - if(key.contains(QRegExp("^\\b(Objects|Shader|Scene)", Qt::CaseInsensitive))) - flagAsModified(); +void SceneWidget::paintEvent(QPaintEvent *event) +{ + frame(); +} - if(key == "3d-render/far-clip-distance" && !list.empty()) - { - if(mCamera->getFarClipDistance() != list.at(0).toFloat()) - mCamera->setFarClipDistance(list.at(0).toFloat()); - } +void SceneWidget::flagAsModified() +{ + _requestRedraw = true; +} - // 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 c57038869..0cdf1ef99 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: - - SceneWidget(QWidget *parent); - virtual ~SceneWidget(); - - QPaintEngine* paintEngine() const; - - 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. - - 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. + public: + SceneWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); - virtual void updateOverlay(); + virtual void paintEvent( QPaintEvent* event ); - virtual void mouseReleaseEvent (QMouseEvent *event); + void flagAsModified(); - virtual void mouseMoveEvent (QMouseEvent *event); + protected: - 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 462b62b7a..a269fab45 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 582ccea64..5ae5c8177 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 1ae466f42..0c9823c44 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 3fdf2f6e5..c59236ee5 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 035/450] 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 e688a9474..2a5fa7746 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 f3aef6db6..2d42e9903 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 ecff4bbed..edce6e613 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 a12d22c4e..8dc4f338a 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 a0d0f6e71..72ceb654a 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 b54551c96..2434343c9 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 "elements.hpp" +#include -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); - } -} +#include "elements.hpp" 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 3ed4fa793..8e9598bbf 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 Group; +} + +namespace VFS { - class SceneNode; + 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 6982cad52..ee43ac13c 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 7260ee242..dfe05b484 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 82dc4c211..2f28c06df 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 0cdf1ef99..3784a5c59 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 0c9823c44..c82d1b82e 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 5a0c901c1..7b38ce560 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 036/450] 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 | 391 ++++++++++++------ components/nifosg/controller.hpp | 144 ++++--- components/nifosg/nifloader.cpp | 103 +++-- components/nifosg/nifloader.hpp | 18 +- components/nifosg/particle.cpp | 1 + 7 files changed, 415 insertions(+), 253 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 7f9a7ce3f..fee919787 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); + if (hasInput()) + { + 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); + } - for (int i=0;i<3;++i) - for (int j=0;j<3;++j) - mat(i,j) *= scale; + traverse(node, nv); +} - if(mTranslations->mKeys.size() > 0) - mat.setTrans(interpKey(mTranslations->mKeys, time)); - trans->setMatrix(mat); +Controller::Controller() +{ } -Controller::Controller(boost::shared_ptr src, boost::shared_ptr dest, boost::shared_ptr function) - : mSource(src) - , mDestValue(dest) - , mFunction(function) +bool Controller::hasInput() const { + return mSource.get() != NULL; +} +float Controller::getInputValue(osg::NodeVisitor* nv) +{ + return mFunction->calculate(mSource->getValue(nv)); } -void Controller::update() +GeomMorpherController::GeomMorpherController() { - if (mSource.get()) - { - mDestValue->setValue(mFunction->calculate(mSource->getValue())); - } } -GeomMorpherControllerValue::GeomMorpherControllerValue(osgAnimation::MorphGeometry *geom, const Nif::NiMorphData* morphData) - : mGeom(geom) - , mMorphs(morphData->mMorphs) +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 GeomMorpherControllerValue::setValue(float time) +void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable) { - if (mMorphs.size() <= 1) - return; - int i = 0; - for (std::vector::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i) + osgAnimation::MorphGeometry* morphGeom = dynamic_cast(drawable); + if (morphGeom) { - 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); + 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(); } } -UVControllerValue::UVControllerValue(osg::StateSet *target, const Nif::NiUVData *data, std::set textureUnits) - : mStateSet(target) - , mUTrans(data->mKeyList[0]) +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]) @@ -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) +void UVController::operator()(osg::Node* node, osg::NodeVisitor* nv) +{ + if (hasInput()) { - mStateSet->setTextureAttributeAndModes(*it, texMat, osg::StateAttribute::ON); + 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 VisControllerValue::calculate(float time) const +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) +{ + if (hasInput()) + { + bool vis = calculate(getInputValue(nv)); + node->setNodeMask(vis ? ~0 : 0); + } + traverse(node, nv); +} + +AlphaController::AlphaController(const Nif::NiFloatData *data) + : mData(data->mKeyList) { - bool vis = calculate(time); - mNode->setNodeMask(vis ? ~0 : 0); + } -AlphaControllerValue::AlphaControllerValue(osg::StateSet *target, const Nif::NiFloatData *data) - : mTarget(target) - , mData(data->mKeyList) +AlphaController::AlphaController() { } -void AlphaControllerValue::setValue(float time) +AlphaController::AlphaController(const AlphaController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop), ValueInterpolator(), Controller(copy) { - 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); +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); } -MaterialColorControllerValue::MaterialColorControllerValue(osg::StateSet *target, const Nif::NiPosData *data) - : mTarget(target), mData(data->mKeyList) +MaterialColorController::MaterialColorController(const Nif::NiPosData *data) + : mData(data->mKeyList) { +} +MaterialColorController::MaterialColorController() +{ } -void MaterialColorControllerValue::setValue(float time) +MaterialColorController::MaterialColorController(const MaterialColorController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop), Controller(copy) + , mData(copy.mData) { - 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); +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); } -FlipControllerValue::FlipControllerValue(osg::StateSet* target, const Nif::NiFlipController *ctrl, - std::vector > textures) +FlipController::FlipController(const Nif::NiFlipController *ctrl, std::vector > textures) : mTexSlot(ctrl->mTexSlot) , mDelta(ctrl->mDelta) , mTextures(textures) - , mTarget(target) { } -void FlipControllerValue::setValue(float time) +FlipController::FlipController() +{ +} + +FlipController::FlipController(const FlipController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop) + , Controller(copy) + , mTexSlot(copy.mTexSlot) + , mDelta(copy.mDelta) + , mTextures(copy.mTextures) { - 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) +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() { } -void ParticleSystemControllerValue::setValue(float time) +ParticleSystemController::ParticleSystemController(const ParticleSystemController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop) + , Controller(copy) + , mEmitStart(copy.mEmitStart) + , mEmitStop(copy.mEmitStop) { - mEmitter->setEnabled(time >= mEmitStart && time < 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 c92a77816..5a9af6324 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(); + + bool hasInput() const; - virtual void update(); + 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 + class GeomMorpherController : public osg::Drawable::UpdateCallback, public Controller, public ValueInterpolator { - 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; } - }; + GeomMorpherController(const Nif::NiMorphData* data); + GeomMorpherController(); + GeomMorpherController(const GeomMorpherController& copy, const osg::CopyOp& copyop); - class GeomMorpherControllerValue : public ControllerValue, public ValueInterpolator - { - public: - // FIXME: don't copy the morph data? - GeomMorpherControllerValue(osgAnimation::MorphGeometry* geom, const Nif::NiMorphData *data); + META_Object(NifOsg, GeomMorpherController) - virtual void setValue(float time); + 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 operator() (osg::Node* node, osg::NodeVisitor* nv); - virtual void setValue(float time); + 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); + + META_Object(NifOsg, FlipController) - virtual void setValue(float time); + 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); + + META_Object(NifOsg, ParticleSystemController) - virtual void setValue(float time); + 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 a92baee79..26f0927b5 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 7b38ce560..5bd25f6ca 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 58501763b..f2f59195c 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 037/450] 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 fee919787..3e70c8cd2 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 509d20bbf..01671dbd8 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 26f0927b5..2fb60280b 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 038/450] 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 2fb60280b..5666fe07f 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 039/450] 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 5666fe07f..099288b4f 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 040/450] 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 099288b4f..30b3c6537 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 041/450] 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 30b3c6537..dcab80707 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 f2f59195c..77e5f16df 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 13010fbac..1f3905089 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 042/450] 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 2434343c9..f21e8dd4d 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 ee43ac13c..8802b5cf3 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 2f28c06df..2dc5bdbc6 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 dcab80707..27cce16fd 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 77e5f16df..934ef51eb 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 1f3905089..1c8174e8a 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 043/450] 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 a78f164a6..e0ddeb254 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 4f6998200..7fefb92a2 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 01671dbd8..d61a8937a 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 5a9af6324..fb24fb518 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 27cce16fd..edc011c54 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 934ef51eb..16c2b692c 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 1c8174e8a..01e06f471 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 000000000..9770890b0 --- /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 044/450] 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 c4de1e1bf..1fef8d56f 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 3b1244831..702fbf313 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 98687a2f9..d702d0292 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 d61a8937a..88802f81e 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 fb24fb518..eb9b95a81 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 edc011c54..1e69ee4f5 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 16c2b692c..25970c862 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 045/450] Add .kf loader --- components/nifosg/controller.cpp | 33 ++++++++ components/nifosg/controller.hpp | 37 +++++++-- components/nifosg/nifloader.cpp | 132 +++++++++++++++++++++++++++---- components/nifosg/nifloader.hpp | 20 +++-- 4 files changed, 193 insertions(+), 29 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 88802f81e..ef3157773 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 eb9b95a81..17bf3ae75 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); - - META_Object(NifOsg, KeyframeController) + SourcedKeyframeController(const Nif::NiKeyframeData* data, int sourceIndex); + SourcedKeyframeController(); + SourcedKeyframeController(const SourcedKeyframeController& copy, const osg::CopyOp& copyop); - 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 1e69ee4f5..c73bcbc96 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) + { + if(nif->numRoots() < 1) + { + nif->warn("Found no root nodes"); + 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); + + 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); + } + + 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); - 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; + nif->fail("First root was not a node, but a " + r->recName); } mRootNode = parentNode; - handleNode(nifNode, parentNode, false, std::map(), 0, 0); + + osg::Node* created = handleNode(nifNode, parentNode, false, std::map(), 0, 0); + return created; } - void Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode) + osg::Node* Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode) { mNif = nif; if (nif->numRoots() < 1) { - nif->warn("Found no root nodes"); - return; + //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 5bd25f6ca..18e3e7db8 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); + + /// Create a scene graph for the given NIF. Assumes skinning will be used. + osg::Node* loadAsSkeleton(Nif::NIFFilePtr file, osg::Group* parentNode); - void 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 046/450] 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 3e70c8cd2..c21f423bf 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 c73bcbc96..c05bad5ae 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 18e3e7db8..9fc262c70 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 047/450] 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 3c4ce6868..83fcb3e37 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 c05bad5ae..a37a13261 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 9fc262c70..8f9efe6b3 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 048/450] 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 | 76 ++++++++++++++--------- apps/opencs/view/render/scenewidget.hpp | 27 ++++++-- 3 files changed, 72 insertions(+), 33 deletions(-) diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index 8802b5cf3..c3f838435 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 2dc5bdbc6..195e550a3 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() { - frame(); + static CompositeViewer sThis; + return sThis; } -void SceneWidget::flagAsModified() +void CompositeViewer::update() { - _requestRedraw = true; + frame(); } } diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 3784a5c59..adb10b10a 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 049/450] Hide NIF loader details in the implementation file --- components/nifosg/nifloader.cpp | 1601 ++++++++++++++++--------------- components/nifosg/nifloader.hpp | 55 -- 2 files changed, 820 insertions(+), 836 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a37a13261..c00b4abe1 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) - { - nif->warn("Found no root nodes"); - return; - } - - const Nif::Record *r = nif->getRoot(0); - assert(r != NULL); + public: + const VFS::Manager* mResourceManager; + bool mShowMarkers; - if(r->recType != Nif::RC_NiSequenceStreamHelper) + LoaderImpl(const VFS::Manager* resourceManager, bool showMarkers) + : mResourceManager(resourceManager) + , mShowMarkers(showMarkers) { - 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) + void loadKf(Nif::NIFFilePtr nif, osg::Node *rootNode, int sourceIndex, TextKeyMap& textKeys) { - 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); + if(nif->numRoots() < 1) + { + nif->warn("Found no root nodes"); + return; + } - std::map controllerMap; + const Nif::Record *r = nif->getRoot(0); + assert(r != NULL); - 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(r->recType != Nif::RC_NiSequenceStreamHelper) { - nif->warn("Unexpected extra data "+extra->recName+" with controller "+ctrl->recName); - continue; + nif->warn("First root was not a NiSequenceStreamHelper, but a "+ + r->recName+"."); + return; } + const Nif::NiSequenceStreamHelper *seq = static_cast(r); - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; + 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; + } - const Nif::NiStringExtraData *strdata = static_cast(extra.getPtr()); - const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + extractTextKeys(static_cast(extra.getPtr()), textKeys); - if(key->data.empty()) - continue; + std::map controllerMap; - controllerMap[strdata->string] = key; - } - - LoadKfVisitor visitor(controllerMap, sourceIndex); - rootNode->accept(visitor); - } + 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; + } - osg::Node* Loader::load(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) - { - mNif = nif; + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; - if (nif->numRoots() < 1) - nif->fail("Found no root nodes"); + const Nif::NiStringExtraData *strdata = static_cast(extra.getPtr()); + const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); - const Nif::Record* r = nif->getRoot(0); + if(key->data.empty()) + continue; - const Nif::Node* nifNode = dynamic_cast(r); - if (nifNode == NULL) - nif->fail("First root was not a node, but a " + r->recName); + controllerMap[strdata->string] = key; + } - mRootNode = parentNode; + LoadKfVisitor visitor(controllerMap, sourceIndex); + rootNode->accept(visitor); + } - osg::Node* created = handleNode(nifNode, parentNode, false, std::map(), 0, 0, false, textKeys); - return created; - } + osg::Node* load(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) + { + if (nif->numRoots() < 1) + nif->fail("Found no root nodes"); - osg::Node* Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) - { - mNif = nif; + const Nif::Record* r = nif->getRoot(0); - if (nif->numRoots() < 1) - nif->fail("Found no root nodes"); + const Nif::Node* nifNode = dynamic_cast(r); + if (nifNode == NULL) + nif->fail("First root was not a node, but a " + r->recName); - const Nif::Record* r = nif->getRoot(0); - assert(r != NULL); + osg::Node* created = handleNode(nifNode, parentNode, false, std::map(), 0, 0, false, textKeys); + return created; + } - const Nif::Node* nifNode = dynamic_cast(r); - if (nifNode == NULL) - nif->fail("First root was not a node, but a " + r->recName); + osg::Node* loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) + { + if (nif->numRoots() < 1) + nif->fail("Found no root nodes"); - osg::ref_ptr skel = new osgAnimation::Skeleton; - parentNode->addChild(skel); + const Nif::Record* r = nif->getRoot(0); + assert(r != NULL); - mRootNode = parentNode; + const Nif::Node* nifNode = dynamic_cast(r); + if (nifNode == NULL) + nif->fail("First root was not a node, but a " + r->recName); - handleNode(nifNode, skel, true, std::map(), 0, 0, false, textKeys); + osg::ref_ptr skel = new osgAnimation::Skeleton; + parentNode->addChild(skel); - return skel; - } + handleNode(nifNode, skel, true, std::map(), 0, 0, false, textKeys); - 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) + void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map& boundTextures, int animflags) { - osgAnimation::Bone* bone = new osgAnimation::Bone; - transformNode = bone; - bone->setMatrix(toMatrix(nifNode->trafo)); - bone->setName(nifNode->name); - bone->setInvBindMatrixInSkeletonSpace(osg::Matrixf::inverse(getWorldTransform(nifNode))); + const Nif::PropertyList& props = nifNode->props; + for (size_t i = 0; i trafo)); - } - // Ignoring name for non-bone nodes for now. We might need it later in isolated cases, e.g. AttachLight. + //bool autoPlay = animflags & Nif::NiNode::AnimFlag_AutoPlay; + //if (autoPlay) + toSetup->mSource = boost::shared_ptr(new FrameTimeSource); - // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) - parentNode->insertChild(0, transformNode); + toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl, 1 /*autoPlay*/)); + } - // 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) + 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) { - if(e->recType == Nif::RC_NiTextKeyExtraData && textKeys) + osg::ref_ptr transformNode; + if (nifNode->recType == Nif::RC_NiBillboardNode) + { + transformNode = new BillboardNode(toMatrix(nifNode->trafo)); + } + else if (createSkeleton) { - const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); - extractTextKeys(tk, *textKeys); + 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 if(e->recType == Nif::RC_NiStringExtraData) + else { - 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) + 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) { - // Marker objects. These meshes are only visible in the editor. - skipMeshes = true; + 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; + 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); - } + // 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 + // 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); + 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->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->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->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) + handleParticleSystem(nifNode, transformNode, animflags, particleflags, rootNode); - if (!nifNode->controller.empty()) - handleNodeControllers(nifNode, transformNode, animflags); + 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); + // 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) + const Nif::NiNode *ninode = dynamic_cast(nifNode); + if(ninode) { - if(!children[i].empty()) - handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys); + 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; - } + 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) + void handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures, int animflags) { - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - if (ctrl->recType == Nif::RC_NiUVController) + for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { - 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); + 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); + osg::ref_ptr ctrl = new UVController(uvctrl->data.getPtr(), texUnits); + setupController(uvctrl, ctrl, animflags); + transformNode->getOrCreateStateSet()->setDataVariance(osg::StateSet::DYNAMIC); - transformNode->addUpdateCallback(ctrl); + 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) + void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) { - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - if (ctrl->recType == Nif::RC_NiKeyframeController) + for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { - 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); - transformNode->addUpdateCallback(callback); + setupController(key, callback, animflags); + transformNode->addUpdateCallback(callback); + } } - } - else if (ctrl->recType == Nif::RC_NiVisController) - { - const Nif::NiVisController* visctrl = static_cast(ctrl.getPtr()); + 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); + 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) + + 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_NiAlphaController) + for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { - 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); + 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; } - 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 handleTextureControllers(const Nif::Property *texProperty, 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 = texProperty->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_NiFlipController) { - 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::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); } - 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; } - 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) + void handleParticleAffectors(Nif::ExtraPtr e, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf) { - 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::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; + } } - std::vector targets; - if (partctrl->recType == Nif::RC_NiBSPArrayController) + + void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags, osg::Node* rootNode) { - getAllNiNodes(partctrl->emitter.getPtr(), targets); - } + 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; - osgParticle::ParticleProcessor::ReferenceFrame rf = (particleflags & Nif::NiNode::ParticleFlag_LocalSpace) - ? osgParticle::ParticleProcessor::RELATIVE_RF - : osgParticle::ParticleProcessor::ABSOLUTE_RF; + 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; + } - // TODO: also take into account the transform by placement in the scene - osg::Matrix particletransform; - if (rf == osgParticle::ParticleProcessor::ABSOLUTE_RF) - particletransform = getWorldTransform(nifNode); + std::vector targets; + if (partctrl->recType == Nif::RC_NiBSPArrayController) + { + getAllNiNodes(partctrl->emitter.getPtr(), targets); + } - 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; + osgParticle::ParticleProcessor::ReferenceFrame rf = (particleflags & Nif::NiNode::ParticleFlag_LocalSpace) + ? osgParticle::ParticleProcessor::RELATIVE_RF + : osgParticle::ParticleProcessor::ABSOLUTE_RF; - ParticleAgeSetter particletemplate(std::max(0.f, particle.lifetime)); + // TODO: also take into account the transform by placement in the scene + osg::Matrix particletransform; + if (rf == osgParticle::ParticleProcessor::ABSOLUTE_RF) + particletransform = getWorldTransform(nifNode); - 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); + 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; - osg::Vec4f partcolor (1.f,1.f,1.f,1.f); - if (particle.vertex < int(particledata->colors.size())) - partcolor = particledata->colors.at(particle.vertex); + ParticleAgeSetter particletemplate(std::max(0.f, particle.lifetime)); - float size = particledata->sizes.at(particle.vertex) * partctrl->size; + 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); - created->setSizeRange(osgParticle::rangef(size, size)); - } + osg::Vec4f partcolor (1.f,1.f,1.f,1.f); + if (particle.vertex < int(particledata->colors.size())) + partcolor = particledata->colors.at(particle.vertex); - partsys->setQuota(partctrl->numParticles); + float size = particledata->sizes.at(particle.vertex) * partctrl->size; - 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)); + created->setSizeRange(osgParticle::rangef(size, size)); + } - // ---- emitter + partsys->setQuota(partctrl->numParticles); - osg::ref_ptr emitter = new Emitter(targets); - emitter->setParticleSystem(partsys); - emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); + 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)); - 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 - emitter->setCounter(counter); + osg::ref_ptr emitter = new Emitter(targets); + emitter->setParticleSystem(partsys); + emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); - 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::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)); - 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->setCounter(counter); - emitter->setPlacer(placer); + 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); - // 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. + 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()); - // 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); - } - 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) + 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) { - // TODO: Implement? + std::cerr << "can't find emitter node, wrong node order?" << std::endl; + return; } - else - std::cerr << "Unhandled particle modifier " << e->recName << std::endl; - } + 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 geode (new osg::Geode); - geode->addDrawable(partsys); + osg::ref_ptr callback(new ParticleSystemController(partctrl)); + setupController(partctrl, callback, animflags); + emitter->setUpdateCallback(callback); - std::vector materialProps; - collectMaterialProperties(nifNode, materialProps); - applyMaterialProperties(geode, materialProps, true, animflags); + // affectors must be attached *after* the emitter in the scene graph for correct update order + handleParticleAffectors(partctrl->extra, emitterNode, partsys.get(), rf); - 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); + std::vector materialProps; + collectMaterialProperties(nifNode, materialProps); + applyMaterialProperties(geode, materialProps, true, animflags); - 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); - } + 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) - 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(); + 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); + } - const Nif::NiSkinInstance *skin = (triShape->skin.empty() ? NULL : triShape->skin.getPtr()); - if (skin) + // 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) { - // 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::NiTriShapeData* data = triShape->data.getPtr(); - const Nif::NiSkinData *skinData = skin->data.getPtr(); - const Nif::NodeList &bones = skin->bones; - for(size_t b = 0;b < bones.length();b++) + const Nif::NiSkinInstance *skin = (triShape->skin.empty() ? NULL : triShape->skin.getPtr()); + if (skin) { - 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++) + // 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++) { - size_t index = weights[i].vertex; - float weight = weights[i].weight; + osg::Matrixf mat = toMatrix(skinData->bones[b].trafo); + + mat = mat * getWorldTransform(bones[b].getPtr()); - 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) + const std::vector &weights = skinData->bones[b].weights; + for(size_t i = 0;i < weights.size();i++) { - 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()); + 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); } - // 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()) + else { - // 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->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->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) + 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()) { - 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; + // 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; } - } while(!(ctrl=ctrl->next).empty()); - } - if (!geometry.get()) - geometry = new osg::Geometry; + geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[uvSet].size(), &data->uvlist[uvSet][0]), osg::Array::BIND_PER_VERTEX); + } - osg::ref_ptr geode (new osg::Geode); - geode->setName(triShape->name); // name will be used for part filtering - triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); + if (!data->colors.empty()) + geometry->setColorArray(new osg::Vec4Array(data->colors.size(), &data->colors[0]), osg::Array::BIND_PER_VERTEX); - geode->addDrawable(geometry); + geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, + data->triangles.size(), + (unsigned short*)&data->triangles[0])); - parentNode->addChild(geode); - } + // 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::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++) + void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags) { - 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++) + osg::ref_ptr geometry; + if(!triShape->controller.empty()) { - osgAnimation::VertexIndexWeight indexWeight = std::make_pair(weights[j].vertex, weights[j].weight); - influence.push_back(indexWeight); - } + Nif::ControllerPtr ctrl = triShape->controller; + do { + if(ctrl->recType == Nif::RC_NiGeomMorpherController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) + { + geometry = handleMorphGeometry(static_cast(ctrl.getPtr())); - map->insert(std::make_pair(boneName, influence)); - } - rig->setInfluenceMap(map); + 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 trans(new osg::MatrixTransform); - trans->setUpdateCallback(new InvertBoneMatrix()); + if (!geometry.get()) + geometry = new osg::Geometry; - geode->addDrawable(rig); + osg::ref_ptr geode (new osg::Geode); + geode->setName(triShape->name); // name will be used for part filtering + triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); - trans->addChild(geode); - parentNode->addChild(trans); - } + geode->addDrawable(geometry); - void Loader::handleProperty(const Nif::Property *property, const Nif::Node* nifNode, - osg::Node *node, std::map& boundTextures, int animflags) - { - osg::StateSet* stateset = node->getOrCreateStateSet(); + parentNode->addChild(geode); + } - switch (property->recType) + osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) { - case Nif::RC_NiStencilProperty: + 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) { - const Nif::NiStencilProperty* stencilprop = static_cast(property); - osg::FrontFace* frontFace = new osg::FrontFace; - switch (stencilprop->data.drawMode) + 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++) { - case 1: - frontFace->setMode(osg::FrontFace::CLOCKWISE); - break; - case 0: - case 2: - default: - frontFace->setMode(osg::FrontFace::COUNTER_CLOCKWISE); - break; + 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); - stateset->setAttribute(frontFace, osg::StateAttribute::ON); - stateset->setMode(GL_CULL_FACE, stencilprop->data.drawMode == 3 ? osg::StateAttribute::OFF - : osg::StateAttribute::ON); + osg::ref_ptr trans(new osg::MatrixTransform); + trans->setUpdateCallback(new InvertBoneMatrix()); - // 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); + geode->addDrawable(rig); - 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; + trans->addChild(geode); + parentNode->addChild(trans); } - case Nif::RC_NiAlphaProperty: + + + void handleProperty(const Nif::Property *property, const Nif::Node* nifNode, + osg::Node *node, std::map& boundTextures, int animflags) { - 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); + osg::StateSet* stateset = node->getOrCreateStateSet(); - bool noSort = (alphaprop->flags>>13)&1; - if (!noSort) + switch (property->recType) + { + case Nif::RC_NiStencilProperty: + { + const Nif::NiStencilProperty* stencilprop = static_cast(property); + osg::FrontFace* frontFace = new osg::FrontFace; + switch (stencilprop->data.drawMode) { - stateset->setNestRenderBins(false); - stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + 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); + */ } - else + case Nif::RC_NiWireframeProperty: { - stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::OFF); - stateset->setNestRenderBins(false); - stateset->setRenderingHint(osg::StateSet::OPAQUE_BIN); + 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; } - - osg::AlphaFunc* alphafunc = new osg::AlphaFunc; - if((alphaprop->flags>>9)&1) + case Nif::RC_NiZBufferProperty: { - alphafunc->setFunction(getTestMode((alphaprop->flags>>10)&0x7), alphaprop->data.threshold/255.f); - stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::ON); + 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; } - 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) + // 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) { - 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; - } + blendfunc->setFunction(getBlendMode((alphaprop->flags>>1)&0xf), + getBlendMode((alphaprop->flags>>5)&0xf)); + stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON); - const Nif::NiTexturingProperty::Texture& tex = texprop->textures[i]; - if(tex.texture.empty()) + bool noSort = (alphaprop->flags>>13)&1; + if (!noSort) { - std::cerr << "Warning: texture layer " << i << " is in use but empty " << std::endl; - continue; + stateset->setNestRenderBins(false); + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); } - 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); + } + else + { + stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::OFF); + stateset->setNestRenderBins(false); + stateset->setRenderingHint(osg::StateSet::OPAQUE_BIN); + } - 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) + 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) { - // untested - osg::TexEnv* texEnv = new osg::TexEnv; - texEnv->setMode(osg::TexEnv::MODULATE); - stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + 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 (i == Nif::NiTexturingProperty::DetailTexture) + else if (boundTextures.find(i) != boundTextures.end()) { - // 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); + stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); + boundTextures.erase(i); } - - boundTextures[i] = tex.uvSet; + handleTextureControllers(texprop, node, stateset, animflags); } - 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; } - 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_NiDitherProperty: { - case Nif::RC_NiSpecularProperty: - { - specFlags = property->flags; + stateset->setMode(GL_DITHER, property->flags != 0 ? osg::StateAttribute::ON + : osg::StateAttribute::OFF); break; } - case Nif::RC_NiMaterialProperty: + default: + std::cerr << "Unhandled " << property->recName << std::endl; + break; + } + } + + void 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::NiMaterialProperty* matprop = static_cast(property); + 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->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); + 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); + 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 Nif::RC_NiVertexColorProperty: { - 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; + 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); } - if (specFlags == 0) - mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f,0.f,0.f,0.f)); + }; + + 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); + } - stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); + 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 8f9efe6b3..7ccbbfd2c 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 050/450] 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 c21f423bf..0da95d13d 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 f21e8dd4d..f48fcc440 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 c00b4abe1..60e94c67a 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 7ccbbfd2c..d38b88f97 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 051/450] 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 60e94c67a..b41bc075f 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 052/450] 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 b41bc075f..6a2523120 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 d38b88f97..43eb8da78 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 053/450] 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 e0ddeb254..48de580bc 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 cc750ea65..000000000 --- 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 90930bca8..000000000 --- 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 6be52d1a5..000000000 --- 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 85c3a7b65..000000000 --- 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 731e49c90..000000000 --- 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 17df7a3cd..000000000 --- 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 c13532644..000000000 --- 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 4fec2d29e..000000000 --- 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 6efc669fe..000000000 --- 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 db6a753c5..000000000 --- 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 9ec3a0c82..000000000 --- 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 574b67f19..e8ca2e8bd 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 9613421f7..d1743950f 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 054/450] 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 6a2523120..2ed91d467 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 055/450] 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 0da95d13d..253b5f99d 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 2633b16c5..96156c6d8 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 2ed91d467..45619b21b 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 056/450] 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 45619b21b..199fdb984 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 057/450] 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 199fdb984..ea59b9bd2 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 058/450] 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 ef3157773..0e1f15f0f 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 17bf3ae75..c6ef74d2a 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 ea59b9bd2..d05758f2e 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 059/450] 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 0e1f15f0f..a31263d8b 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 25970c862..899ce7537 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 060/450] 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 526b2eca3..9db0c4a6f 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 ac75c3508..36d90b03d 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 376a1fe12..f39132543 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 73344e77b..0861dfa6b 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 d05758f2e..a2fd8e39a 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 899ce7537..0afbf5e95 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 01e06f471..99db3c83a 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 061/450] 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 a2fd8e39a..c6927cfad 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 062/450] 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 253b5f99d..0f2e43a56 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 f48fcc440..bd44ba577 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 f7d864198..a73985cfb 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 9f08f3f1d..ae5aca5ac 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 7f94c0d05..b47c05281 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 c6927cfad..3c15b57ae 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 43eb8da78..87d1a0a99 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 063/450] 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 3c15b57ae..a15ad7416 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 064/450] 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 a31263d8b..6aa920553 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; + + float cycles = ( time - mStartTime ) / delta; + float remainder = ( cycles - std::floor( cycles ) ) * delta; - value = std::min(mStopTime, std::max(mStartTime, value+mPhase)); - return value; + // 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 c6ef74d2a..7579735ca 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 a15ad7416..17a669312 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 065/450] 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 17a669312..bdd40e245 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 066/450] 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 6976aec42..4f6b2a875 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 2a5fa7746..7f3d98d0c 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 2d42e9903..292b292df 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 72ceb654a..28ce1dd6c 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 73d794948..8c7d7e23a 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 8edd9d58f..000000000 --- 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 70e18427f..000000000 --- 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 bd44ba577..9bc7aa260 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 8e9598bbf..431867d6b 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 84a5a5665..ca4678d49 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 3be791f23..fd63567c7 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 5ae5c8177..68a3acdb9 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 b19197e36..ea344f04a 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 4e23c185a..000000000 --- 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 0036bf769..000000000 --- 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 067/450] 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 | 175 +-------- .../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, 98 insertions(+), 656 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 4f6b2a875..4e360f6eb 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 67f6822c7..07b18cc23 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 02f7bc452..bb4c9a4a8 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 158793173..4dd480e77 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 218937924..3e2f72d93 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 ee939389f..1ce06f2d3 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 28ce1dd6c..2c540dee6 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 8c7d7e23a..259ab1779 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 9bc7aa260..50c227d49 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); - - 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); + 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); - // 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 431867d6b..9efbcf5dc 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 ca4678d49..737a64efa 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::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; - } + //std::string name = cells.getRecord(index).get().mName; + //std::string region = cells.getRecord(index).get().mRegion; + + // cell marker update goes here + ++iter; } } } - //if (mCells.begin()==mCells.end()) - //setCamera = true; - // add for (CSMWorld::CellSelection::Iterator iter (mSelection.begin()); iter!=mSelection.end(); ++iter) @@ -110,111 +64,18 @@ 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; } } - 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); -} + if (modified) + mView->setCameraManipulator(new osgGA::TrackballManipulator); -void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) -{ - WorldspaceWidget::mouseDoubleClickEvent(event); + return modified; } void CSVRender::PagedWorldspaceWidget::addVisibilitySelectorButtons ( @@ -344,25 +205,9 @@ CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() { for (std::map::iterator iter (mCells.begin()); 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 1bc9c3c5c..64a0bccd1 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 c3f838435..22185effc 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 195e550a3..98ddf67c3 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 656ea959c..000000000 --- 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 dbb347e56..000000000 --- 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 fd63567c7..46c010fd2 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 68a3acdb9..f5068bb47 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 068/450] 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 0f2e43a56..dec038825 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 069/450] 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 50c227d49..f8e91e463 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 98ddf67c3..16ad2e68a 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 adb10b10a..04025340d 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 f5068bb47..1026aab58 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 070/450] 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 737a64efa..2b53483ad 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 22185effc..02fcd9f06 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 dfe05b484..58a7d8552 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 46c010fd2..e48b84cff 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 1026aab58..4bbfd5bcd 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 ea344f04a..e935daae2 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 c82d1b82e..0c9823c44 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 071/450] 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 bdd40e245..df912728b 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 072/450] 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 0afbf5e95..791847cd6 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 073/450] 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 07b18cc23..77724c997 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 bb4c9a4a8..ce8776104 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 f8e91e463..afed837f8 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 9efbcf5dc..23a652792 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 48de580bc..70c9daa8b 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 000000000..e87ef6f10 --- /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 000000000..b696a2376 --- /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 000000000..b6a09f3a7 --- /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 000000000..7922f3a49 --- /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 000000000..f124d7de7 --- /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 000000000..662dad543 --- /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 d0e0cf586..829e08978 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 ebbec7d15..f74914977 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 074/450] 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 1fef8d56f..4c9373029 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 702fbf313..e3f1e2770 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 df912728b..6e9de08f8 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 075/450] 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 6e9de08f8..1a36af4c4 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 791847cd6..afa76468a 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 076/450] 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 1a36af4c4..3b68df562 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 077/450] 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 afa76468a..c6e5fa9a8 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 078/450] 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 afed837f8..ec184a563 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 e40253a60..4cea62133 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 3b68df562..7e1c27b0e 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 b6a09f3a7..c7fd5065e 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 7922f3a49..76b69be6e 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 079/450] *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 dec038825..332867be5 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 16ad2e68a..d7a85410b 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 161c9ce4a..47fcf2499 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 6aa920553..eca5a7d79 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 7579735ca..0e5885333 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 7e1c27b0e..ace14c669 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 87d1a0a99..716cd1957 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 e87ef6f10..215b1a67c 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 b696a2376..a91f3cab3 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 c7fd5065e..c44cbd2ae 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 76b69be6e..3d439c186 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 000000000..8347d5f04 --- /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 000000000..c0b36f7cf --- /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 080/450] 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 8347d5f04..d0d32a40e 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 c0b36f7cf..f4ade515d 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 081/450] 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 a1da9f7e3..eb8c97b12 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 a342ab093..6d3d4d790 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; + + // FIXME: ambient should be applied to LightModel instead of the light - mSceneManager->setAmbientLight (Ogre::ColourValue (1.0, 1.0, 1.0, 1)); + 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)); - 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)); + 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 bc01899cb..e7ef63f0a 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 c5189ccfd..1d8444bc3 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 8638146e2..a0f39b866 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 7d94dc964..81236ec13 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 47d1d7ce8..b2fd17893 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 02fcd9f06..f0cbc939a 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 d7a85410b..ef2d701c6 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 04025340d..8580a2bb1 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 e48b84cff..a6d18a0f2 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 4bbfd5bcd..2d7a0a0f8 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 0c9823c44..1c2d6b95c 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 c59236ee5..3fdf2f6e5 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 7ef8102c2..d261d7247 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 c44cbd2ae..3f38762ca 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 3d439c186..7b3bcb2d5 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 082/450] 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 eca5a7d79..76d3c5e62 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 083/450] 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 3553ef58c..8e068168f 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 eb8c97b12..a4315d02f 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 6d3d4d790..035e57c56 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 e7ef63f0a..bc6422814 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 1d8444bc3..376f3e432 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 a0f39b866..407933ec6 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 81236ec13..18a12d63d 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 b2fd17893..8743cc438 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 ef2d701c6..593775970 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 8580a2bb1..acfc0bbd4 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 084/450] 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 c6e5fa9a8..c86a79af8 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 085/450] 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 47fcf2499..9d9ae4f31 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 000000000..7cfb80b5c --- /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 000000000..72f7809e9 --- /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 086/450] 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 7cfb80b5c..6208d0152 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 087/450] 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 ace14c669..9006c16ef 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 088/450] 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 0aa1cb4ad..ed8fbf6d0 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 089/450] 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 cd077356f..69d4498bb 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 090/450] Billboard scaling fix and culling bug fix --- CMakeLists.txt | 2 +- components/nifosg/nifloader.cpp | 65 ++++++++++++++++++++------------- 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0785ef28c..cde53f27a 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 9006c16ef..555105e35 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) {} + BillboardCallback() + { + } + BillboardCallback(const BillboardCallback& copy, const osg::CopyOp& copyop) + : osg::NodeCallback(copy, copyop) + { + } - META_Node(NifOsg, BillboardNode) + META_Object(NifOsg, BillboardCallback) - virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { - if (_referenceFrame==RELATIVE_RF) + osgUtil::CullVisitor* cv = dynamic_cast(nv); + osg::MatrixTransform* billboardNode = dynamic_cast(node); + if (billboardNode && cv) { - const NifOsg::NodeUserData* userdata = static_cast(getUserDataContainer()->getUserObject(0)); + osg::Matrix modelView = *cv->getModelViewMatrix(); - matrix.preMult(_matrix); - matrix.setRotate(osg::Quat()); - matrix(0,0) = userdata->mScale; - matrix(1,1) = userdata->mScale; - matrix(2,2) = userdata->mScale; - } - else // absolute - { - matrix = _matrix; + // 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 091/450] 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 cde53f27a..bf525646d 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 a183d172d..56ee82d7d 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 a4bb8c538..c7a92e52e 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 3b088595c..ef26ceb3a 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 8404b9523..ac99fa4b4 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 1d58dc87e..3dcb57fbb 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 668253712..475428f33 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 9c64f94ca..82e0b9699 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 761a89ca6..d96255c85 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 eb458be50..2323d39e7 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 80b246e84..c3932d388 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 36940113e..1da2ab879 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 02e8ffdfe..d65e242de 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 a80b3e4c5..68d2e28de 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 8f595df80..5c0fd773d 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 f908a9dd0..af4332c7c 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 be16af5d1..f188af2b3 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 d022c8e25..980afdfae 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 c744d3ed6..80806941c 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 c597cfaeb..8770bab38 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 4e03b788a..8b63ab541 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 f865de377..4ead16c5b 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 ee44328eb..75aa6e98a 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 718624a16..888955391 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 279c2f22e..bc7bb0bb5 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 675bd160a..3161bb413 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 2f68087e5..e570d1c33 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 58c42ddb8..319d01495 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 0d4518f87..abfc793de 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 d08334ae8..30cc207f7 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 8a43cc932..a7d3545b3 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 668031141..daf4424c5 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 3da6c40c8..878712ecc 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 4f6c1bec2..887ea68d1 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 bdaa2d515..3c6a507e7 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 adfe5ca26..b2f07ab0f 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 8fb1ee53c..c64a265ac 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 9f029c1b9..5bfd8ae77 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 a8c04aa4b..fab65b152 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 06c40dd8e..5fc39f03e 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 d31ae520b..a59efecfe 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 8d689240b..6d7408607 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 a9d80bf17..341a89a78 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 a9ca8e72b..82814b623 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 013386f8f..8b2035fe9 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 63d6506de..07698aae5 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 40fa2373f..b5c4e8ade 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 9d9ae4f31..1debf3495 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 933d89099..87c000d9a 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 89062bd27..709008a90 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 eb7dd901d..1b61aea90 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 972cf1b84..000000000 --- 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 edff876d4..000000000 --- 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 65f9b477a..000000000 --- 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 3542becf6..492a6323b 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 092/450] 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 bf525646d..77bea373f 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 103a56ecc..bae1ec4d4 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 56ee82d7d..50aeafc2a 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 cce5abd36..e3bae1173 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 daf2a9df8..000000000 --- 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 570e81d4a..000000000 --- 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 3564c45f6..000000000 --- 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 b9cf58e23..000000000 --- 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 37d004638..000000000 --- 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 c04ebd374..000000000 --- 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 fb8f596dc..000000000 --- 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 d08599a04..000000000 --- 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 135e81987..000000000 --- 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 1bbdbe5a9..000000000 --- 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 71b47feb1..000000000 --- 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 c1d2c960b..000000000 --- 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 b4e19b087..000000000 --- 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 eead159f0..000000000 --- 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 0bf30f6dd..000000000 --- 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 8c58d0e66..000000000 --- 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 2b1e8040d..000000000 --- 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 a2c52dc2f..000000000 --- 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 3f0dc295c..000000000 --- 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 f1a716a9f..000000000 --- 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 2a20bbb39..000000000 --- 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 637fe11b0..000000000 --- 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 f96927764..000000000 --- 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 ccf07b62b..000000000 --- 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 d98c8c9b2..000000000 --- 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 63de7d141..000000000 --- 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 b27c8357d..000000000 --- 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 f24561cf7..000000000 --- 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 1687d5ed1..000000000 --- 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 d89bcf3ad..000000000 --- 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 d7c4234cb..000000000 --- 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 721b4af7d..000000000 --- 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 6b271cb86..000000000 --- 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 c69d13401..000000000 --- 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 72c78c7b7..000000000 --- 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 a628cd64c..000000000 --- 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 3d83d8fa3..000000000 --- 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 0e3078af3..000000000 --- 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 5ca400fd4..000000000 --- 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 3eb7f4ad3..000000000 --- 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 d3156e680..000000000 --- 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 26481aa03..000000000 --- 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 7ee30ae7f..000000000 --- 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 8592712fa..000000000 --- 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 13809443e..000000000 --- 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 bafe07fc8..000000000 --- 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 89720fb5d..000000000 --- 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 270aaba68..000000000 --- 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 76326ce0c..000000000 --- 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 8fb530d39..000000000 --- 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 988c6769f..000000000 --- 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 e71854019..000000000 --- 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 42673ed9b..000000000 --- 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 04560e1f9..000000000 --- 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 67a2c26e8..000000000 --- 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 f45e64155..000000000 --- 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 acfc5a362..000000000 --- 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 5cd501094..000000000 --- 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 e7cfd4e33..000000000 --- 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 aa01c8ba1..000000000 --- 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 d3a1a8360..000000000 --- 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 ad8e6d2b0..000000000 --- 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 0f1914f62..000000000 --- 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 613321990..000000000 --- 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 492a6323b..eaf92c673 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 741b672ff..000000000 --- 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 9bdc4c137..000000000 --- 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 093/450] 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 77bea373f..5e510b29d 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 265577d98..000000000 --- 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 332867be5..000000000 --- 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 094/450] 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 76d3c5e62..463eb9e45 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 095/450] 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 ed90b0475..b0ab89bed 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 45b05136a..d912d1058 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 096/450] 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 463eb9e45..5916359c8 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 0e5885333..80e6090e4 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 555105e35..94885a11b 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 716cd1957..1c403a4fe 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 3f38762ca..e626a9f08 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 7b3bcb2d5..4d6ad4855 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 097/450] 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 94885a11b..dd9dbc328 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 098/450] 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 c86a79af8..143a73e08 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 099/450] 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 9db0c4a6f..bf391d388 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 100/450] 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 dd9dbc328..2a3d0322d 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 143a73e08..c4bf69579 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; - - int n = mCounter->numParticlesToCreate(dt); + osg::Matrix emitterToPs = ltw * worldToPs; - 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 e626a9f08..ead6a9669 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 101/450] 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 bda9cb8de..000000000 --- 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 102/450] 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 c4bf69579..59a4a981b 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 103/450] 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 2a3d0322d..b077c32ff 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 104/450] 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 b077c32ff..9df27df32 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 105/450] 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 dbbe7e43a..834ce129e 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 106/450] *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 1debf3495..abce7020c 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 9df27df32..a5c9b6e2a 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 6208d0152..47efe986c 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 000000000..c49cf77b8 --- /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 000000000..ccb6603a6 --- /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 000000000..0d99e762d --- /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 000000000..59c706f11 --- /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 107/450] 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 5e510b29d..77bea373f 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 000000000..265577d98 --- /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 000000000..332867be5 --- /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 108/450] 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 a6d18a0f2..dec7d493e 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 0d99e762d..a41c6b74b 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 a8d970df1..c99771c5e 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 109/450] 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 5916359c8..59ba9ad4f 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 80e6090e4..1a90b8759 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 a5c9b6e2a..a85847351 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 110/450] 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 | 1542 +---------------- apps/openmw/mwrender/animation.hpp | 198 +-- apps/openmw/mwrender/objects.cpp | 245 ++- apps/openmw/mwrender/objects.hpp | 57 +- apps/openmw/mwrender/renderingmanager.cpp | 1060 +---------- 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, 636 insertions(+), 3173 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 332867be5..487a91890 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 50aeafc2a..e10688149 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 c7a92e52e..0d0294fa7 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 ef26ceb3a..de09082d8 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 457b0cec1..2621f5e52 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 5f49a74b6..ac23744e8 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 ac99fa4b4..c1b8177f7 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 2d39881b1..f46ede730 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 90c708f97..2cf31d996 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 3dcb57fbb..506852a90 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 bc7bb0bb5..319e1d7ec 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 d277b1249..685051860 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 c5fc34507..64456dd11 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 20b87a3a9..76c472001 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 abfc793de..0b3390271 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 a7d3545b3..5f4d986b4 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 887ea68d1..931c5bbd5 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 871561bdc..85d9546aa 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) - { - mSkelBase = mObjectRoot->mSkelBase; - - Ogre::AnimationStateSet *aset = mObjectRoot->mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); - while(asiter.hasMoreElements()) - { - Ogre::AnimationState *state = asiter.getNext(); - state->setEnabled(false); - state->setLoop(false); - } - - // Set the bones as manually controlled since we're applying the - // transformations manually - Ogre::SkeletonInstance *skelinst = mObjectRoot->mSkelBase->getSkeleton(); - Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); - while(boneiter.hasMoreElements()) - boneiter.getNext()->setManuallyControlled(true); - - // Reattach any objects that have been attached to this one - ObjectAttachMap::iterator iter = mAttachedObjects.begin(); - while(iter != mAttachedObjects.end()) - { - 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()); - } - else - { - bone->_setDerivedOrientation(srcbone->_getDerivedOrientation()); - bone->_setDerivedPosition(srcbone->_getDerivedPosition()); - bone->setScale(Ogre::Vector3::UNIT_SCALE); - } - } - - 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) + Animation::Animation(const MWWorld::Ptr &ptr, osg::ref_ptr node, Resource::ResourceSystem* resourceSystem) + : mPtr(ptr) + , mInsert(node) + , mResourceSystem(resourceSystem) { - 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++) + Animation::~Animation() { - 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); + if (mObjectRoot) + mInsert->removeChild(mObjectRoot); } - mNonAccumCtrl = NULL; - - if(!mNonAccumRoot || mAccumulate == Ogre::Vector3(0.0f)) - return; - AnimStateMap::const_iterator state = mStates.find(mAnimationTimePtr[0]->getAnimName()); - if(state == mStates.end()) + osg::Vec3f Animation::runAnimation(float duration) { - if (mAccumRoot && mNonAccumRoot) - mAccumRoot->setPosition(-mNonAccumRoot->getPosition()*mAccumulate); - return; + return osg::Vec3f(); } - const Ogre::SharedPtr &animsrc = state->second.mSource; - const std::vector >&ctrls = animsrc->mControllers[0]; - for(size_t i = 0;i < ctrls.size();i++) + void Animation::setObjectRoot(const std::string &model) { - NifOgre::NodeTargetValue *dstval; - dstval = static_cast*>(ctrls[i].getDestination().getPointer()); - if(dstval->getNode() == mNonAccumRoot) + if (mObjectRoot) { - mNonAccumCtrl = dstval; - break; + mObjectRoot->getParent(0)->removeChild(mObjectRoot); } - } - - 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); + mObjectRoot = mResourceSystem->getSceneManager()->createInstance(model, mInsert); } - 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) + osg::Group* Animation::getObjectRoot() { - const NifOgre::TextKeyMap &keys = (*iter)->mTextKeys; - - NifOgre::TextKeyMap::const_iterator found = findGroupStart(keys, groupname); - if(found != keys.end()) - return found->first; + return static_cast(mObjectRoot.get()); } - return -1.f; -} -float Animation::getTextKeyTime(const std::string &textKey) const -{ - for(AnimSourceList::const_iterator iter(mAnimSources.begin()); iter != mAnimSources.end(); ++iter) + osg::Group* Animation::getOrCreateObjectRoot() { - const NifOgre::TextKeyMap &keys = (*iter)->mTextKeys; + if (mObjectRoot) + return static_cast(mObjectRoot.get()); - for(NifOgre::TextKeyMap::const_iterator iterKey(keys.begin()); iterKey != keys.end(); ++iterKey) - { - if(iterKey->second.compare(0, textKey.size(), textKey) == 0) - return iterKey->first; - } + mObjectRoot = new osg::Group; + mInsert->addChild(mObjectRoot); + return static_cast(mObjectRoot.get()); } - 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()) + ObjectAnimation::ObjectAnimation(const MWWorld::Ptr &ptr, const std::string &model, Resource::ResourceSystem* resourceSystem) + : Animation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) { - 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) + if (!model.empty()) { - mStates.erase(stateiter++); - - resetActiveGroups(); + setObjectRoot(model); } 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; + // 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())); } - 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 dab8cfebb..cbded364a 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 clearAnimSources(); + //void addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScenePtr objlist, const ESM::Light *light); - // 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; - - /// 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); + //float getVelocity(const std::string &groupname) const; + + 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 3c6a507e7..6d37fa1e8 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" + +namespace +{ + + /// 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); + } -using namespace MWRender; + 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(); + } -int Objects::uniqueID = 0; + private: + std::vector > mToRemove; + }; + +} -void Objects::setRootNode(Ogre::SceneNode* root) + +namespace MWRender +{ + +Objects::Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr rootNode) + : mResourceSystem(resourceSystem) + , mRootNode(rootNode) { - mRootNode = root; +} + +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; - Ogre::SceneNode* insert = cellnode->createChildSceneNode(); - const float *f = ptr.getRefData().getPosition().pos; + osg::ref_ptr insert (new osg::PositionAttitudeTransform); + cellnode->addChild(insert); - insert->setPosition(f[0], f[1], f[2]); - insert->setScale(ptr.getCellRef().getScale(), ptr.getCellRef().getScale(), ptr.getCellRef().getScale()); + 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 - 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); + + osg::Vec3f lightOffset (0.f, 0.f, 0.f); + + osg::Group* attachTo = NULL; + if (visitor.mFoundNode) + { + attachTo = visitor.mFoundNode; + } + else + { + osg::ComputeBoundsVisitor computeBound; + osg::Group* objectRoot = anim->getOrCreateObjectRoot(); + objectRoot->accept(computeBound); - 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; + lightOffset = computeBound.getBoundingBox().center(); - if (mBounds.find(ptr.getCell()) == mBounds.end()) - mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL; - mBounds[ptr.getCell()].merge(bounds); + 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 b2f07ab0f..44334e444 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; - OEngine::Render::OgreRenderer &mRenderer; +class Objects{ + typedef std::map PtrAnimationMap; - 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(); + + /// @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); - ObjectAnimation* getAnimation(const MWWorld::Ptr &ptr); + 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 c64a265ac..4e5b33c64 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) -{ - 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")) - { - Settings::Manager::setString("shader mode", "General", openGL ? (glES ? "glsles" : "glsl") : "hlsl"); - } - - 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) - { - anim->rebuild(); - if(mCamera->getHandle() == ptr.getRefData().getHandle()) - { - attachCameraTo(ptr); - mCamera->setAnimation(anim); - } - } -} - -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()) - { - 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); - } - - // 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) - { - if (mRendering.getCamera()->getPolygonMode() == PM_SOLID) - { - mRendering.getCamera()->setPolygonMode(PM_WIREFRAME); - return true; - } - else - { - mRendering.getCamera()->setPolygonMode(PM_SOLID); - return false; - } - } - else //if (mode == MWBase::World::Render_BoundingBoxes) - { - bool show = !mRendering.getScene()->getShowBoundingBoxes(); - mRendering.getScene()->showBoundingBoxes(show); - return show; - } -#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) +namespace MWRender { - mFogColour = colour; - float max = Settings::Manager::getFloat("viewing distance", "Viewing distance"); - if (density == 0) - { - mFogStart = 0; - mFogEnd = std::numeric_limits::max(); - mRendering.getCamera()->setFarClipDistance (max); - } - else + RenderingManager::RenderingManager(osgViewer::Viewer &viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem) + : mViewer(viewer) + , mRootNode(rootNode) + , mResourceSystem(resourceSystem) { - 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); - } + osg::ref_ptr lightRoot = new SceneUtil::LightManager; + lightRoot->setStartLight(1); -} + mRootNode->addChild(lightRoot); -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)); - } -} + mObjects.reset(new Objects(mResourceSystem, lightRoot)); -void RenderingManager::setAmbientMode() -{ - setAmbientColour(mAmbientColor); -} + mViewer.setLightingMode(osgViewer::View::NO_LIGHT); -void RenderingManager::configureAmbient(MWWorld::CellStore &mCell) -{ - if (mCell.getCell()->mData.mFlags & ESM::Cell::Interior) - mAmbientColor.setAsABGR (mCell.getCell()->mAmbi.mAmbient); - setAmbientMode(); + 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); - // 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); - } -} + 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); -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; + // 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 ); } -} - -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) + MWRender::Objects& RenderingManager::getObjects() { - // 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()); + return *mObjects.get(); } -} -void RenderingManager::requestMap(MWWorld::CellStore* cell) -{ - if (cell->getCell()->isExterior()) + MWRender::Actors& RenderingManager::getActors() { - 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); + throw std::runtime_error("unimplemented"); } - 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++) + Resource::ResourceSystem* RenderingManager::getResourceSystem() { - 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 mResourceSystem; } - 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) + void RenderingManager::configureAmbient(const ESM::Cell *cell) { - 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; + osg::ref_ptr lightmodel = new osg::LightModel; + lightmodel->setAmbientIntensity(SceneUtil::colourFromRGB(cell->mAmbi.mAmbient)); + mRootNode->getOrCreateStateSet()->setAttributeAndModes(lightmodel, osg::StateAttribute::ON); - 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; - } + mSunLight->setDiffuse(SceneUtil::colourFromRGB(cell->mAmbi.mSunlight)); + mSunLight->setDirection(osg::Vec3f(1.f,-1.f,-1.f)); } - if (changeRes) + osg::Vec3f RenderingManager::getEyePos() { - 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); - } + osg::Vec3d eye; + //mViewer.getCamera()->getViewMatrixAsLookAt(eye, center, up); + eye = mViewer.getCameraManipulator()->getMatrix().getTrans(); + return eye; } - mWater->processChangedSettings(settings); - - if (rebuild) + void RenderingManager::removeCell(const MWWorld::CellStore *store) { - mObjects->rebuildStaticGeometry(); - if (mTerrain) - mTerrain->applyMaterials(Settings::Manager::getBool("enabled", "Shadows"), - Settings::Manager::getBool("split", "Shadows")); + mObjects->removeCell(store); } -} - -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 5bfd8ae77..f0c5040f2 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); - } - - void resetCamera(); - - bool vanityRotateCamera(const float *rot); - void setCameraDistance(float dist, bool adjust = false, bool override = true); - float getCameraDistance() const; - - void setupPlayer(const MWWorld::Ptr &ptr); - void renderPlayer(const MWWorld::Ptr &ptr); - - SkyManager* getSkyManager(); - - MWRender::Camera* getCamera() const; - - bool toggleRenderMode(int mode); - - void removeCell (MWWorld::CellStore *store); - - /// \todo this function should be removed later. Instead the rendering subsystems should track - /// when rebatching is needed and update automatically at the end of each frame. - void cellAdded (MWWorld::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; + public: + RenderingManager(osgViewer::Viewer& viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem); - MWRender::NpcAnimation *mPlayerAnimation; + MWRender::Objects& getObjects(); + MWRender::Actors& getActors(); - Ogre::ColourValue mAmbientColor; - Ogre::Light* mSun; + Resource::ResourceSystem* getResourceSystem(); - Ogre::SceneNode *mRootNode; + void configureAmbient(const ESM::Cell* cell); - Ogre::ColourValue mFogColour; - float mFogStart; - float mFogEnd; + void removeCell(const MWWorld::CellStore* store); - OEngine::Physic::PhysicEngine* mPhysicsEngine; + osg::Vec3f getEyePos(); - MWRender::Camera *mCamera; + private: + osgViewer::Viewer& mViewer; + osg::ref_ptr mRootNode; + Resource::ResourceSystem* mResourceSystem; - MWRender::LocalMap* mLocalMap; + osg::ref_ptr mSunLight; - bool mRenderWorld; -}; + std::auto_ptr mObjects; + }; } diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index f87983ce8..e71a4a34b 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 5115fa02d..cf6f7bf56 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 d4aadc6c7..371543f2e 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 a59efecfe..b8e4a06a8 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 14a315a81..7e83fda5e 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 e90b44f9c..2099b859f 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 6d7408607..1084ae03a 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 341a89a78..4e8f6a11b 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 8b2035fe9..994a0c9dd 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 07698aae5..f77bb4760 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 c49cf77b8..60315ba7d 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 ccb6603a6..fe5dc5082 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 de22e1b56..32c3861c0 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 111/450] 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 6d37fa1e8..764aa13c6 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 60315ba7d..5bccd53b3 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 fe5dc5082..1cd73589a 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 112/450] LightManager optimization --- components/sceneutil/lightmanager.cpp | 67 ++++++++++++++++++--------- 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 5bccd53b3..1aaf7ab40 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())); + const LightSourceTransform& l = mLights[lightList[i]]; + lights.push_back(l.mLightSource->getLight()); + } - clonedLight->setLightNum(i+mStartLight); + osg::ref_ptr attr = new LightStateAttribute(mStartLight, lights); - // don't use setAttributeAndModes, that does not support light indices! - stateset->setAttribute(clonedLight, osg::StateAttribute::ON); - stateset->setAssociatedModes(clonedLight, osg::StateAttribute::ON); + osg::ref_ptr stateset = new osg::StateSet; - //stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + // 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 113/450] 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 764aa13c6..25d57aba0 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()); + + objectRoot->addChild(trans); - attachTo = objectRoot; + 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 114/450] 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 0d0294fa7..59f9fa692 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 0185d3ecc..55607b5b7 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 2cdbbf363..3abf7c474 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 1b3dced80..266b97f87 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 151b58036..1be9dd374 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 5fc39f03e..84f61ddf8 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 250cb0d51..8089a7e6f 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 115/450] 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 | 787 +++++++------------- 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, 590 insertions(+), 742 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 e10688149..e7ed2d921 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 59f9fa692..59504048a 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 44334e444..07328b959 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 4e5b33c64..e9a5d302c 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 f0c5040f2..1db0467ef 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 d591cca2e..be702a221 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()) - { - Ogre::Pass *pass = passes.getNext(); - Ogre::ColourValue diffuse = pass->getDiffuse(); - diffuse.a = alpha; - pass->setDiffuse(diffuse); - } + osg::StateSet* stateset = node->getOrCreateStateSet(); + osg::ref_ptr cloned = static_cast(stateset->clone(osg::CopyOp::SHALLOW_COPY)); + node->setStateSet(cloned); + return cloned; } -} - -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::ref_ptr createAlphaTrackingUnlitMaterial() { - if (scene->mEntities[i] != scene->mSkelBase) - setAlpha(scene, scene->mEntities[i], alpha); + 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; } -} - -} - -BillboardObject::BillboardObject( const String& textureName, - const float initialSize, - const Vector3& position, - SceneNode* rootNode, - const std::string& material) -: mVisibility(1.0f) -{ - SceneManager* sceneMgr = rootNode->getCreator(); - Vector3 finalPosition = position.normalisedCopy() * 1000.f; + 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; + } - static unsigned int bodyCount=0; + osg::ref_ptr createTexturedQuad() + { + osg::ref_ptr geom = new osg::Geometry; - mMaterial = sh::Factory::getInstance().createMaterialInstance ("BillboardMaterial"+StringConverter::toString(bodyCount), material); - mMaterial->setProperty("texture", sh::makeProperty(new sh::StringValue(textureName))); + 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)); - 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); + geom->setVertexArray(verts); - 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())); + 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)); - sh::Factory::getInstance().getMaterialInstance ("BillboardMaterial"+StringConverter::toString(bodyCount))->setListener(this); + geom->setTexCoordArray(0, texcoords, osg::Array::BIND_PER_VERTEX); - bodyCount++; -} + geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4)); -void BillboardObject::requestedConfiguration (sh::MaterialInstance* m, const std::string& configuration) -{ -} + return geom; + } -void BillboardObject::createdConfiguration (sh::MaterialInstance* m, const std::string& configuration) -{ - setVisibility(mVisibility); - setColour(mColour); } -void BillboardObject::setVisible(const bool visible) +namespace MWRender { - mEntity->setVisible(visible); -} -void BillboardObject::setSize(const float size) +class AtmosphereUpdater : public SceneUtil::StateSetController { - mNode->setScale(450.f*size, 450.f*size, 450.f*size); -} +public: + void setEmissionColor(osg::Vec4f emissionColor) + { + mEmissionColor = emissionColor; + } -void BillboardObject::setVisibility(const float visibility) -{ - mVisibility = visibility; - Ogre::MaterialPtr m = static_cast(mMaterial->getMaterial ())->getOgreMaterial (); - for (int i=0; igetNumTechniques(); ++i) +protected: + virtual void setDefaults(osg::StateSet* stateset) { - Ogre::Technique* t = m->getTechnique(i); - if (t->getNumPasses ()) - t->getPass(0)->setDiffuse (0,0,0, visibility); + stateset->setAttribute(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); } -} -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); -} + 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); + } -Vector3 BillboardObject::getPosition() const -{ - return mNode->getPosition(); -} +private: + osg::Vec4f mEmissionColor; +}; -void BillboardObject::setVisibilityFlags(int flags) +/// Transform that removes the eyepoint of the modelview matrix, +/// i.e. its children are positioned relative to the camera. +class CameraRelativeTransform : public osg::Transform { - mEntity->setVisibilityFlags(flags); -} +public: + CameraRelativeTransform() + { + } -void BillboardObject::setColour(const ColourValue& pColour) -{ - mColour = pColour; - Ogre::MaterialPtr m = static_cast(mMaterial->getMaterial ())->getOgreMaterial (); - for (int i=0; igetNumTechniques(); ++i) + CameraRelativeTransform(const CameraRelativeTransform& copy, const osg::CopyOp& copyop) + : osg::Transform(copy, copyop) { - Ogre::Technique* t = m->getTechnique(i); - if (t->getNumPasses ()) - t->getPass(0)->setSelfIllumination (pColour); } -} -void BillboardObject::setRenderQueue(unsigned int id) -{ - mEntity->setRenderQueueGroup(id); -} + META_Node(MWRender, CameraRelativeTransform) -SceneNode* BillboardObject::getNode() -{ - return mNode; -} + virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const + { + if (_referenceFrame==RELATIVE_RF) + { + matrix.setTrans(osg::Vec3f(0.f,0.f,0.f)); + return false; + } + else // absolute + { + matrix.makeIdentity(); + return true; + } + } -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); + osg::BoundingSphere computeBound() const + { + return osg::BoundingSphere(osg::Vec3f(0,0,0), 0); + } +}; - mMaterial->setProperty("alphatexture", sh::makeProperty(new sh::StringValue(textureName + "_alpha"))); +class DisableCullingVisitor : public osg::NodeVisitor +{ +public: + DisableCullingVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + } - mPhase = Moon::Phase_Full; -} + void apply(osg::Geode &geode) + { + geode.setCullingActive(false); + } +}; -void Moon::setType(const Moon::Type& type) +class ModVertexAlphaVisitor : public osg::NodeVisitor { - mType = type; -} +public: + ModVertexAlphaVisitor(int meshType) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mMeshType(meshType) + { + } -void Moon::setPhase(const Moon::Phase& phase) -{ - // Colour texture - Ogre::String textureName = "textures\\tx_"; + void apply(osg::Geode &geode) + { + for (unsigned int i=0; iasGeometry(); + if (!geom) + continue; - 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"; + // 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) - textureName += ".dds"; + 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); + } - 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"); + geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX); + } } - mPhase = phase; -} - -unsigned int Moon::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: + int mMeshType; +}; -SkyManager::SkyManager(Ogre::SceneNode *root, Ogre::Camera *pCamera) - : mHour(0.0f) +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))); - - sh::Factory::getInstance().setTextureAlias ("cloud_texture_1", ""); - sh::Factory::getInstance().setTextureAlias ("cloud_texture_2", ""); - - // Create light used for thunderstorm - mLightning = mSceneMgr->createLight(); - mLightning->setType (Ogre::Light::LT_DIRECTIONAL); - mLightning->setDirection (Ogre::Vector3(0.3f, -0.7f, 0.3f)); - mLightning->setVisible (false); - mLightning->setDiffuseColour (ColourValue(3,3,3)); - - 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"); - else - objects = NifOgre::Loader::createObjects(mAtmosphereNight, "meshes\\sky_night_01.nif"); - - for(size_t i = 0, matidx = 0;i < objects->mEntities.size();i++) - { - Entity* night1_ent = objects->mEntities[i]; - night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); - night1_ent->setVisibilityFlags(RV_Sky); - night1_ent->setCastShadows(false); - night1_ent->getMesh()->_setBounds (aabInf); - - for (unsigned int j=0; jgetNumSubEntities(); ++j) - { - std::string matName = "openmw_stars_" + boost::lexical_cast(matidx++); - sh::MaterialInstance* m = sh::Factory::getInstance().createMaterialInstance(matName, "openmw_stars"); - - std::string textureName = sh::retrieveValue( - sh::Factory::getInstance().getMaterialInstance(night1_ent->getSubEntity(j)->getMaterialName())->getProperty("diffuseMap"), NULL).get(); + mAtmosphereDay = mSceneManager->createInstance("meshes/sky_atmosphere.nif", mRootNode); + ModVertexAlphaVisitor modAtmosphere(0); + mAtmosphereDay->accept(modAtmosphere); - m->setProperty("texture", sh::makeProperty(new sh::StringValue(textureName))); + // osg::Node* alphaBlendedRoot = - night1_ent->getSubEntity(j)->setMaterialName(matName); - } - } - mObjects.push_back(objects); - - // 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"); + mAtmosphereUpdater = new AtmosphereUpdater; + mAtmosphereDay->addUpdateCallback(mAtmosphereUpdater); - // 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); + if (mSceneManager->getVFS()->exists("meshes/sky_night_02.nif")) + mAtmosphereNight = mSceneManager->createInstance("meshes/sky_night_02.nif", mRootNode); + else + 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); + + 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); + + mSunTransform = trans; + + 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); + + mCloudNode->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + 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 6950dbab3..c8403af71 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 3a8154ca7..fd6022481 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 f69a5e57b..af47063ee 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 82814b623..fe4f62953 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 a2e668159..002f4355c 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 994a0c9dd..20298bd85 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 f77bb4760..9afda480b 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 abce7020c..6b1c01644 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 ead6a9669..393f322d7 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 4d6ad4855..6a52dfb21 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 000000000..301e709e4 --- /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 000000000..7c6c7e407 --- /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 116/450] 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 59ba9ad4f..344cb2323 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 1a90b8759..103a72046 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 a85847351..8dc286a92 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 301e709e4..079eaf6aa 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 7c6c7e407..e34332e5f 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 117/450] 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 cbded364a..754adec92 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 e9a5d302c..ba34cf303 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 be702a221..a4fd17172 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 6b1c01644..f61724eeb 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 344cb2323..ce004dc79 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 103a72046..3136b3118 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 8dc286a92..1d7eaba2c 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 000000000..565d48672 --- /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 000000000..de73c7e80 --- /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 079eaf6aa..8ed229aa6 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 e34332e5f..56f832a08 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 118/450] 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 1d7eaba2c..b61e3824b 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 119/450] 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 59504048a..f6f2ba9bb 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 a4fd17172..1ac7ca10b 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 c8403af71..ebf3ee87f 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 fe4f62953..90aedda1c 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 120/450] 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 e7ed2d921..91b1ab1c5 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 85d9546aa..4352520db 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 754adec92..34173c29c 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 a724644a7..fe16fa06e 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); -} - -void NpcAnimation::preRender(Ogre::Camera *camera) -{ - Animation::preRender(camera); - for (int i=0; irotateBillboardNodes(camera); - } + //mHeadAnimationTime->setEnabled(enable); } -void NpcAnimation::applyAlpha(float alpha, Ogre::Entity *ent, NifOgre::ObjectScenePtr scene) +void NpcAnimation::setWeaponGroup(const std::string &group) { - 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 90b1c269b..28ac6509b 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 25d57aba0..322d02e94 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 e1ccd9465..400962856 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 121/450] 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 1ac7ca10b..f843f9a43 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 b61e3824b..1f0c36839 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 47efe986c..e06155a61 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 122/450] 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 e06155a61..882bd66ec 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 123/450] 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 882bd66ec..f084704c3 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 124/450] 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 f6f2ba9bb..9a7f023e6 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 4352520db..3aeaa2ed1 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 34173c29c..1feab7bf3 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 fe16fa06e..e30c701fc 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 28ac6509b..2605d58e3 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 322d02e94..21d7c1ab5 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 215b1a67c..acde8f5d2 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 a91f3cab3..3bb454785 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 125/450] 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 | 30 ++-- components/sceneutil/controller.hpp | 21 ++- 17 files changed, 292 insertions(+), 59 deletions(-) create mode 100644 apps/openmw/mwrender/vismask.hpp diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 487a91890..6d0586775 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 91b1ab1c5..03a4181b5 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 3aeaa2ed1..2febf9c9a 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 1feab7bf3..ccc4bfa23 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 e30c701fc..c413d9334 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 2605d58e3..16bd45cc4 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 21d7c1ab5..4564e3a97 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 07328b959..f4d5675aa 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 ba34cf303..26b86d1b2 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 1db0467ef..b7aec3786 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 000000000..4a064b60f --- /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 1084ae03a..c9fd84ee3 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 20298bd85..c6a1b5477 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 ce004dc79..499a74d95 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 3136b3118..e480f4c13 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 565d48672..1f1b95ac8 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 de73c7e80..655e02164 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: - AssignControllerSourcesVisitor(); - AssignControllerSourcesVisitor(boost::shared_ptr toAssign); + 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); + /// 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 126/450] 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 2de3abc75..e3254d30a 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 127/450] 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 03a4181b5..32ed17c5b 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 9a7f023e6..fe6180299 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 7260fc6d1..9ccdf390e 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 6201c7af4..ccb553d99 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 c413d9334..eeb5298b8 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 4564e3a97..3d11662aa 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 128/450] 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 9ccdf390e..241ea56a3 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 eeb5298b8..719fb336b 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 f084704c3..26185eb3e 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 59c706f11..d26f95116 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 129/450] Port HeadAnimationTime --- apps/openmw/mwrender/npcanimation.cpp | 75 +++++++++++++++------------ apps/openmw/mwrender/npcanimation.hpp | 12 ++--- 2 files changed, 47 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 719fb336b..6a6b8a315 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) + + boost::shared_ptr src; + if (type == ESM::PRT_Head) { - if(ctrl->getSource().isNull()) - { - ctrl->setSource(mNullAnimationTimePtr); + src = mHeadAnimationTime; - if (type == ESM::PRT_Head) + 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 16bd45cc4..309bc5ef5 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 130/450] 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 2febf9c9a..e4c05bc1e 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 ccc4bfa23..797c215c5 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 6a6b8a315..56f12da13 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 3d11662aa..1d28291de 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 131/450] 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 | 113 +++++++++------------- apps/openmw/mwrender/effectmanager.hpp | 55 +++++++---- 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, 255 insertions(+), 166 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 32ed17c5b..09f2e08fa 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 9e6c6d9bf..0c1874ce6 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 c1b8177f7..a2451e1a1 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 506852a90..b5ac8f6c6 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 64456dd11..b80ac8cf9 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 daf4424c5..221c67267 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 e4c05bc1e..d54e87dc5 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 797c215c5..aef4d4b80 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 503a0223e..642909cda 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); + clear(); +} - NifOgre::ObjectScenePtr scene = NifOgre::Loader::createObjects(sceneNode, model); +void EffectManager::addEffect(const std::string &model, const std::string& textureOverride, const osg::Vec3f &worldPosition, float scale) +{ + osg::ref_ptr node = mResourceSystem->getSceneManager()->createInstance(model); - MWRender::Animation::setRenderProperties(scene, RV_Effects, - RQG_Main, RQG_Alpha, 0.f, false, NULL); + node->setNodeMask(Mask_Effect); - for(size_t i = 0;i < scene->mControllers.size();i++) - { - if(scene->mControllers[i].getSource().isNull()) - scene->mControllers[i].setSource(Ogre::SharedPtr (new EffectAnimationTime())); - } + Effect effect; + effect.mAnimTime.reset(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); - } - } - } - } - } + 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); - mEffects.push_back(std::make_pair(sceneNode, scene)); + mParentNode->addChild(trans); + + mEffects[trans] = effect; } -void EffectManager::update(float dt, Ogre::Camera* camera) +void EffectManager::update(float dt) { - for (std::vector >::iterator it = mEffects.begin(); it != mEffects.end(); ) + 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); - - objects->mControllers[i].update(); - } - objects->rotateBillboardNodes(camera); + it->second.mAnimTime->addTime(dt); - // 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 eb6863655..6d7aaaf4f 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 -namespace MWRender -{ +#include - class EffectAnimationTime : public Ogre::ControllerValue - { - private: - float mTime; - public: - EffectAnimationTime() : mTime(0) { } - void addTime(float time) { mTime += time; } +#include - virtual Ogre::Real getValue() const { return mTime; } - virtual void setValue(Ogre::Real value) {} - }; +namespace osg +{ + class Group; + class Vec3f; + class PositionAttitudeTransform; +} +namespace Resource +{ + class ResourceSystem; +} + +namespace MWRender +{ + 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 1d28291de..4b1fa6d5b 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 26b86d1b2..becd563b9 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 b7aec3786..61f611a8c 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 000000000..e1af1c339 --- /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 000000000..d078f0d98 --- /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 2099b859f..955913d9c 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 c6a1b5477..0628b42d7 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 9afda480b..5f79f52dc 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 d261d7247..8ce76a8ea 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 1f1b95ac8..79a75063a 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 655e02164..a4e209e8c 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 132/450] 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 08d540333..c5319d600 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 09f2e08fa..46eb79462 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 becd563b9..412d10ba2 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 f843f9a43..f4028caa7 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 468f8c82c..198a66c53 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 c2daf3579..8dedeaf64 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 2727ac6f0..073dc6be2 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 66c7c2ad5..e95a0ca7b 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 cdeb2d0e3..40925e014 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 133/450] 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 073dc6be2..261246f39 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 e95a0ca7b..6a054d99e 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 134/450] 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 c5319d600..e806b2578 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 46eb79462..c8854f84b 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 4ead16c5b..28771f14f 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 198a66c53..47889051a 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 a3c602197..1391a0012 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 299a57799..92a2f3424 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 135/450] 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 bf391d388..5c63094ce 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 36d90b03d..4bd7ce1f9 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 59a4a981b..3cfd91f1f 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 99db3c83a..416477cdd 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 136/450] 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 f61724eeb..b49beea0b 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 1f0c36839..f0bb538f2 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 000000000..8283caa23 --- /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 000000000..7c8ea83bc --- /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 000000000..26c6e80b3 --- /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 000000000..f006ca84b --- /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 137/450] 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 55607b5b7..6a586e81d 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 6a054d99e..72fc82f86 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 138/450] 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 f0bb538f2..eb78a0632 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; - 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 ); + 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 // 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 8283caa23..37fee1f51 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 139/450] 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 26c6e80b3..2e00eb76e 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 26185eb3e..b88bddc8d 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 - { - 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 + class CopyRigVisitor : 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 d26f95116..6bb8b2e35 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 140/450] 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 37fee1f51..0217a7ac0 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 2e00eb76e..b9d113d34 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 f006ca84b..5344f9f5d 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 141/450] 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 b49beea0b..75f6756f8 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 eb78a0632..301c487da 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 b88bddc8d..9f9d63619 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 0217a7ac0..00f80c829 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 7c8ea83bc..e99bc757e 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 b9d113d34..c1ab36136 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 5344f9f5d..c241844f1 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 142/450] 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 301c487da..b28412cb6 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 143/450] 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 e99bc757e..70f2c6e7d 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 c241844f1..acb9e6136 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 144/450] 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 3a06e4006..fc0631b84 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 1b4d02f26..63dc42ade 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 628541933..d0fc9bab0 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 b732c83af..45733f48f 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 b28412cb6..f7f6af0ae 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 00f80c829..4d4ea22d2 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 70f2c6e7d..c77ff7c72 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 145/450] 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 f124d7de7..eb7e63587 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 146/450] 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 412d10ba2..b7265533c 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 61f611a8c..d8744db4a 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 c9fd84ee3..aabe4d6d8 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 147/450] 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 fe6180299..68f4e8225 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 319e1d7ec..4ae610f51 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 297480d20..ddb9368c5 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 39be34cb0..e24331801 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 b8e4a06a8..ae6cce6c7 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 c1046aacb..bc61914bc 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 eaf92c673..f3622b2ee 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 bdeeeb8c4..000000000 --- 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 33a42f8cd..000000000 --- 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 148/450] 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 c8854f84b..84dcb60fa 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 878712ecc..000000000 --- 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 931c5bbd5..000000000 --- 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 02f3c804a..63039b612 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 b7265533c..dc5b584cc 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 d8744db4a..230885cd3 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 149/450] 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 9f9d63619..49e2acbd2 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 150/450] 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 d54e87dc5..8a0a85620 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 75f6756f8..aa801689a 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 000000000..d0056ecc6 --- /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 000000000..f6e2fa9fa --- /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 4d4ea22d2..ab9abcdda 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 acb9e6136..d710ac61b 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 f3622b2ee..0fb39b9d1 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 3367afdbb..000000000 --- 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 97fa938da..000000000 --- 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 61d09a0e6..000000000 --- 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 151/450] 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 56f12da13..740418a01 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 152/450] 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 68f4e8225..64457834c 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 a2451e1a1..d4a50ce81 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 b5ac8f6c6..b28fb0499 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 5c0a6ec5f..2e065c1c2 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 bc7c5528e..2620e5660 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 a0e5991b4..2e6383210 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 42491a5e8..a879bf21f 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 f74b06891..afbef5b67 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 a6cc9af8e..7068310a0 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 e570d1c33..84cf6f519 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 b6cb553e8..f6e8c453f 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 319d01495..ec4580568 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 b80ac8cf9..9f5d4fc85 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 0153be3dc..cf21f3806 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 bb02fb41d..2cb963e28 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 76c472001..f2f0c7cab 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 0b3390271..0e3220cf8 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 561011df3..eca24606e 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 b5058fb88..fa429bbee 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 3f72f1b66..9eab5bfef 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 5f4d986b4..ff3d2fceb 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 04225b43e..4d00d39c9 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 740418a01..702fd03ae 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 f4028caa7..0529b9a7b 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 84f61ddf8..a5e18dd49 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 e3254d30a..e0fd087fb 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 90aedda1c..b9d16993f 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 0628b42d7..a2d40930b 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 aa801689a..ece1148cb 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 f566a5499..c49bbeb01 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 3d50400df..df0fc687e 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 4e1da17e1..01fcdd763 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 d0056ecc6..484cea447 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 0fb39b9d1..07ac60bc6 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 153/450] Disable mygui plugin for now --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e806b2578..e8a2458b1 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 154/450] 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 c0a6dcc81..2ea736db7 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 155/450] 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 8a0a85620..75d409aec 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 aef4d4b80..ea47a5b79 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 702fd03ae..03af50c71 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 309bc5ef5..0c91dfe6e 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 f4d5675aa..2acf10d10 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 dc5b584cc..5199e6e12 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 aabe4d6d8..ef9e5792b 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 1c403a4fe..d1437ff2a 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 156/450] 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 f7f6af0ae..63a3ee887 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 d1437ff2a..678b8cc64 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 157/450] 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 499a74d95..27665b6c6 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 e480f4c13..d32c9f977 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 63a3ee887..3b3ae4b2c 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 678b8cc64..b6e9b1c8f 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 a4e209e8c..378837ad7 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 158/450] 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 378837ad7..6086663bd 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 6bb8b2e35..b9342b884 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 159/450] 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 814490404..000000000 --- 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 dc1ded5ff..000000000 --- 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 7b054082b..000000000 --- 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 e69de29bb..000000000 diff --git a/components/misc/tests/slice_test.cpp b/components/misc/tests/slice_test.cpp deleted file mode 100644 index 0d9d7b4ab..000000000 --- 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 24ab8a298..000000000 --- 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 2d07708ad..000000000 --- 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 160/450] 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 75d409aec..d291e0fd0 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 ea47a5b79..a04544ac8 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; + + typedef std::map > ControllerMap; - /* - struct AnimSource : public Ogre::AnimationAlloc { - //NifOgre::TextKeyMap mTextKeys; - std::vector > mControllers[sNumGroups]; + 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 241ea56a3..721215749 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 03af50c71..ab32864bd 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 4b1fa6d5b..e278662aa 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 3b3ae4b2c..38ead0925 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 b6e9b1c8f..f2f3c2534 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 79a75063a..6beb1bc80 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 6086663bd..84fe6e896 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 161/450] 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 d291e0fd0..f490baefe 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 a04544ac8..083213c85 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 e278662aa..4b1fa6d5b 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 162/450] 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 f490baefe..27e54b228 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 083213c85..d5b2de81b 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 721215749..d2abf1413 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 ab32864bd..80dbf3c7f 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 163/450] 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 4b1fa6d5b..be21b2bec 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 5199e6e12..be23ebc2f 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 230885cd3..c47317608 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 ef9e5792b..4f689ee59 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 4e8f6a11b..0ae1ff4da 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 a2d40930b..07c3b1b16 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 164/450] 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 d4a50ce81..a85c648f4 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 e11529b2e..5585835fd 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 b28fb0499..8be551dd2 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 27beeb626..b74546395 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 6fa9ba9b6..79444e110 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 782aa7815..3f65af05c 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 ae6cce6c7..623a79576 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 4f689ee59..191a8ffef 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 0ae1ff4da..ea1a56d63 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 07c3b1b16..4b1946d1c 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 165/450] 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 84dcb60fa..3349a1afe 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 64457834c..7698c3146 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 de09082d8..8c73920bd 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 6ad4da3bf..0a8667d80 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 000000000..5ba54b009 --- /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 000000000..eaf60f8b9 --- /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 000000000..01d6ca567 --- /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 000000000..4c3e70143 --- /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 000000000..53a194c73 --- /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 000000000..64a5fe07b --- /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 4ae610f51..63d74b355 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 ddb9368c5..a98fbf7b8 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 be23ebc2f..32afc73c2 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 349647892..000000000 --- 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 28eb6419b..000000000 --- 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 166/450] 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 7698c3146..7dac03c34 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 8c73920bd..be405c600 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 53a194c73..55e78cb0c 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 63d74b355..86d065e39 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 a98fbf7b8..54b69be40 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 167/450] 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 3349a1afe..acca23f8e 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 c6df24154..bab022d94 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 ffde59aee..c989e3f45 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 27e54b228..4a1ec3f2f 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 d5b2de81b..9aa15520f 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 168/450] 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 be405c600..f3b3a8fbf 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 ece1148cb..cc913912f 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 ae5aca5ac..6fbef31ca 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 342251dbc..000000000 --- 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 173b91865..000000000 --- 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 d32c9f977..4ebd4f41d 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 f2f3c2534..bf1dbe6b5 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 169/450] 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 4a1ec3f2f..c5479e3f7 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 170/450] 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 7dac03c34..582172bff 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 f3b3a8fbf..b47a7bb76 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 070136dfd..792a2674e 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 3161bb413..675bd160a 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 bab022d94..bb59d46c0 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 c989e3f45..98a420ba6 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 0e3220cf8..7e6e29670 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 30cc207f7..d08334ae8 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 be21b2bec..f77865634 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 32afc73c2..d68620f8a 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 c47317608..005100701 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 623a79576..a1b37a275 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 191a8ffef..e61e5d84e 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 ea1a56d63..26590c796 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 4b1946d1c..77028aaff 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 171/450] 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 fdd51ef44..d5960779c 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 0c1874ce6..00d4d8536 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 55e78cb0c..c066ba308 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 86d065e39..ce1314c6f 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 54b69be40..738690bbc 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 77028aaff..2c92ad93b 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 5f79f52dc..e9655b12e 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 172/450] 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 ab9abcdda..9205ef379 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 c77ff7c72..f8458cdfa 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 173/450] 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 0529b9a7b..97055ecae 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 2c92ad93b..4e737fc07 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 174/450] 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 38ead0925..936f266dd 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 9205ef379..19e5b0ae6 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 f8458cdfa..e82f6254a 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 175/450] 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 4c3e70143..a2256e970 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 c066ba308..06e404d88 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 64a5fe07b..513edb5b7 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 176/450] 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 e8a2458b1..d2a245366 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 acca23f8e..a36dd4e2a 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 b5c4e8ade..b52d94f98 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 177/450] 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 bb59d46c0..3333511d3 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 98a420ba6..adcfb57a4 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 da74b2a33..987a0d29a 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 c5479e3f7..245095492 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 9aa15520f..c85f87403 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 19e5b0ae6..7f30aff74 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 e82f6254a..ea4245aa8 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 c1ab36136..f105977ba 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 d710ac61b..1987fd4e8 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 178/450] 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 7f30aff74..df5f65029 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 179/450] 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 a41c6b74b..52f9c9e54 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 180/450] 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 7e83fda5e..82bb06b8d 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 181/450] 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 582172bff..e2e09bdec 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 06e404d88..f218d9ff0 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 d68620f8a..8689935d0 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 97055ecae..4fd5b7e63 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 4a064b60f..48845c78c 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 182/450] 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 a36dd4e2a..680ea9c86 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 f218d9ff0..e5160bb5b 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 000000000..d61e396f1 --- /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 000000000..5ae34a3d6 --- /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 183/450] 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 680ea9c86..f352547e0 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 e2e09bdec..488c94501 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 ce1314c6f..cac4939ed 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 738690bbc..894c81ec9 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 a5e18dd49..775e3da19 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 26590c796..f7ef9b276 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 e9655b12e..447bb1300 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 cc913912f..563a77268 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 5ba54b009..69bc3878d 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 eaf60f8b9..5002f0fb7 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 a2256e970..5079b23b0 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 e5160bb5b..3ebbd957a 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 513edb5b7..05d0f9a5a 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 d61e396f1..7de7ebfb0 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 5ae34a3d6..de385e94d 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 bed6a2794..10150c6b1 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 72c8a733c..6ee2ef3f2 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 184/450] 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 cac4939ed..ce9735f9d 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 894c81ec9..16dab08a9 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 1b61aea90..e579de18f 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 a41506dbb..b92815f13 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 185/450] 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 563a77268..ac7eef16a 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 da36b90a2..b36e0d852 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 000000000..3da4d3c52 --- /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 5079b23b0..c0c9e0ce4 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 07ac60bc6..fa3df0820 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 47978ba44..000000000 --- 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 186/450] 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 f352547e0..f049f0387 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 d5960779c..743577812 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 263c08774..e717e094e 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 cd94387f9..6bdb1a9f4 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 b0515ccbb..0e7cf3faa 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 0a8667d80..d563eacc8 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 cd2050d0f..9089ed1d5 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 48a92c844..59d1a0b06 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 71b4a560f..0ddd313df 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 bf74c8bf0..195b6c384 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 ce9735f9d..cf7475d5c 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 16dab08a9..ec99364c7 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 fa3df0820..b135d0fc6 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 187/450] 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 488c94501..0abb43cfd 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 28771f14f..13fabfeed 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()); + + mPlayer->playVideo(mVFS->get(video)); + + osg::ref_ptr texture = mPlayer->getVideoTexture(); + if (!texture) + return; + + mTexture.reset(new osgMyGUI::OSGTexture(texture)); - //setImageTexture(mPlayer->getTextureName()); + 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 75aa6e98a..6b265628e 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 cf7475d5c..7ce8d6200 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 ec99364c7..3a6f3b024 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 8dedeaf64..1336e45a3 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 188/450] 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 7e6e29670..077f67b5e 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 245095492..1f749ab4e 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 f77865634..a06b751cc 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 8689935d0..d07c98ed7 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 005100701..71c70b990 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 4e737fc07..8cb9f4d50 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 189/450] 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 743577812..59407fbeb 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 475428f33..dd20999e0 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 d96255c85..461d8e32e 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 2323d39e7..9c8fa48a1 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 1da2ab879..645a72277 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 3fddbc84b..0c462c67d 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 80806941c..e0a1493c2 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 8770bab38..c26316626 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 8b63ab541..f91c17370 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 888955391..996cc528d 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 7ce8d6200..096838f81 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 3a6f3b024..765a18156 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 1763f7777..fa50cce22 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 190/450] 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 da3451d93..e69de29bb 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 3eaa73b1c..000000000 --- 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 54108dbba..000000000 --- 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 5902d2fdc..000000000 --- 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 5fffb5658..000000000 --- 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 e6cde4bda..000000000 --- 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 151b94180..000000000 --- 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 659481a96..000000000 --- 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 78cba3f89..000000000 --- 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 4d12eba90..000000000 --- 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 980cd4caf..000000000 --- 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 7d3085b0f..000000000 --- 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 5c74b1139..000000000 --- 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 028c15ce8..000000000 --- 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 b953a9131..000000000 --- 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 77a2c0c34..000000000 --- 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 4620588c3..000000000 --- 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 71fd82da4..000000000 --- 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 58045f6d7..000000000 --- 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 2cb92f884..000000000 --- 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 095a31259..000000000 --- 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 c90826282..000000000 --- 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 5c5c8e088..000000000 --- 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 8f7911553..000000000 --- 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 5f4990ed1..000000000 --- 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 eba3a3ea7..000000000 --- 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 c2e8ddeb0..000000000 --- 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 830be862a..000000000 --- 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 0f8803450..000000000 --- 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 72e49d1a7..000000000 --- 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 1b9e92a43..000000000 --- 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 f20fce506..000000000 --- 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 a72f2358f..000000000 --- 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 2f38f6546..000000000 --- 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 cf03be39e..000000000 --- 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 eff245b5e..000000000 --- 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 5e070a45a..000000000 --- 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 191/450] 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 a1b37a275..14cab6c82 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 bc61914bc..23bf47543 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 8cb9f4d50..416ef7416 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 ac7eef16a..9ec648381 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 cdc06f985..1d07bea26 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 0d81d84b6..81e854a94 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 92d56b42c..26b6caa0e 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 907ff8bfe..472efac6d 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 d5103d32b..0125fd01e 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 7784e8941..71f84cca7 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 192/450] 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 cdb51348c..cb3a3e7cb 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 213b6bccb..fb96c39d7 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 9ec648381..1f9bd337b 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 e8ca2e8bd..000000000 --- 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 d1743950f..000000000 --- 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 069b25e7b..000000000 --- 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 6fcf61376..000000000 --- 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 32c3861c0..f1af8b654 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 193/450] 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 14cab6c82..271b23d09 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 0125fd01e..b1bd978c6 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 71f84cca7..e92e9c3c1 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 194/450] 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 0abb43cfd..0dc19144c 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 59407fbeb..d1f1ad3a3 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 00d4d8536..1f27756d1 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 9c8fa48a1..5f5f2eca3 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 e717e094e..9eed9811a 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 d895a28ea..23cf2c62e 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 096838f81..e4e0c3167 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 765a18156..7fccff2d8 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 416ef7416..842a24ded 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 447bb1300..9598d4357 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 0cbe0dd97..dd114097e 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 f1af8b654..862f9495a 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 195/450] 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 e579de18f..080c64c4c 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 d0d32a40e..b86b70cde 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 196/450] 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 e4e0c3167..3755de07e 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 7fccff2d8..325881889 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 3ebbd957a..87464f22d 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 197/450] 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 d563eacc8..48f9ee42c 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 9089ed1d5..d01f67fbd 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 3755de07e..9d9ba329b 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 198/450] 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 0dc19144c..15fee0cb1 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 b86b70cde..939f81d9b 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 f4ade515d..d44d47d24 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 199/450] 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 | 249 +++++++++------------ 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, 199 insertions(+), 273 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 f049f0387..ed5530126 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 1f27756d1..4ccbfc784 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 f48de6624..0f4d42775 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 d2abf1413..25d9e9e47 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 79eeff2d0..97ead9d7d 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() -{ - if (mGridMatsCreated) return; - - 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); - } - - 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() +osg::ref_ptr Debugging::createPathgridLines(const ESM::Pathgrid *pathgrid) { - if (mGridMatsCreated) - { - MaterialManager::getSingleton().remove(PATHGRID_POINT_MATERIAL); - MaterialManager::getSingleton().remove(PATHGRID_LINE_MATERIAL); - mGridMatsCreated = false; - } -} + osg::ref_ptr geom = new osg::Geometry; -ManualObject *Debugging::createPathgridLines(const ESM::Pathgrid *pathgrid) -{ - ManualObject *result = mSceneMgr->createManualObject(); + osg::ref_ptr vertices = new osg::Vec3Array; - 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); + + geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, vertices->size())); - return result; + 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); - - 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 - - result->index(startIndex + 0); - result->index(startIndex + 1); - result->index(startIndex + 2); - result->index(startIndex + 5); - result->index(startIndex + 3); - result->index(startIndex + 4); + float pointMeshBase = static_cast(POINT_MESH_BASE); + + 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 + + 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 e24331801..4ec5bc41d 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; - - void enableCellPathgrid(MWWorld::CellStore *store); - void disableCellPathgrid(MWWorld::CellStore *store); - - // utility - void destroyCellPathgridNode(Ogre::SceneNode *node); - void destroyAttachedObjects(Ogre::SceneNode *node); + osg::ref_ptr mInteriorPathgridNode; - // 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 80dbf3c7f..d6aa05fcb 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 a06b751cc..6f4f4ef79 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 cfd84cb32..000000000 --- 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 d07c98ed7..5cb779545 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 71c70b990..334025096 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 000000000..a74d9bd52 --- /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 4fd5b7e63..48de57239 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 48845c78c..872695556 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 29f586a65..ce74c0c9f 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 e61e5d84e..637fde18c 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 842a24ded..fda9d53af 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 9598d4357..464f2d605 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 200/450] 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 ed5530126..81cecc2c8 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 000000000..9e683232b --- /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 000000000..288091e7c --- /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 97ead9d7d..9cbf94d46 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 271b23d09..422268397 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 23bf47543..1fc0e0e76 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 637fde18c..1ccbc6b55 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 fda9d53af..04fd82e80 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 b1bd978c6..35c767ca9 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 e92e9c3c1..6322105e8 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 201/450] 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 422268397..6a08e8e1f 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 f8c1fe41d..000000000 --- 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 7e497b535..000000000 --- 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 2e42fe1f9..000000000 --- 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 35c767ca9..11b6b1834 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 202/450] 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 7e88f2d97..01bd590a7 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); - - MWBase::Environment::get().getInputManager()->update(0, true, true); + int oldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask(); + int oldCullMask = mViewer->getCamera()->getCullMask(); + mViewer->getUpdateVisitor()->setTraversalMask(MWRender::Mask_GUI); + mViewer->getCamera()->setCullMask(MWRender::Mask_GUI); - // 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(); + //MWBase::Environment::get().getInputManager()->update(0, true, true); - 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 0d3ffbbec..46bbb00cc 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 9d9ba329b..575d7045a 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 203/450] 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 01bd590a7..3b13ed5a9 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 46bbb00cc..4c9d45f66 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 204/450] 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 939f81d9b..ee75296a7 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 205/450] 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 81cecc2c8..4a93daec7 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 15fee0cb1..5be9317eb 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 3b13ed5a9..a7791d838 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 575d7045a..ebca96b19 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 88d891a02..442a5e8b2 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 558801023..26a1fcb21 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 1ef68f619..000000000 --- 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 a234defe7..000000000 --- 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 fab65b152..a8c04aa4b 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 206/450] 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 d2a245366..d1008d313 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 e69de29bb..00cae86d2 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 13d1a9e1a..602397743 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 207/450] 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 ebca96b19..c32f2bfe8 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 208/450] 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 5be9317eb..d7ad97e6e 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 a7791d838..45bd5bf9d 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 4c9d45f66..7c49df027 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 6f4f4ef79..69311c111 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 2acf10d10..fd6ceab54 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 5cb779545..4f13df8e7 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 209/450] 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 83fcb3e37..56076dbe0 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 48f9ee42c..ef86666f4 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 c32f2bfe8..abc19b3f9 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 080c64c4c..7635c43da 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 210/450] 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 87464f22d..e63756ecd 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 211/450] 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 c3932d388..cbce86650 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 212/450] 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 d1008d313..92023da2c 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 0de79f8f6..76b6e46bd 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 8347af6ee..d7aafcf30 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 4a93daec7..d680f49d6 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 ac51eace8..d91d32a28 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 23cf2c62e..c23e2bb94 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 1b970b8de..7cebb10d1 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 2efd5841e..cc9c3d1dc 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 862f9495a..7f2185b62 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 213/450] 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 d680f49d6..e1de2a556 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 9cbf94d46..5e559eeed 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 4ec5bc41d..39a6d71ed 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 4f13df8e7..4d06d901a 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 334025096..0dc0fe571 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 464f2d605..cb58f0496 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 214/450] 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 e63756ecd..e1ebf781c 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 05d0f9a5a..342050d90 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 215/450] 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 4d06d901a..853ba3834 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 e1ebf781c..d1bf73904 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 342050d90..afb07eaa6 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 216/450] 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 d1bf73904..e9a6f8c4e 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 217/450] 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 7fefb92a2..d95180145 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 1d07bea26..0ddb6291c 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); - - 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()); +osg::Matrixf getWorldTransform(const Nif::Node *node) +{ + if(node->parent != NULL) + return node->trafo.toMatrix() * getWorldTransform(node->parent); + return node->trafo.toMatrix(); +} - 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 3ffb6ac8f..733e9264b 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 936f266dd..adf7e94b4 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 218/450] 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 d91d32a28..368af216f 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 b47a7bb76..e94b5e3ff 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 69311c111..17fbbe549 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 fd6ceab54..e920869b9 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 853ba3834..c9bf22009 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 219/450] 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 13fabfeed..2c9b1c97e 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 1336e45a3..9bd4a2df3 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 261246f39..b886257e7 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 72fc82f86..4dd618858 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 40925e014..4a4f2fc6b 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 220/450] 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 6421df824..40180d700 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 de385e94d..109858bc8 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 221/450] 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 40180d700..9c7a9de20 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 222/450] 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 45bd5bf9d..d56c77bdd 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 223/450] 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 368af216f..59c3667a4 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 224/450] 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 4dd618858..dea08de92 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 225/450] 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 acde8f5d2..bd6824079 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 3bb454785..7c00a11ee 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 393f322d7..8a0d526fa 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 6a52dfb21..9f3c5387e 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 ee75296a7..b9b9fad5f 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 d44d47d24..851a55166 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 226/450] 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 d56c77bdd..cdb2d6bdf 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 7c49df027..a1e6e4d21 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 227/450] 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 e9a6f8c4e..442b6be78 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 228/450] 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 442b6be78..3a36a3b10 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 229/450] 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 6a08e8e1f..a43ca9178 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 3a36a3b10..3caa61548 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 0ddb6291c..b80bbb83f 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 733e9264b..b3e30cbd9 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 26b6caa0e..d164b9b23 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 472efac6d..a856e8153 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 889986339..391d266df 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 6322105e8..691ccbfd6 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 230/450] 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 92023da2c..2fa9cb821 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 59c3667a4..4c6d1585b 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 a43ca9178..7c1a44e48 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) + void PhysicsSystem::addActor (const Ptr& ptr, const std::string& mesh) { - 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 1fc0e0e76..018ea0a28 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 04fd82e80..7047978ff 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 1f9bd337b..931d84e26 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 3da4d3c52..70dfc4ecf 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 b3e30cbd9..2a2e914e3 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 23a5e931b..000000000 --- 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 52c12a84a..000000000 --- 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 621fe8d60..000000000 --- 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 d164b9b23..000000000 --- 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 a856e8153..000000000 --- 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 391d266df..000000000 --- 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 691ccbfd6..000000000 --- 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 c0f653dae..000000000 --- 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 f499f4a27..000000000 --- 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 231/450] 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 2fa9cb821..fae7ff683 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 2ea736db7..7f305052b 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 8a7576f92..8ed63f35d 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 69d4498bb..aeda3191d 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 c0fbb1a1b..000000000 --- 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 232/450] 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 d7aafcf30..5a74fa48f 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 d18a199ff..9f411ffc6 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 e1de2a556..bcfc24053 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 2621f5e52..4cf33ceb8 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 e79318a55..646bb79bb 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 2abd071bd..55209764a 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 2ab0a47e3..94e998e48 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 686f5af61..ec3658b3d 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 21d711a0d..ec3290878 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 a9c96e7c7..e71dd6769 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 05ff88bb2..8dcae731a 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 b387a3e9f..39025227c 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 570054348..adb349158 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 ac23744e8..862ae6c5d 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 52873374e..3268d45d1 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 a85c648f4..7d4fcf5d6 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 5585835fd..7a50968bf 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 f46ede730..36f7b021c 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 c5f258d3e..9cfb46509 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 de43e818e..9b35b8530 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 a4681f462..69dd70743 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 2cf31d996..7ea5ae1be 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 8658375b7..6161f1899 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 478c50301..e1e774755 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 293a40be1..3f2c004f8 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 f5daafeec..df28daee9 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 23160d41c..66699f9df 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 8be551dd2..6f969146b 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 b74546395..e0ebbec2b 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 ee299ab4f..98bb703cb 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 32e390115..091d29195 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 da22e9be6..fb96bff5a 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 bb90ac153..e39e43c27 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 c02146f12..9ddc36ff9 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 2589a4af3..295b9d4f1 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 834ce129e..6438046de 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 a94dff394..3d78f949b 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 a484ad668..bbe81f370 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 47f1c5251..47c1157a0 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 26a1fcb21..cd80ed460 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 7c1a44e48..f57a8fbff 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 018ea0a28..e04ac1b51 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 79444e110..0ab18699d 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 3f65af05c..15058294f 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 1ccbc6b55..0e17dad74 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 f7ef9b276..24ffdf07b 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 7047978ff..72423f476 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 cb58f0496..efb9b88c6 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 931d84e26..417164f2d 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 233/450] 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 f57a8fbff..8ae4fc853 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 e04ac1b51..4dbecdb7c 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 0e17dad74..6a994f0cd 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 234/450] 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 | 294 ++++++++------ components/nifbullet/bulletnifloader.hpp | 113 +++--- components/nifbullet/bulletshapemanager.cpp | 47 +++ components/nifbullet/bulletshapemanager.hpp | 37 ++ 38 files changed, 1232 insertions(+), 467 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 5a74fa48f..1b71cf0ed 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 bcfc24053..95875de10 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 4ccbfc784..7cc0a6e5e 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 55209764a..6f11a36c7 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 ec3658b3d..04c98e437 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 e71dd6769..2c20435b2 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 39025227c..8964b65e0 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 9b35b8530..fb409cb55 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 7ea5ae1be..4d0c0cba9 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 e1e774755..8f22c3fa1 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 df28daee9..b7c39b50a 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 98bb703cb..647f83f67 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 fb96bff5a..cb43ccce6 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 9ddc36ff9..0bc64a99e 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 bbe81f370..8c3d7fb10 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 adcfb57a4..5769138fa 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 6c9a4b758..c12b61538 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 000000000..edad7e196 --- /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 000000000..ec1d81fd9 --- /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 000000000..0f083ab35 --- /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 000000000..c5075a2c3 --- /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 8ae4fc853..6d429f3e5 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); - - return position; -#if 0 - OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); - if (!physicActor) - return position; + osg::Vec3f position(ptr.getRefData().getPosition().asVec3()); - 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; + } - PhysicsSystem::PhysicsSystem(osg::ref_ptr parentNode) - : mTimeAccum(0.0f) + 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(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 4dbecdb7c..e6bfd7cd2 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 000000000..ddb984821 --- /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 000000000..02f9ebdd1 --- /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 f0cb8a967..4a7952c44 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 ce74c0c9f..9fe23ff14 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 cf6f7bf56..c7fdc793c 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 6a994f0cd..81e240698 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 b9d16993f..b37a38353 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 002f4355c..77d961057 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 72423f476..add8d0373 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 efb9b88c6..a7830da3a 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 417164f2d..ef32e10dc 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 b80bbb83f..62f2d94d8 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; - } - - // 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); + return mShape; } - 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); + if (findBoundingBox(node)) + { + std::auto_ptr compound (new btCompoundShape); - //do a first pass - handleNode(node,0,false,false); + btBoxShape* boxShape = new btBoxShape(getbtVector(mShape->mCollisionBoxHalfExtents)); + btTransform transform = btTransform::getIdentity(); + transform.setOrigin(getbtVector(mShape->mCollisionBoxTranslate)); + compound->addChildShape(transform, boxShape); - if(mBoundingBox != NULL) - { - mShape->mCollisionShape = mBoundingBox; - delete mStaticMesh; - if (mCompoundShape) - { - int n = mCompoundShape->getNumChildShapes(); - for(int i=0; i getChildShape(i)); - delete mCompoundShape; - mShape->mAnimatedShapes.clear(); - } + 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) + +} + +BulletShape::~BulletShape() +{ + deleteShape(mCollisionShape); +} + +void BulletShape::deleteShape(btCollisionShape* shape) +{ + if(shape!=NULL) { - if (!(node->flags & Nif::NiNode::Flag_Hidden)) + if(shape->isCompound()) { - //translation = node->boundPos; - //orientation = node->boundRot; - //halfExtents = node->boundXYZ; - return true; + btCompoundShape* ms = static_cast(shape); + int a = ms->getNumChildShapes(); + for(int i=0; i getChildShape(i)); } + delete shape; } +} - const Nif::NiNode *ninode = dynamic_cast(node); - if(ninode) +btCollisionShape* BulletShape::duplicateCollisionShape(btCollisionShape *shape) const +{ + if(shape->isCompound()) { - const Nif::NodeList &list = ninode->children; - for(size_t i = 0;i < list.length();i++) + btCompoundShape *comp = static_cast(shape); + btCompoundShape *newShape = new btCompoundShape; + + int numShapes = comp->getNumChildShapes(); + for(int i = 0;i < numShapes;++i) { - if(!list[i].empty()) - if (findBoundingBox(list[i].getPtr(), halfExtents, translation, orientation)) - return true; + btCollisionShape *child = duplicateCollisionShape(comp->getChildShape(i)); + btTransform trans = comp->getChildTransform(i); + newShape->addChildShape(trans, child); } - } - return false; -} -bool getBoundingBox(const std::string& nifFile, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation) -{ - Nif::NIFFilePtr pnif;// (Nif::Cache::getInstance().load(nifFile)); - Nif::NIFFile & nif = *pnif.get (); + return newShape; + } - if (nif.numRoots() < 1) + 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; } - Nif::Record *r = nif.getRoot(0); - assert(r != NULL); - - Nif::Node *node = dynamic_cast(r); - if (node == NULL) + if (btBoxShape* boxshape = dynamic_cast(shape)) { - return false; + return new btBoxShape(*boxshape); } - return findBoundingBox(node, halfExtents, translation, orientation); + 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 2a2e914e3..d80ab77bd 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 000000000..6acfdd408 --- /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 000000000..d9ba3ffbb --- /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 235/450] 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 7cc0a6e5e..008d64aaf 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 6d429f3e5..9b56a46b8 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 2c5e01aaa..49197d167 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 7da7c187d..4e6c6f116 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 d7036d6b1..d3c6d0735 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 82bb06b8d..a95a66f7e 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 955913d9c..5951cb101 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 81e240698..20f1f7ebc 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 24ffdf07b..af0b82fc3 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 add8d0373..094098a91 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 a7830da3a..97515b7d0 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 236/450] 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 ec1d81fd9..1f5838543 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 9b56a46b8..81fc1e225 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 e6bfd7cd2..54cf48ad1 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 094098a91..c1e31453f 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 62f2d94d8..89daf898a 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 d80ab77bd..ae4279f40 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 6acfdd408..34c64570e 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 d9ba3ffbb..9db674d6d 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 eb7e63587..862a070d8 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 237/450] 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 edad7e196..1a712461e 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 1f5838543..513985c94 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 238/450] 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 34c64570e..e53a351cf 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 239/450] 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 7d4fcf5d6..89302dcc0 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 240/450] 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 4d0c0cba9..1e882b568 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 241/450] 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 20f1f7ebc..d087a40d8 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 242/450] 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 76b6e46bd..bc1975ac9 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 00e6a9aa2..edbe48077 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 84cf6f519..ac5d1691c 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 1f749ab4e..888846789 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 c85f87403..81f044707 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 c1e31453f..6ea38a8fb 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 97515b7d0..279d35329 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 243/450] 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 | 74 +++++++++---------- 14 files changed, 109 insertions(+), 107 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index e71558de0..4fccec40b 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 81fc1e225..04b53a8e3 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 54cf48ad1..91e166bef 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 e71a4a34b..d43eae021 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 007791984..9446a1dae 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 266b97f87..6862bb889 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 1a95d6150..755a0e5b6 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 1b5c00196..bdc8cf459 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 4f5c210bb..a0c6fb17b 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 775e3da19..a5ae9f0e2 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 8089a7e6f..27af1e65b 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 371543f2e..d4aadc6c7 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 93f54c008..f46f544d2 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 6ea38a8fb..6c7fd6ff3 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 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 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(); + + 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 244/450] 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 4c6d1585b..a77b3e293 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::prepareEngine (Settings::Manager & settings) +void OMW::Engine::createWindow(Settings::Manager& settings) { - mEnvironment.setStateManager ( - new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0))); + 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); + } - //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"; + 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"); - // 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")); + 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))); + + createWindow(settings); + osg::ref_ptr rootNode (new osg::Group); mViewer->setSceneData(rootNode); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index e94b5e3ff..420121a8e 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 89302dcc0..1e41aea24 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 7a50968bf..f5a2402f3 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 6f969146b..463209df8 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 e0ebbec2b..f72a9bb2c 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 0ab18699d..5999979de 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 15058294f..02afd8960 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 ef32e10dc..d62ff3f00 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 000000000..5a9db5923 --- /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 000000000..27b9e8e28 --- /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 245/450] 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 a77b3e293..9270b07e8 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 246/450] 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 9270b07e8..7f98f6ad7 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 420121a8e..bb70c288d 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 d62ff3f00..e18871a64 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 000000000..36e503c74 --- /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 000000000..2c5df5cbd --- /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 5a9db5923..1424337ab 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 27b9e8e28..cfe40d98e 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 247/450] 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 7f98f6ad7..98e1c5a28 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 1424337ab..6c7bac12e 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 cfe40d98e..45cf47002 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 248/450] 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 | 42 +++--- 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, 150 insertions(+), 456 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 98e1c5a28..08d77e7af 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 62d3bdd03..0fc25db4c 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); + + mMouseX = w / 2.f; + mMouseY = h / 2.f; - /* - Ogre::RenderWindow* window = ogre.getWindow (); - mInputManager = new SFO::InputWrapper(mOgre.getSDLWindow(), mOgre.getWindow(), grab); + 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 cd80ed460..27c08ed32 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 e18871a64..6590c7e99 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 986dd7d8b..7c79470ff 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 6c7bac12e..c69fcca64 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 45cf47002..b2b7cfaf0 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 aaf669ff4..44492cf6c 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 a7023207c..bdb5842ae 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.h" -#include "events.h" +#include +#include "OISCompat.hpp" +#include "events.hpp" +namespace osgViewer +{ + class Viewer; +} -namespace SFO +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; + + MouseListener* mMouseListener; + KeyListener* mKeyboardListener; + WindowListener* mWindowListener; + ControllerListener* mConListener; - typedef boost::unordered_map KeyMap; + 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 51b701b48..a82a11d75 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 9742d389c..5decaf1eb 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 b825943fc..000000000 --- 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 7135a571a..000000000 --- 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 48149827a..000000000 --- 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 4069959cb..000000000 --- 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 637fae0ef..000000000 --- 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 834716b22..000000000 --- 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 249/450] 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 761574c15..71bbfe9f0 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 250/450] 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 fae7ff683..d0515a1fb 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 08d77e7af..403cb79f2 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 9c7a9de20..5e573c1e4 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 325881889..d07f2fb98 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 6590c7e99..0c76f666b 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 36e503c74..6313c0a8f 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 2c5df5cbd..ad0457433 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 000000000..b8ae92c57 --- /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 000000000..646f548e3 --- /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 c69fcca64..f16c0bca4 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 44492cf6c..eb3370cf7 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 b8c56bd00..000000000 --- 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 3036b236b..000000000 --- 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 61d9c32dd..000000000 --- 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 58324fc01..000000000 --- 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 251/450] 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 b2b7cfaf0..4b48b4073 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 252/450] 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 b8ae92c57..9a7c2aa76 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); + + glViewport(0, 0, width, height); - // FIXME: implement for GL ES (PBO & glMapBufferRange?) - glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, resultImage->data()); + 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 253/450] 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 cc9c3d1dc..768652e1a 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 254/450] 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 5e573c1e4..3bedb5d5e 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 7de7ebfb0..68408dd3a 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 109858bc8..de385e94d 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 255/450] 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 2854401c8..ca95a552b 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 256/450] 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 403cb79f2..f9bb297a9 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 bb70c288d..8b792c5a8 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 257/450] 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 862a070d8..237417974 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 258/450] 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 888846789..c0cddb4d0 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 81f044707..3426094c8 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 259/450] 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 6c7fd6ff3..1ee9586ae 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 260/450] 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 3426094c8..a12375a9b 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 26f05e35f..2bb1b66fd 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 0c91dfe6e..a58f0fdf3 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 17fbbe549..5face96a6 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 e920869b9..3e1af6087 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 c9bf22009..49e6ba06f 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 0dc0fe571..7d902b854 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 1ee9586ae..32eb92d2a 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 261/450] 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 49e6ba06f..7822ccb30 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 7d902b854..b13dffb8c 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 32eb92d2a..bbd98be56 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 7f2185b62..eeea0e6e1 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 262/450] 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 0fc25db4c..6abd3c0c9 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 27c08ed32..6b636058f 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 0c76f666b..b800da701 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 000000000..dd89d1072 --- /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 000000000..77f0b8039 --- /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 768652e1a..397a9df04 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 eeea0e6e1..d28240f2c 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 263/450] 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 f9bb297a9..9fb233140 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 c23e2bb94..8ba46339a 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 7822ccb30..7e742e729 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 b13dffb8c..32e081995 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 bbd98be56..91484a6ba 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 279d35329..21ad2d7ef 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 b9b9fad5f..5f2ca19ef 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 851a55166..5ff233348 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 397a9df04..66514c886 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 d28240f2c..4ad2a323f 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 264/450] 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 4ad2a323f..cbb3ff6b0 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 265/450] 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 2c9b1c97e..d28ea0b66 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 266/450] 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 8fdcf6b20..c3be3539e 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 3bedb5d5e..aef37809b 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 6abd3c0c9..7a3dd5e18 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 6b636058f..aec640736 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 c0c9e0ce4..513267c99 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 3caa61548..e2f2f9820 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 afb07eaa6..d9fdc1834 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 68408dd3a..2a32dd9f3 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 cbb3ff6b0..fc8571bf8 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 267/450] 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 9fb233140..be873d09b 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 268/450] 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 be873d09b..ca21e3612 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 eb3370cf7..1f47d5304 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 269/450] 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 ee966c189..98828a041 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 f594cd43c..dbc513049 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 d65e242de..4b3711071 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 aef37809b..0a9e86750 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 fffd2e66e..13234792f 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 ca95a552b..e74038391 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 270/450] 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 95875de10..7d66b2aba 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 4b3711071..a44c0214c 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 68d2e28de..1e1e2c97e 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 95d4429d6..897225a72 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 a162ab68f..d7e20a3a7 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 271/450] 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 9a7c2aa76..70f389136 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 272/450] 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 70f389136..2befc7bd0 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 273/450] 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 1aaf7ab40..ce7a343da 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 274/450] 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 035e57c56..00c4fb815 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 376f3e432..a841edc63 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 18a12d63d..6f87d020b 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 7e742e729..c0eb00ea4 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 275/450] 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 | 367 +++++++++++----------- apps/openmw/mwrender/characterpreview.hpp | 93 +++--- 12 files changed, 377 insertions(+), 354 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 7d66b2aba..9fa5e38a2 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 fb00d6a98..73b950a6a 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 a4515569d..f6e7c6c92 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 cbce86650..a225b4e11 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(); - - 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 (); + 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 ee71d9b04..fc579ae62 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 af4332c7c..a65379fca 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 f188af2b3..b3de9bef0 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 0a9e86750..5649908fc 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 c0cddb4d0..3a0f543d9 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 a12375a9b..0c490b525 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 7d61e3b6c..1a7b4ea39 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() + CharacterPreview::~CharacterPreview () { - + mViewer->getSceneData()->asGroup()->removeChild(mCamera); } - void CharacterPreview::onFrame() + int CharacterPreview::getTextureWidth() const { - if (mRecover) - { - setupRenderTarget(); - mRenderTarget->update(); - mRecover = false; - } + return mSizeX; } - void CharacterPreview::setup () + int CharacterPreview::getTextureHeight() const { - 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(); + return mSizeY; + } - onSetup (); + void CharacterPreview::onSetup() + { } - CharacterPreview::~CharacterPreview () + osg::ref_ptr CharacterPreview::getTexture() { - if (mSceneMgr) - { - mSceneMgr->destroyAllCameras(); - delete mAnimation; - Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); - Ogre::TextureManager::getSingleton().remove(mName); - } + 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(); - } - - void CharacterPreview::loadResource(Ogre::Resource *resource) - { - Ogre::Texture* tex = dynamic_cast(resource); - if (!tex) - return; - - tex->createInternalResources(); - mRenderTarget = NULL; - mViewport = NULL; - mRecover = true; + redraw(); } - void CharacterPreview::setupRenderTarget() + void CharacterPreview::redraw() { - 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; - } - - void InventoryPreview::resize(int sizeX, int sizeY) - { - mSizeX = sizeX; - mSizeY = sizeY; + sizeX = std::max(sizeX, 0); + sizeY = std::max(sizeY, 0); - mViewport->setDimensions (0, 0, std::min(1.f, float(mSizeX) / float(512)), std::min(1.f, float(mSizeY) / float(1024))); - mTexture->load(); + mCamera->setViewport(0, 0, std::min(mSizeX, sizeX), std::min(mSizeY, sizeY)); - 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(); + redraw(); } - void InventoryPreview::setupRenderTarget() + int InventoryPreview::getSlotSelected (int posX, int posY) { - CharacterPreview::setupRenderTarget(); - mViewport->setDimensions (0, 0, std::min(1.f, float(mSizeX) / float(512)), std::min(1.f, float(mSizeY) / float(1024))); + // TODO: implement + return 0; } - int InventoryPreview::getSlotSelected (int posX, int posY) + void InventoryPreview::updatePtr(const MWWorld::Ptr &ptr) { - return mSelectionBuffer->getSelected (posX, posY); + mCharacter = MWWorld::Ptr(ptr.getBase(), NULL); } - void InventoryPreview::onSetup () + void InventoryPreview::onSetup() { - delete mSelectionBuffer; - mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, 0); + osg::Vec3f scale (1.f, 1.f, 1.f); + mCharacter.getClass().adjustScale(mCharacter, scale); - mAnimation->showWeapons(true); + mNode->setScale(scale); - mCurrentAnimGroup = "inventoryhandtohand"; - mAnimation->play(mCurrentAnimGroup, 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); + 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(); } - void RaceSelectionPreview::onSetup () + class UpdateCameraCallback : public osg::NodeCallback { - mAnimation->play("idle", 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); + public: + UpdateCameraCallback(osg::ref_ptr nodeToFollow, const osg::Vec3& posOffset, const osg::Vec3& lookAtOffset) + : mNodeToFollow(nodeToFollow) + , mPosOffset(posOffset) + , mLookAtOffset(lookAtOffset) + { + } - updateCamera(); - } + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osg::Camera* cam = static_cast(node); - void RaceSelectionPreview::updateCamera() + // 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 () { - Ogre::Vector3 scale = mNode->getScale(); - Ogre::Node* headNode = mAnimation->getNode("Bip01 Head"); - if (!headNode) - return; - Ogre::Vector3 headOffset = headNode->_getDerivedPosition(); - headOffset = mNode->convertLocalToWorldPosition(headOffset); + mAnimation->play("idle", 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); + mAnimation->runAnimation(0.f); - mCamera->setPosition(headOffset + mPosition * scale); - mCamera->lookAt(headOffset + mPosition*Ogre::Vector3(0,1,0) * scale); + // 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); } + } diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index 80dbe18b4..b7722d1f3 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(); - - virtual void rebuild(); + int getTextureWidth() const; + int getTextureHeight() const; - void onFrame(); + void redraw(); - void loadResource(Ogre::Resource *resource); + void rebuild(); - 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(); - - Ogre::TexturePtr mTexture; - Ogre::RenderTarget* mRenderTarget; - Ogre::Viewport* mViewport; - - Ogre::Camera* mCamera; - - Ogre::SceneManager* mSceneMgr; - Ogre::SceneNode* mNode; + osg::ref_ptr mViewer; + Resource::ResourceSystem* mResourceSystem; + osg::ref_ptr mTexture; + osg::ref_ptr mCamera; + osg::ref_ptr mDrawOnceCallback; - 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 276/450] 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 df5f65029..065ee60d9 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 277/450] 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 a225b4e11..943d09f1a 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 14eed0e10..f423142e0 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 1a7b4ea39..cc6b4a9bb 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 2bb1b66fd..932da30b9 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 a58f0fdf3..7ebc42784 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 c0eb00ea4..5ece10dc1 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 278/450] 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 49e2acbd2..2432b5eb2 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 279/450] 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 932da30b9..b23a72e55 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 7ebc42784..eda59f50c 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 280/450] 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 04b53a8e3..db34e0411 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 281/450] 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 3a0f543d9..df6d6e9f2 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 0c490b525..119814135 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 25d9e9e47..e15dee532 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 b23a72e55..5fafa6d59 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 282/450] 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 | 222 +++++++++++----------- 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, 326 insertions(+), 170 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 9fa5e38a2..941222b0c 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 ca21e3612..5ce1607b5 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 df6d6e9f2..416f66cec 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 119814135..82b54bdea 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 c7a27dfe8..a92f90158 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,82 +65,70 @@ 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); } - void Camera::reset() + MWWorld::Ptr Camera::getTrackingPtr() const { - togglePreviewMode(false); - toggleVanityMode(false); - if (!mFirstPersonView) - toggleViewMode(); + return mTrackingPtr; } - void Camera::rotateCamera(const Ogre::Vector3 &rot, bool adjust) + void Camera::updateCamera(osg::Camera *cam) { - if (adjust) { - setYaw(getYaw() + rot.z); - setPitch(getPitch() + rot.x); - } else { - setYaw(rot.z); - setPitch(rot.x); - } + 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]; - 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; - } + osg::Vec3 position = worldMat.getTrans(); + if (!isFirstPerson()) + position.z() += mHeight; - if (isFirstPerson()) - mCamera->getParentNode()->setOrientation(orient); - else - mCameraNode->setOrientation(orient); + 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); } - const std::string &Camera::getHandle() const + void Camera::reset() { - return mTrackingPtr.getRefData().getHandle(); + togglePreviewMode(false); + toggleVanityMode(false); + if (!mFirstPersonView) + toggleViewMode(); } - Ogre::SceneNode* Camera::attachTo(const MWWorld::Ptr &ptr) + void Camera::rotateCamera(float pitch, float yaw, bool adjust) { - 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) + if (adjust) { - node->setOrientation(mCameraNode->getOrientation()); - posNode->setPosition(mCameraPosNode->getPosition()); - mCameraNode->getCreator()->destroySceneNode(mCameraNode); - mCameraNode->getCreator()->destroySceneNode(mCameraPosNode); + pitch += getPitch(); + yaw += getYaw(); } - mCameraNode = node; - mCameraPosNode = posNode; - - if (!isFirstPerson()) - { - mCamera->detachFromParent(); - mCameraPosNode->attachObject(mCamera); - } - - return mCameraPosNode; + setYaw(yaw); + setPitch(pitch); } - void Camera::setPosition(const Ogre::Vector3& position) + void Camera::attachTo(const MWWorld::Ptr &ptr) { - mCameraPosNode->setPosition(position); - } - - void Camera::setPosition(float x, float y, float z) - { - setPosition(Ogre::Vector3(x,y,z)); + mTrackingPtr = ptr; } 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 691a80862..68f0870d7 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 5ece10dc1..bbff16a10 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 32e081995..bb04d04e1 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 d087a40d8..fd63146f2 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 91484a6ba..110ed61be 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 21ad2d7ef..67d4f863a 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 283/450] 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 5769138fa..a89a06091 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 987a0d29a..2b2131061 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 416f66cec..e8d6bbcc9 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 82b54bdea..20fbbed5c 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 5face96a6..6c5709b5d 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 3e1af6087..298dc97bb 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 bbff16a10..9b796a359 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 bb04d04e1..8a81aacd7 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 fd63146f2..d210ff162 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 284/450] 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 9b796a359..def16ae30 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 285/450] 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 def16ae30..4a28ba9de 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 286/450] 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 db34e0411..840bb3bd6 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 91e166bef..5f89b1b43 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 110ed61be..c81a3f71b 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 287/450] 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 b7722d1f3..0f85cc3bf 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 e15dee532..810fc8b19 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 298dc97bb..716192959 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 2f3a87c5b..6b432ae5e 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 ebf3ee87f..652de28b4 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 b37a38353..655e0a073 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 288/450] 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 | 79 +++++++++++++++++------ 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, 98 insertions(+), 45 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 008d64aaf..88dbf89f8 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 1e41aea24..b6eb930c9 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 463209df8..829862ad1 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 513985c94..60de42151 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 840bb3bd6..afc81da8b 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))); - - 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])); - */ + object.setWorldTransform(btTransform(toBullet(orient), toBullet(center))); + + 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 5f89b1b43..aca24105e 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 4a28ba9de..af4e46f62 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 c81a3f71b..35b6fc103 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 67d4f863a..8b4772309 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 289/450] 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 fc8571bf8..64ef4e302 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 290/450] 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 a92f90158..3982e5ad4 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 291/450] 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 a95a66f7e..c14ad6930 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 5951cb101..b5b1f1560 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 292/450] 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 35b6fc103..30be5a00c 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 293/450] 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 6c5709b5d..237e90b74 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 872695556..512f9f4ad 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 294/450] 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 30be5a00c..70751e445 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 295/450] 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 d0515a1fb..4b6ede3dd 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 265577d98..000000000 --- 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 6d0586775..000000000 --- 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 296/450] 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 | 4 ++-- 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, 25 insertions(+), 26 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index ec184a563..6ddea913a 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 5ce1607b5..08dba334f 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 e9c973fc3..b96e79ca9 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 7a3dd5e18..1b5abc099 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 afc81da8b..b32ac2f52 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())) + , mDebugDrawEnabled(false) , mTimeAccum(0.0f) - , mWaterEnabled(false) , mWaterHeight(0) - , mDebugDrawEnabled(false) + , mWaterEnabled(false) , mParentNode(parentNode) { mCollisionConfiguration = new btDefaultCollisionConfiguration(); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index e8d6bbcc9..1c436d440 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 5fafa6d59..aeff1f60a 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 237e90b74..3d981a9c7 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 5e559eeed..9fffd76d1 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 6b432ae5e..43c88427e 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 a73985cfb..0a6f8f505 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 27665b6c6..d676bc3f8 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 3cfd91f1f..b733987d0 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 416477cdd..5e463aae3 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 484cea447..d31e3d107 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 f105977ba..96941126b 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 297/450] 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 941222b0c..d45e76f25 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 b55ececc2..791c2f57e 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 b69222664..f675fe1d8 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 014c67f16..d0d7d73d2 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 9446a1dae..1e6872a76 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 27af1e65b..f79bfce15 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 298/450] 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 4f7a5b87f..442f493c1 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 299/450] 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 66514c886..3fb4adf42 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 64ef4e302..6653966cf 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 300/450] 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 af4e46f62..b8620d60b 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 8a81aacd7..2978c9983 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 3fb4adf42..19e3bcf88 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 6653966cf..0581d7356 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 301/450] 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 | 65 ++++-------------- apps/openmw/mwworld/worldimp.hpp | 3 +- 7 files changed, 144 insertions(+), 60 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 3d981a9c7..cb53105a7 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 716192959..b3799d0ef 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 b8620d60b..c49a44493 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 2978c9983..011ceee09 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 512f9f4ad..7382438d1 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 442f493c1..5689b12cc 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); - void World::performUpdateSceneQueries () - { -#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)); + MWBase::Environment::get().getWindowManager()->setFocusObjectScreenCoords( + screenBounds.x(), screenBounds.y(), screenBounds.z(), screenBounds.w()); } -#endif } - void World::getFacedHandle(std::string& facedHandle, float maxDistance, bool ignorePlayer) + MWWorld::Ptr World::getFacedObject(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); + 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 af1e68af1..e217f4bc4 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 302/450] 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 b32ac2f52..065be083d 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 aca24105e..2ebe16e3b 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 5689b12cc..57b8b67a4 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 303/450] 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 c49a44493..e60b35524 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 304/450] Fix debug drawer crash --- apps/openmw/mwrender/bulletdebugdraw.cpp | 46 ++++++++++++++++-------- apps/openmw/mwrender/bulletdebugdraw.hpp | 3 ++ 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwrender/bulletdebugdraw.cpp b/apps/openmw/mwrender/bulletdebugdraw.cpp index 9e683232b..36fc24226 100644 --- a/apps/openmw/mwrender/bulletdebugdraw.cpp +++ b/apps/openmw/mwrender/bulletdebugdraw.cpp @@ -28,19 +28,39 @@ DebugDrawer::DebugDrawer(osg::ref_ptr parentNode, btDynamicsWorld *w mParentNode->addChild(mGeode); mGeode->setNodeMask(Mask_Debug); - mGeometry = new osg::Geometry; + createGeometry(); - mVertices = new osg::Vec3Array; + mParentNode->addChild(mGeode); +} + +void DebugDrawer::createGeometry() +{ + if (!mGeometry) + { + mGeometry = new osg::Geometry; - mDrawArrays = new osg::DrawArrays(osg::PrimitiveSet::LINES); + mVertices = new osg::Vec3Array; - mGeometry->setUseDisplayList(false); - mGeometry->setVertexArray(mVertices); - mGeometry->setDataVariance(osg::Object::DYNAMIC); - mGeometry->addPrimitiveSet(mDrawArrays); + mDrawArrays = new osg::DrawArrays(osg::PrimitiveSet::LINES); - mGeode->addDrawable(mGeometry); - mParentNode->addChild(mGeode); + 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() @@ -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 288091e7c..d2a4163cf 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 305/450] 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 1e6872a76..12fe8ae4d 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 306/450] 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 | 524 +++++++++++----------- 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, 530 insertions(+), 453 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 08dba334f..9bfd86709 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 d1f1ad3a3..37112477e 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 6d1bc34bc..c0e2ade0f 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 a1e027f89..43df37b6d 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 9eed9811a..72fc06f6a 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 cdb2d6bdf..1f084402b 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 a1e6e4d21..baacc7133 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 28fd13335..95de175a3 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 1e1e2c97e..92cd880f4 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 43acbeaab..5dd201068 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 5649908fc..e4ecdad53 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 d07f2fb98..c0184d4b6 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 1a712461e..7084af862 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 1c436d440..1f78f0dd8 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 cc6b4a9bb..62c732051 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 f675fe1d8..8ab16283e 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" + +namespace +{ + + 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; + }; + +} -using namespace MWRender; -using namespace Ogre; +namespace MWRender +{ -LocalMap::LocalMap() - : mMapResolution(Settings::Manager::getInt("local map resolution", "Map")) +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); - - 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"); -} + mRoot = mViewer->getSceneData()->asGroup(); -LocalMap::~LocalMap() -{ + SceneUtil::FindByNameVisitor find("Scene Root"); + mRoot->accept(find); + mSceneRoot = find.mFoundNode; + if (!mSceneRoot) + throw std::runtime_error("no scene root found"); } -const Ogre::Vector2 LocalMap::rotatePoint(const Ogre::Vector2& p, const Ogre::Vector2& c, const float angle) +LocalMap::~LocalMap() { - 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); + 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); } -std::string LocalMap::coordStr(const int x, const int y) +const osg::Vec2f LocalMap::rotatePoint(const osg::Vec2f& p, const osg::Vec2f& c, const float angle) { - 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) { - mInterior = false; + 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; +} - 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))); +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; 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); - - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); - Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y); + osg::Vec2f min(mBounds.xMin(), mBounds.yMin()); + osg::Vec2f max(mBounds.xMax(), mBounds.yMax()); - Vector2 length = max-min; + osg::Vec2f 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)); - - mInteriorName = cell->getCell()->mName; + 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; 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); + + 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)); + + osg::Vec2f pos = osg::Vec2f(rotatedCenter.x(), rotatedCenter.y()) + center; - std::string texturePrefix = cell->getCell()->mName + "_" + coordStr(x,y); + osg::ref_ptr camera = createOrthographicCamera(pos.x(), pos.y(), + mMapWorldSize, mMapWorldSize, + osg::Vec3f(north.x(), north.y(), 0.f), zMin, zMax); - render(newcenter.x - center.x, newcenter.y - center.y, zMin, zMax, static_cast(sSize), static_cast(sSize), texturePrefix); + 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::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) -{ - mCellCamera->setFarClipDistance( (zhigh-zlow) + 2000 ); - mCellCamera->setNearClipDistance(50); - - 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) +void LocalMap::worldToInteriorMapPosition (osg::Vec2f pos, float& nX, float& nY, int& x, int& y) { - pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().y), mAngle); + pos = rotatePoint(pos, osg::Vec2f(mBounds.center().x(), mBounds.center().y()), mAngle); - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); + osg::Vec2f min(mBounds.xMin(), mBounds.yMin()); - x = static_cast(std::ceil((pos.x - min.x) / sSize) - 1); - y = static_cast(std::ceil((pos.y - min.y) / sSize) - 1); + 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 - sSize*x)/sSize; - nY = 1.0f-(pos.y - min.y - sSize*y)/sSize; + nX = (pos.x() - min.x() - mMapWorldSize*x)/mMapWorldSize; + nY = 1.0f-(pos.y() - min.y() - mMapWorldSize*y)/mMapWorldSize; } -Ogre::Vector2 LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, int y) +osg::Vec2f LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, int y) { - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); - Ogre::Vector2 pos; + osg::Vec2f min(mBounds.xMin(), mBounds.yMin()); + osg::Vec2f pos (mMapWorldSize * (nX + x) + min.x(), + mMapWorldSize * (1.0f-nY + y) + min.y()); - 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); + worldToInteriorMapPosition(pos, u,v, x,y); - // 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 d0d7d73d2..8160c325c 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 MWRender +namespace osgViewer { - class RenderingManager; + class Viewer; +} +namespace osg +{ + class Texture2D; + class Camera; + class Group; + class Node; +} + +namespace MWRender +{ /// /// \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 cb53105a7..816002753 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 e60b35524..b1c26812c 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 43c88427e..990f3a5d9 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 7382438d1..c9ac35c67 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 397ebbe75..939fbe873 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 57b8b67a4..e20904d71 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 e217f4bc4..dedfebdf2 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 2a32dd9f3..0a846b227 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 d676bc3f8..06d5d8792 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 adf7e94b4..5fdf964c4 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 b733987d0..ac304bdf3 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 ce7a343da..e53a55bf3 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 1cd73589a..dd0c2d3e6 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 065ee60d9..dd6b9a499 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 307/450] 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 8ab16283e..0da14f702 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 8160c325c..ba92cde24 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 308/450] 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 b1c26812c..6a1ed89a2 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 990f3a5d9..d66761195 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 309/450] 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 dd6b9a499..2a67c6ce6 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 ea4245aa8..bd7c586c4 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 310/450] 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 1f084402b..f6a9f5ccd 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 816002753..47a54fdbf 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 b3799d0ef..5c7ea32f4 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 6a1ed89a2..e1f1e13d1 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 8a0d526fa..5c3d9f151 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 9f3c5387e..625c1cd5e 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 311/450] 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 7084af862..c47ecd17c 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 065be083d..b706912ed 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 2ebe16e3b..75666acd7 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 ddb984821..79d4de1a0 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 36fc24226..8ac8e3121 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 d2a4163cf..66af2f565 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 89daf898a..33c8c449d 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 ae4279f40..0865b134a 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 312/450] 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 d45e76f25..b4ecdd956 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 c47ecd17c..94d93e7d7 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 60de42151..7a12f549d 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 b706912ed..2bd88e634 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 75666acd7..841085f47 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 79d4de1a0..94434b856 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 02f9ebdd1..ef1a24d44 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 8ac8e3121..c6d7935c5 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 66af2f565..1bccc20bd 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 b75f3105a..5204c00ce 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 313/450] Restore savegame screenshot display --- apps/openmw/mwgui/savegamedialog.cpp | 62 +++++++++++++++++----------- apps/openmw/mwgui/savegamedialog.hpp | 1 + components/CMakeLists.txt | 2 +- components/files/memorystream.hpp | 31 ++++++++++++++ 4 files changed, 70 insertions(+), 26 deletions(-) create mode 100644 components/files/memorystream.hpp diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 980afdfae..ab8d93a87 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::string textureName = "@savegame_screenshot"; - Ogre::TexturePtr texture; - texture = Ogre::TextureManager::getSingleton().getByName(textureName); - mScreenshot->setImageTexture(""); - if (texture.isNull()) + const std::vector& data = mCurrentSlot->mProfile.mScreenshot; + Files::IMemStream instream (&data[0], data.size()); + + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("jpg"); + if (!readerwriter) + { + std::cerr << "Can't open savegame screenshot, no jpg readerwriter found" << std::endl; + return; + } + + osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(instream); + if (!result.success()) { - 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 << "Failed to read savegame screenshot: " << result.message() << std::endl; + return; } - texture->unload(); - texture->setWidth(image.getWidth()); - texture->setHeight(image.getHeight()); - texture->loadImage(image); - mScreenshot->setImageTexture(textureName); -#endif + 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 2192adbde..6a9e59cc6 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 b800da701..6a5b7f59a 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 000000000..9a3510044 --- /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 314/450] 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 0c462c67d..cd6e2405c 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 315/450] 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 e20904d71..38353fa68 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 316/450] 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 3982e5ad4..a945a171e 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 317/450] 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 | 363 +++++++++++++----------- apps/openmw/mwrender/localmap.hpp | 56 ++-- apps/openmw/mwstate/statemanagerimp.cpp | 2 + apps/openmw/mwworld/worldimp.cpp | 4 +- 9 files changed, 267 insertions(+), 205 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 37112477e..f8bf157c2 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 95de175a3..8d2aaf04a 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 92cd880f4..b44b545d2 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 e4ecdad53..88b0bd321 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 c0184d4b6..c275a9f62 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 0da14f702..0e7256345 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 + mSegments.clear(); +} + +osg::ref_ptr LocalMap::getMapTexture(int x, int y) +{ + SegmentMap::iterator found = mSegments.find(std::make_pair(x, y)); + if (found == mSegments.end()) + return osg::ref_ptr(); else - mTextures.clear(); + return found->second.mMapTexture; } -osg::ref_ptr LocalMap::getMapTexture(bool interior, int x, int y) +osg::ref_ptr LocalMap::getFogOfWarTexture(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.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()) - { - std::map >::iterator anIter; + MapSegment& segment = mSegments[std::make_pair(texX, texY)]; - // get its buffer - anIter = mBuffers.find(texName); - if (anIter == mBuffers.end()) return; + if (!segment.mFogOfWarImage || !segment.mMapTexture) + continue; - std::vector& aBuffer = (*anIter).second; - int i=0; - for (int texV = 0; texVdata(); + 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); - - ++i; - } - } + float sqrDist = square((texU + mx*(sFogOfWarResolution-1)) - u*(sFogOfWarResolution-1)) + + square((texV + my*(sFogOfWarResolution-1)) - v*(sFogOfWarResolution-1)); - tex->load(); + uint32_t clr = *(uint32_t*)data; + uint8_t alpha = (clr >> 24); - // 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(); + 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; + } } + + 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 ba92cde24..c319b7ce7 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 0883bc63b..d403590dd 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 38353fa68..427a41d64 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 318/450] 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 fccace55c..9ec5bc19a 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 9f3a23dd0..7588a3287 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 20fbbed5c..d298fdff0 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 810fc8b19..b653f4d30 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 47a54fdbf..2eb72dfd2 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 0b81532e1..09f6de072 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 319/450] 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 0e7256345..495ea2d1d 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 320/450] 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 9bfd86709..fed1f134b 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 c321c342c..a9209bf58 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 321/450] 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 2befc7bd0..1c5008f7a 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 322/450] 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 8d2aaf04a..3a56d3dfd 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 b44b545d2..40ccbda5f 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 323/450] 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 | 146 ++++++++++++++++++++--------- apps/openmw/mwrender/globalmap.hpp | 6 +- 4 files changed, 115 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 3a56d3dfd..46e2f29e0 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 40ccbda5f..bea3d33b9 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 da1be0028..8ca21cbfb 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); - - mOverlayImage.loadDynamicImage(&buffer[0], mWidth, mHeight, 1, Ogre::PF_A8B8G8R8, true); // pass ownership of buffer to image + 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(); - 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)); - - // 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; - else - mOverlayTexture->convertToImage(mOverlayImage); + std::min(mWidth, mWidth + rightDiff * cellImageSizeDst), + std::min(mHeight, mHeight + bottomDiff * cellImageSizeDst)); - Ogre::TextureManager::getSingleton().remove("@temp"); - */ + 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 + { + // 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 d7e20a3a7..9ca7ed5b4 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 324/450] Port global map exploration --- apps/openmw/mwgui/mapwindow.cpp | 9 +- apps/openmw/mwrender/globalmap.cpp | 239 +++++++++++++++++++++++------ apps/openmw/mwrender/globalmap.hpp | 53 ++++++- apps/openmw/mwrender/localmap.cpp | 5 + apps/openmw/mwrender/localmap.hpp | 2 + 5 files changed, 255 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 46e2f29e0..d748bef6c 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 8ca21cbfb..1e30eb0fc 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); - if (cellX > mMaxX || cellX < mMinX || cellY > mMaxY || cellY < mMinY) - return; + camera->setUpdateCallback(new CameraUpdateCallback(camera, this)); - /* - Ogre::TexturePtr localMapTexture = Ogre::TextureManager::getSingleton().getByName("Cell_" - + boost::lexical_cast(cellX) + "_" + boost::lexical_cast(cellY)); + camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); + camera->attach(osg::Camera::COLOR_BUFFER, mOverlayTexture); - if (!localMapTexture.isNull()) + if (cpuCopy) { - 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); - } + // 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; + + 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,11 +354,15 @@ 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; } }; @@ -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 9ca7ed5b4..7adb8218a 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 495ea2d1d..edc88ac55 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 c319b7ce7..72ee0354e 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 325/450] 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 1e30eb0fc..bcf9e74bf 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 d66761195..5b01edb16 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 326/450] 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 5204c00ce..6d5c517af 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 327/450] 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 5fdf964c4..219f6e194 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 328/450] 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 7588a3287..9feb831c9 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 91f4f766e..327f59df8 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 329/450] 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 237417974..0131adc89 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 330/450] 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 327f59df8..fed96f213 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 331/450] 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 6beb1bc80..4b51485f2 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 332/450] 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 0131adc89..36c5c02a1 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 333/450] 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 b4476de11..6593bbf89 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 9feb831c9..a8a6f74aa 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 97dea7341..ee48d124f 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 72a68e96b..0ae9395c5 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 ff3d2fceb..8965d3b0d 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 221c67267..4140fd3c0 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 b8ebf99d0..54860fc31 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 b5b1f1560..61055aa73 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 427a41d64..08617d0d6 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 84fe6e896..0ef1356e7 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 334/450] 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 939fbe873..db1f9714a 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 dedfebdf2..b642a1ba7 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 335/450] 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 2bd88e634..8e63fecfb 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 841085f47..2240a5119 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 08617d0d6..39b26c5d2 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 336/450] 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 a8a6f74aa..379025c9e 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 fed96f213..403f270d8 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 d298fdff0..d1a1b01c6 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 62c732051..cdf99f0fc 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 337/450] 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 219f6e194..1f089f0c4 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 87a1f9f9aa2e05db33df52b3a35efe94e9935988 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 30 May 2015 15:31:44 +0300 Subject: [PATCH 338/450] Add ID completion manager --- apps/opencs/CMakeLists.txt | 1 + .../model/world/idcompletionmanager.cpp | 121 ++++++++++++++++++ .../model/world/idcompletionmanager.hpp | 38 ++++++ 3 files changed, 160 insertions(+) create mode 100644 apps/opencs/model/world/idcompletionmanager.cpp create mode 100644 apps/opencs/model/world/idcompletionmanager.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 7723b15f5..99ba54ac1 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -26,6 +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 ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/idcompletionmanager.cpp b/apps/opencs/model/world/idcompletionmanager.cpp new file mode 100644 index 000000000..ca614dcd9 --- /dev/null +++ b/apps/opencs/model/world/idcompletionmanager.cpp @@ -0,0 +1,121 @@ +#include "idcompletionmanager.hpp" + +#include + +#include + +#include "data.hpp" +#include "idtablebase.hpp" + +namespace +{ + std::map generateModelTypes() + { + std::map types; + + types[CSMWorld::Columns::ColumnId_Actor] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_AreaObject] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_AreaSound] = CSMWorld::UniversalId::Type_Sound; + types[CSMWorld::Columns::ColumnId_BoltObject] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_BoltSound] = CSMWorld::UniversalId::Type_Sound; + types[CSMWorld::Columns::ColumnId_CastingObject] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_CastingSound] = CSMWorld::UniversalId::Type_Sound; + types[CSMWorld::Columns::ColumnId_Cell] = CSMWorld::UniversalId::Type_Cell; + types[CSMWorld::Columns::ColumnId_Class] = CSMWorld::UniversalId::Type_Class; + types[CSMWorld::Columns::ColumnId_Creature] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_DestinationCell] = CSMWorld::UniversalId::Type_Cell; + types[CSMWorld::Columns::ColumnId_Enchantment] = CSMWorld::UniversalId::Type_Enchantment; + types[CSMWorld::Columns::ColumnId_Faction] = CSMWorld::UniversalId::Type_Faction; + types[CSMWorld::Columns::Columnid_Hair] = CSMWorld::UniversalId::Type_Mesh; + types[CSMWorld::Columns::ColumnId_Head] = CSMWorld::UniversalId::Type_Mesh; + types[CSMWorld::Columns::ColumnId_HitObject] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_HitSound] = CSMWorld::UniversalId::Type_Sound; + types[CSMWorld::Columns::ColumnId_Icon] = CSMWorld::UniversalId::Type_Icon; + types[CSMWorld::Columns::ColumnId_InventoryItemId] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_MajorSkill1] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_MajorSkill2] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_MajorSkill3] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_MajorSkill4] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_MajorSkill5] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_MinorSkill1] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_MinorSkill2] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_MinorSkill3] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_MinorSkill4] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_MinorSkill5] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_Model] = CSMWorld::UniversalId::Type_Mesh; + types[CSMWorld::Columns::ColumnId_Owner] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_OwnerGlobal] = CSMWorld::UniversalId::Type_Global; + types[CSMWorld::Columns::ColumnId_Particle] = CSMWorld::UniversalId::Type_Texture; + types[CSMWorld::Columns::ColumnId_PcFaction] = CSMWorld::UniversalId::Type_Faction; + types[CSMWorld::Columns::ColumnId_Race] = CSMWorld::UniversalId::Type_Race; + types[CSMWorld::Columns::ColumnId_ReferenceableId] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_Region] = CSMWorld::UniversalId::Type_Region; + types[CSMWorld::Columns::ColumnId_Skill1] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_Skill2] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_Skill3] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_Skill4] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_Skill5] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_Skill6] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_Skill7] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_SleepEncounter] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_Soul] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_Sound] = CSMWorld::UniversalId::Type_Sound; + types[CSMWorld::Columns::ColumnId_SoundFile] = CSMWorld::UniversalId::Type_SoundRes; + types[CSMWorld::Columns::ColumnId_SoundName] = CSMWorld::UniversalId::Type_Sound; + types[CSMWorld::Columns::ColumnId_SpellId] = CSMWorld::UniversalId::Type_Spell; + types[CSMWorld::Columns::ColumnId_Script] = CSMWorld::UniversalId::Type_Script; + types[CSMWorld::Columns::ColumnId_TeleportCell] = CSMWorld::UniversalId::Type_Cell; + types[CSMWorld::Columns::ColumnId_Texture] = CSMWorld::UniversalId::Type_Texture; + types[CSMWorld::Columns::ColumnId_Trap] = CSMWorld::UniversalId::Type_Spell; + + return types; + } +} + +const std::map + CSMWorld::IdCompletionManager::sCompleterModelTypes = generateModelTypes(); + +CSMWorld::IdCompletionManager::IdCompletionManager(CSMWorld::Data &data) +{ + generateCompleters(data); +} + +bool CSMWorld::IdCompletionManager::isCompleterExistFor(CSMWorld::Columns::ColumnId id) const +{ + return mCompleters.find(id) != mCompleters.end(); +} + +boost::shared_ptr CSMWorld::IdCompletionManager::getCompleter(CSMWorld::Columns::ColumnId id) +{ + if (!isCompleterExistFor(id)) + { + throw std::logic_error("This column doesn't have an ID completer"); + } + return mCompleters[id]; +} + +void CSMWorld::IdCompletionManager::generateCompleters(CSMWorld::Data &data) +{ + typedef std::map::const_iterator ModelTypeConstIterator; + + ModelTypeConstIterator current = sCompleterModelTypes.begin(); + ModelTypeConstIterator end = sCompleterModelTypes.end(); + for (; current != end; ++current) + { + QAbstractItemModel *model = data.getTableModel(current->second); + CSMWorld::IdTableBase *table = dynamic_cast(model); + if (table != NULL) + { + int idColumn = table->searchColumnIndex(CSMWorld::Columns::ColumnId_Id); + if (idColumn != -1) + { + boost::shared_ptr completer = boost::make_shared(table); + completer->setCompletionColumn(idColumn); + // The completion role must be Qt::DisplayRole to get the ID values from the model + completer->setCompletionRole(Qt::DisplayRole); + completer->setCaseSensitivity(Qt::CaseInsensitive); + mCompleters[current->first] = completer; + } + } + } +} \ No newline at end of file diff --git a/apps/opencs/model/world/idcompletionmanager.hpp b/apps/opencs/model/world/idcompletionmanager.hpp new file mode 100644 index 000000000..725cfa331 --- /dev/null +++ b/apps/opencs/model/world/idcompletionmanager.hpp @@ -0,0 +1,38 @@ +#ifndef CSM_WORLD_IDCOMPLETIONMANAGER_HPP +#define CSM_WORLD_IDCOMPLETIONMANAGER_HPP + +#include + +#include + +#include "columns.hpp" +#include "universalid.hpp" + +class QCompleter; + +namespace CSMWorld +{ + class Data; + + /// \brief Creates and stores all ID completers + class IdCompletionManager + { + static const std::map sCompleterModelTypes; + + std::map > mCompleters; + + // Don't allow copying + IdCompletionManager(const IdCompletionManager &); + IdCompletionManager &operator = (const IdCompletionManager &); + + void generateCompleters(CSMWorld::Data &data); + + public: + IdCompletionManager(CSMWorld::Data &data); + + bool isCompleterExistFor(CSMWorld::Columns::ColumnId id) const; + boost::shared_ptr getCompleter(CSMWorld::Columns::ColumnId id); + }; +} + +#endif \ No newline at end of file From 19cc6b83e5c795f8b1a8b8fb9989ab84d262b1ed Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 30 May 2015 15:40:23 +0300 Subject: [PATCH 339/450] Integrate the Id completion manager into the Document class --- apps/opencs/model/doc/document.cpp | 8 +++++++- apps/opencs/model/doc/document.hpp | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index a73201ec0..1e3d1c59b 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2257,7 +2257,8 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, mSavingOperation (*this, mProjectPath, encoding), mSaving (&mSavingOperation), mResDir(resDir), - mRunner (mProjectPath), mPhysics(boost::shared_ptr()) + mRunner (mProjectPath), mPhysics(boost::shared_ptr()), + mIdCompletionManager(mData) { if (mContentFiles.empty()) throw std::runtime_error ("Empty content file sequence"); @@ -2488,3 +2489,8 @@ boost::shared_ptr CSMDoc::Document::getPhysics () return mPhysics; } + +CSMWorld::IdCompletionManager &CSMDoc::Document::getIdCompletionManager() +{ + return mIdCompletionManager; +} \ No newline at end of file diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 6b1a1fc1e..14daeeb75 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -13,6 +13,7 @@ #include #include "../world/data.hpp" +#include "../world/idcompletionmanager.hpp" #include "../tools/tools.hpp" @@ -66,6 +67,7 @@ namespace CSMDoc Blacklist mBlacklist; Runner mRunner; boost::shared_ptr mPhysics; + CSMWorld::IdCompletionManager mIdCompletionManager; // 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. @@ -144,6 +146,8 @@ namespace CSMDoc boost::shared_ptr getPhysics(); + CSMWorld::IdCompletionManager &getIdCompletionManager(); + signals: void stateChanged (int state, CSMDoc::Document *document); From 33e36ee9227d88e334c8dbc9f0fd8017216d54ee Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 30 May 2015 15:51:33 +0300 Subject: [PATCH 340/450] Add the ID completion delegate --- apps/opencs/CMakeLists.txt | 2 +- .../view/world/idcompletiondelegate.cpp | 41 +++++++++++++++++++ .../view/world/idcompletiondelegate.hpp | 36 ++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/world/idcompletiondelegate.cpp create mode 100644 apps/opencs/view/world/idcompletiondelegate.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 99ba54ac1..efbe77ccb 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -69,7 +69,7 @@ opencs_units (view/world opencs_units_noqt (view/world subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate - scripthighlighter idvalidator dialoguecreator physicssystem + scripthighlighter idvalidator dialoguecreator physicssystem idcompletiondelegate ) opencs_units (view/widget diff --git a/apps/opencs/view/world/idcompletiondelegate.cpp b/apps/opencs/view/world/idcompletiondelegate.cpp new file mode 100644 index 000000000..0f309054b --- /dev/null +++ b/apps/opencs/view/world/idcompletiondelegate.cpp @@ -0,0 +1,41 @@ +#include "idcompletiondelegate.hpp" + +#include "../../model/world/idcompletionmanager.hpp" + +CSVWorld::IdCompletionDelegate::IdCompletionDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document& document, + QObject *parent) + : CommandDelegate(dispatcher, document, parent) +{} + +QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_None); +} + +QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index, + CSMWorld::ColumnBase::Display display) const +{ + int columnIdData = index.data(CSMWorld::ColumnBase::Role_ColumnId).toInt(); + CSMWorld::Columns::ColumnId columnId = static_cast(columnIdData); + CSMWorld::IdCompletionManager &completionManager = getDocument().getIdCompletionManager(); + + QWidget *editor = CSVWorld::CommandDelegate::createEditor(parent, option, index, display); + QLineEdit *lineEditor = qobject_cast(editor); + if (lineEditor != NULL && completionManager.isCompleterExistFor(columnId)) + { + lineEditor->setCompleter(completionManager.getCompleter(columnId).get()); + } + return editor; +} + +CSVWorld::CommandDelegate *CSVWorld::IdCompletionDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document& document, + QObject *parent) const +{ + return new IdCompletionDelegate(dispatcher, document, parent); +} \ No newline at end of file diff --git a/apps/opencs/view/world/idcompletiondelegate.hpp b/apps/opencs/view/world/idcompletiondelegate.hpp new file mode 100644 index 000000000..11ecc1cb9 --- /dev/null +++ b/apps/opencs/view/world/idcompletiondelegate.hpp @@ -0,0 +1,36 @@ +#ifndef CSV_WORLD_IDCOMPLETIONMANAGER_HPP +#define CSV_WORLD_IDCOMPLETIONMANAGER_HPP + +#include "util.hpp" + +namespace CSVWorld +{ + /// \brief Enables the Id completion for a column + class IdCompletionDelegate : public CommandDelegate + { + public: + IdCompletionDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document& document, + QObject *parent); + + virtual QWidget *createEditor (QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const; + + virtual QWidget *createEditor (QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index, + CSMWorld::ColumnBase::Display display) const; + }; + + class IdCompletionDelegateFactory : public CommandDelegateFactory + { + public: + virtual CommandDelegate *makeDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document& document, + QObject *parent) const; + ///< The ownership of the returned CommandDelegate is transferred to the caller. + }; +} + +#endif \ No newline at end of file From 5e8718d8b2ba976f7e1c4a339a464f7786b047c1 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 30 May 2015 18:37:13 +0300 Subject: [PATCH 341/450] Add the ID completion delegate factory to the delegate factory collection --- apps/opencs/view/doc/viewmanager.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 97b7aac19..3e7c2cb97 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -16,6 +16,7 @@ #include "../world/vartypedelegate.hpp" #include "../world/recordstatusdelegate.hpp" #include "../world/idtypedelegate.hpp" +#include "../world/idcompletiondelegate.hpp" #include "../../model/settings/usersettings.hpp" @@ -60,6 +61,33 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) mDelegateFactories->add (CSMWorld::ColumnBase::Display_RefRecordType, new CSVWorld::IdTypeDelegateFactory()); + // Columns with QLineEdit editor + static const CSMWorld::ColumnBase::Display sIdCompletionColumns[] = + { + CSMWorld::ColumnBase::Display_Class, + CSMWorld::ColumnBase::Display_Faction, + CSMWorld::ColumnBase::Display_String, + CSMWorld::ColumnBase::Display_GlobalVariable, + CSMWorld::ColumnBase::Display_Icon, + CSMWorld::ColumnBase::Display_Mesh, + CSMWorld::ColumnBase::Display_Miscellaneous, + CSMWorld::ColumnBase::Display_Music, + CSMWorld::ColumnBase::Display_None, + CSMWorld::ColumnBase::Display_Race, + CSMWorld::ColumnBase::Display_Region, + CSMWorld::ColumnBase::Display_Script, + CSMWorld::ColumnBase::Display_Skill, + CSMWorld::ColumnBase::Display_Sound, + CSMWorld::ColumnBase::Display_SoundRes, + CSMWorld::ColumnBase::Display_Texture, + CSMWorld::ColumnBase::Display_Video + }; + + for (std::size_t i = 0; i < sizeof(sIdCompletionColumns) / sizeof(CSMWorld::ColumnBase::Display); ++i) + { + mDelegateFactories->add(sIdCompletionColumns[i], new CSVWorld::IdCompletionDelegateFactory()); + } + struct Mapping { CSMWorld::ColumnBase::Display mDisplay; From 602f33bd91dfcc87da6d8a0cef37d40d2f482594 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 30 May 2015 21:30:25 +0300 Subject: [PATCH 342/450] Add ColumnId role to the IdTree data methods --- apps/opencs/model/world/idtree.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 7351c03a7..a9ec2c4cd 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -35,28 +35,26 @@ QVariant CSMWorld::IdTree::data (const QModelIndex & index, int role) const if (!index.isValid()) return QVariant(); - if ((role!=Qt::DisplayRole && role!=Qt::EditRole) || index.row() < 0 || index.column() < 0) - return QVariant(); - if (index.internalId() != 0) { std::pair parentAddress(unfoldIndexAddress(index.internalId())); + const NestableColumn *parentColumn = mNestedCollection->getNestableColumn(parentAddress.second); - if (role == Qt::EditRole && - !mNestedCollection->getNestableColumn(parentAddress.second)->nestedColumn(index.column()).isEditable()) - { + if (role == ColumnBase::Role_ColumnId) + return parentColumn->nestedColumn(index.column()).mColumnId; + + if (role == Qt::EditRole && !parentColumn->nestedColumn(index.column()).isEditable()) + return QVariant(); + + if (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant(); - } return mNestedCollection->getNestedData(parentAddress.first, parentAddress.second, index.row(), index.column()); } else { - if (role==Qt::EditRole && !idCollection()->getColumn (index.column()).isEditable()) - return QVariant(); - - return idCollection()->getData (index.row(), index.column()); + return IdTable::data(index, role); } } @@ -79,6 +77,9 @@ QVariant CSMWorld::IdTree::nestedHeaderData(int section, int subSection, Qt::Ori if (role==ColumnBase::Role_Display) return parentColumn->nestedColumn(subSection).mDisplayType; + if (role==ColumnBase::Role_ColumnId) + return parentColumn->nestedColumn(subSection).mColumnId; + return QVariant(); } From 62ce2cc123fb0a50ec3471664f235823b89979fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 May 2015 20:44:19 +0200 Subject: [PATCH 343/450] Minor cleanup --- CMakeLists.txt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 87c3fabd4..3c3cd9f6b 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 e943d17b2905fb3b509662cda4800f6e5129191d Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 30 May 2015 22:01:21 +0300 Subject: [PATCH 344/450] Check for invalid index in IdTable::flags(). This prevents QCompleter from crashes --- apps/opencs/model/world/idtable.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 04aa271cc..bde6412ec 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -84,6 +84,9 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const { + if (!index.isValid()) + return 0; + Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; if (mIdCollection->getColumn (index.column()).isUserEditable()) From 994c6833bcd91f72d00d1784a227dfcc14f0cfbc Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 30 May 2015 23:54:16 +0300 Subject: [PATCH 345/450] Add missing columns for the ID completion --- apps/opencs/model/world/idcompletionmanager.cpp | 11 +++++++++-- apps/opencs/view/doc/viewmanager.cpp | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/idcompletionmanager.cpp b/apps/opencs/model/world/idcompletionmanager.cpp index ca614dcd9..c9e135c83 100644 --- a/apps/opencs/model/world/idcompletionmanager.cpp +++ b/apps/opencs/model/world/idcompletionmanager.cpp @@ -22,16 +22,19 @@ namespace types[CSMWorld::Columns::ColumnId_CastingSound] = CSMWorld::UniversalId::Type_Sound; types[CSMWorld::Columns::ColumnId_Cell] = CSMWorld::UniversalId::Type_Cell; types[CSMWorld::Columns::ColumnId_Class] = CSMWorld::UniversalId::Type_Class; + types[CSMWorld::Columns::ColumnId_CloseSound] = CSMWorld::UniversalId::Type_Sound; types[CSMWorld::Columns::ColumnId_Creature] = CSMWorld::UniversalId::Type_Referenceable; types[CSMWorld::Columns::ColumnId_DestinationCell] = CSMWorld::UniversalId::Type_Cell; types[CSMWorld::Columns::ColumnId_Enchantment] = CSMWorld::UniversalId::Type_Enchantment; types[CSMWorld::Columns::ColumnId_Faction] = CSMWorld::UniversalId::Type_Faction; - types[CSMWorld::Columns::Columnid_Hair] = CSMWorld::UniversalId::Type_Mesh; - types[CSMWorld::Columns::ColumnId_Head] = CSMWorld::UniversalId::Type_Mesh; + types[CSMWorld::Columns::Columnid_Hair] = CSMWorld::UniversalId::Type_BodyPart; + types[CSMWorld::Columns::ColumnId_Head] = CSMWorld::UniversalId::Type_BodyPart; types[CSMWorld::Columns::ColumnId_HitObject] = CSMWorld::UniversalId::Type_Referenceable; types[CSMWorld::Columns::ColumnId_HitSound] = CSMWorld::UniversalId::Type_Sound; types[CSMWorld::Columns::ColumnId_Icon] = CSMWorld::UniversalId::Type_Icon; types[CSMWorld::Columns::ColumnId_InventoryItemId] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_Key] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_LevelledItemId] = CSMWorld::UniversalId::Type_Referenceable; types[CSMWorld::Columns::ColumnId_MajorSkill1] = CSMWorld::UniversalId::Type_Skill; types[CSMWorld::Columns::ColumnId_MajorSkill2] = CSMWorld::UniversalId::Type_Skill; types[CSMWorld::Columns::ColumnId_MajorSkill3] = CSMWorld::UniversalId::Type_Skill; @@ -43,9 +46,13 @@ namespace types[CSMWorld::Columns::ColumnId_MinorSkill4] = CSMWorld::UniversalId::Type_Skill; types[CSMWorld::Columns::ColumnId_MinorSkill5] = CSMWorld::UniversalId::Type_Skill; types[CSMWorld::Columns::ColumnId_Model] = CSMWorld::UniversalId::Type_Mesh; + types[CSMWorld::Columns::ColumnId_OpenSound] = CSMWorld::UniversalId::Type_Sound; + types[CSMWorld::Columns::ColumnId_OriginalCreature] = CSMWorld::UniversalId::Type_Referenceable; types[CSMWorld::Columns::ColumnId_Owner] = CSMWorld::UniversalId::Type_Referenceable; types[CSMWorld::Columns::ColumnId_OwnerGlobal] = CSMWorld::UniversalId::Type_Global; types[CSMWorld::Columns::ColumnId_Particle] = CSMWorld::UniversalId::Type_Texture; + types[CSMWorld::Columns::ColumnId_PartRefMale] = CSMWorld::UniversalId::Type_BodyPart; + types[CSMWorld::Columns::ColumnId_PartRefFemale] = CSMWorld::UniversalId::Type_BodyPart; types[CSMWorld::Columns::ColumnId_PcFaction] = CSMWorld::UniversalId::Type_Faction; types[CSMWorld::Columns::ColumnId_Race] = CSMWorld::UniversalId::Type_Race; types[CSMWorld::Columns::ColumnId_ReferenceableId] = CSMWorld::UniversalId::Type_Referenceable; diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 3e7c2cb97..f48513703 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -64,7 +64,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) // Columns with QLineEdit editor static const CSMWorld::ColumnBase::Display sIdCompletionColumns[] = { + CSMWorld::ColumnBase::Display_Cell, CSMWorld::ColumnBase::Display_Class, + CSMWorld::ColumnBase::Display_Creature, CSMWorld::ColumnBase::Display_Faction, CSMWorld::ColumnBase::Display_String, CSMWorld::ColumnBase::Display_GlobalVariable, @@ -72,15 +74,20 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) CSMWorld::ColumnBase::Display_Mesh, CSMWorld::ColumnBase::Display_Miscellaneous, CSMWorld::ColumnBase::Display_Music, - CSMWorld::ColumnBase::Display_None, + CSMWorld::ColumnBase::Display_None, // Inplace editing (Table SubView) creates QLineEdit using Display_None + CSMWorld::ColumnBase::Display_Npc, CSMWorld::ColumnBase::Display_Race, + CSMWorld::ColumnBase::Display_Referenceable, CSMWorld::ColumnBase::Display_Region, CSMWorld::ColumnBase::Display_Script, CSMWorld::ColumnBase::Display_Skill, CSMWorld::ColumnBase::Display_Sound, CSMWorld::ColumnBase::Display_SoundRes, + CSMWorld::ColumnBase::Display_Static, + CSMWorld::ColumnBase::Display_String, CSMWorld::ColumnBase::Display_Texture, - CSMWorld::ColumnBase::Display_Video + CSMWorld::ColumnBase::Display_Video, + CSMWorld::ColumnBase::Display_Weapon }; for (std::size_t i = 0; i < sizeof(sIdCompletionColumns) / sizeof(CSMWorld::ColumnBase::Display); ++i) From a066b2430331e156f340e50f32dd56785d945df3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 May 2015 01:07:43 +0200 Subject: [PATCH 346/450] 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 b4ecdd956..2193f4ca0 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 c0e2ade0f..4d01f9529 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 379025c9e..5765d8b04 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 d1a1b01c6..86dd21df4 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 a945a171e..392f8978a 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 b653f4d30..b98b26179 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 ccb553d99..61d077df3 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 aeff1f60a..e9e3b7aef 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 eda59f50c..0f90bb2d7 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 d16afe3ce..23a74fb95 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 400962856..f46638ac8 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 39b26c5d2..768177b16 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 b642a1ba7..b1718f030 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 8ce76a8ea..9f1a935ae 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 347/450] 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 403f270d8..b23981f81 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 86dd21df4..e30f2b082 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 392f8978a..bb4724555 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 e9e3b7aef..598e2fba9 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 0f90bb2d7..28ae43144 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 9e405b69fa74e429c23b4039365957dbdf1bc82d Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 31 May 2015 16:43:28 +0300 Subject: [PATCH 348/450] Create the custom completer popup to avoid the problem with the wrong height of the default popup --- apps/opencs/CMakeLists.txt | 2 +- .../model/world/idcompletionmanager.cpp | 7 +++++ apps/opencs/view/widget/completerpopup.cpp | 28 +++++++++++++++++++ apps/opencs/view/widget/completerpopup.hpp | 17 +++++++++++ 4 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/widget/completerpopup.cpp create mode 100644 apps/opencs/view/widget/completerpopup.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index efbe77ccb..37d13223a 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -74,7 +74,7 @@ opencs_units_noqt (view/world opencs_units (view/widget scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton - scenetooltoggle2 + scenetooltoggle2 completerpopup ) opencs_units (view/render diff --git a/apps/opencs/model/world/idcompletionmanager.cpp b/apps/opencs/model/world/idcompletionmanager.cpp index c9e135c83..c483a9fb5 100644 --- a/apps/opencs/model/world/idcompletionmanager.cpp +++ b/apps/opencs/model/world/idcompletionmanager.cpp @@ -4,6 +4,8 @@ #include +#include "../../view/widget/completerpopup.hpp" + #include "data.hpp" #include "idtablebase.hpp" @@ -121,6 +123,11 @@ void CSMWorld::IdCompletionManager::generateCompleters(CSMWorld::Data &data) // The completion role must be Qt::DisplayRole to get the ID values from the model completer->setCompletionRole(Qt::DisplayRole); completer->setCaseSensitivity(Qt::CaseInsensitive); + + QAbstractItemView *popup = new CSVWidget::CompleterPopup(); + completer->setPopup(popup); // The completer takes ownership of the popup + completer->setMaxVisibleItems(10); + mCompleters[current->first] = completer; } } diff --git a/apps/opencs/view/widget/completerpopup.cpp b/apps/opencs/view/widget/completerpopup.cpp new file mode 100644 index 000000000..ad50b76e6 --- /dev/null +++ b/apps/opencs/view/widget/completerpopup.cpp @@ -0,0 +1,28 @@ +#include "completerpopup.hpp" + +CSVWidget::CompleterPopup::CompleterPopup(QWidget *parent) + : QListView(parent) +{ + setEditTriggers(QAbstractItemView::NoEditTriggers); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setSelectionBehavior(QAbstractItemView::SelectRows); + setSelectionMode(QAbstractItemView::SingleSelection); +} + +int CSVWidget::CompleterPopup::sizeHintForRow(int row) const +{ + if (model() == NULL) + { + return -1; + } + if (row < 0 || row >= model()->rowCount()) + { + return -1; + } + + ensurePolished(); + QModelIndex index = model()->index(row, modelColumn()); + QStyleOptionViewItem option = viewOptions(); + QAbstractItemDelegate *delegate = itemDelegate(index); + return delegate->sizeHint(option, index).height(); +} \ No newline at end of file diff --git a/apps/opencs/view/widget/completerpopup.hpp b/apps/opencs/view/widget/completerpopup.hpp new file mode 100644 index 000000000..92731ab50 --- /dev/null +++ b/apps/opencs/view/widget/completerpopup.hpp @@ -0,0 +1,17 @@ +#ifndef CSV_WIDGET_COMPLETERPOPUP_HPP +#define CSV_WIDGET_COMPLETERPOPUP_HPP + +#include + +namespace CSVWidget +{ + class CompleterPopup : public QListView + { + public: + CompleterPopup(QWidget *parent = 0); + + virtual int sizeHintForRow(int row) const; + }; +} + +#endif \ No newline at end of file From e636101725c8fe214bf18bfdab455ed81cfd3d67 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 31 May 2015 18:18:49 +0300 Subject: [PATCH 349/450] Add missing new lines at the ends of files --- apps/opencs/model/doc/document.cpp | 2 +- apps/opencs/model/world/idcompletionmanager.cpp | 2 +- apps/opencs/model/world/idcompletionmanager.hpp | 2 +- apps/opencs/view/widget/completerpopup.cpp | 2 +- apps/opencs/view/widget/completerpopup.hpp | 2 +- apps/opencs/view/world/idcompletiondelegate.cpp | 2 +- apps/opencs/view/world/idcompletiondelegate.hpp | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 1e3d1c59b..18a4f4878 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2493,4 +2493,4 @@ boost::shared_ptr CSMDoc::Document::getPhysics () CSMWorld::IdCompletionManager &CSMDoc::Document::getIdCompletionManager() { return mIdCompletionManager; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/idcompletionmanager.cpp b/apps/opencs/model/world/idcompletionmanager.cpp index c483a9fb5..ff5ec6b4b 100644 --- a/apps/opencs/model/world/idcompletionmanager.cpp +++ b/apps/opencs/model/world/idcompletionmanager.cpp @@ -132,4 +132,4 @@ void CSMWorld::IdCompletionManager::generateCompleters(CSMWorld::Data &data) } } } -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/idcompletionmanager.hpp b/apps/opencs/model/world/idcompletionmanager.hpp index 725cfa331..fff9868ea 100644 --- a/apps/opencs/model/world/idcompletionmanager.hpp +++ b/apps/opencs/model/world/idcompletionmanager.hpp @@ -35,4 +35,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/widget/completerpopup.cpp b/apps/opencs/view/widget/completerpopup.cpp index ad50b76e6..5777325c8 100644 --- a/apps/opencs/view/widget/completerpopup.cpp +++ b/apps/opencs/view/widget/completerpopup.cpp @@ -25,4 +25,4 @@ int CSVWidget::CompleterPopup::sizeHintForRow(int row) const QStyleOptionViewItem option = viewOptions(); QAbstractItemDelegate *delegate = itemDelegate(index); return delegate->sizeHint(option, index).height(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/widget/completerpopup.hpp b/apps/opencs/view/widget/completerpopup.hpp index 92731ab50..6857064b8 100644 --- a/apps/opencs/view/widget/completerpopup.hpp +++ b/apps/opencs/view/widget/completerpopup.hpp @@ -14,4 +14,4 @@ namespace CSVWidget }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/world/idcompletiondelegate.cpp b/apps/opencs/view/world/idcompletiondelegate.cpp index 0f309054b..33e1282d4 100644 --- a/apps/opencs/view/world/idcompletiondelegate.cpp +++ b/apps/opencs/view/world/idcompletiondelegate.cpp @@ -38,4 +38,4 @@ CSVWorld::CommandDelegate *CSVWorld::IdCompletionDelegateFactory::makeDelegate(C QObject *parent) const { return new IdCompletionDelegate(dispatcher, document, parent); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/idcompletiondelegate.hpp b/apps/opencs/view/world/idcompletiondelegate.hpp index 11ecc1cb9..979c10c34 100644 --- a/apps/opencs/view/world/idcompletiondelegate.hpp +++ b/apps/opencs/view/world/idcompletiondelegate.hpp @@ -33,4 +33,4 @@ namespace CSVWorld }; } -#endif \ No newline at end of file +#endif From dbe61115b2086fdee2649972d171db5a93c30793 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 31 May 2015 18:22:43 +0300 Subject: [PATCH 350/450] Fix the mistyping header guard in the idcompletiondelegate.hpp --- apps/opencs/view/world/idcompletiondelegate.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/idcompletiondelegate.hpp b/apps/opencs/view/world/idcompletiondelegate.hpp index 979c10c34..d2ac6874f 100644 --- a/apps/opencs/view/world/idcompletiondelegate.hpp +++ b/apps/opencs/view/world/idcompletiondelegate.hpp @@ -1,5 +1,5 @@ -#ifndef CSV_WORLD_IDCOMPLETIONMANAGER_HPP -#define CSV_WORLD_IDCOMPLETIONMANAGER_HPP +#ifndef CSV_WORLD_IDCOMPLETIONDELEGATE_HPP +#define CSV_WORLD_IDCOMPLETIONDELEGATE_HPP #include "util.hpp" From 71bafcb52bbf590f2a853ec43059ec3e787e2ea7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 May 2015 18:04:14 +0200 Subject: [PATCH 351/450] 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 3333511d3..84e97487a 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 5765d8b04..354ca998c 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(); + + if (!mPtr.getRefData().getBaseNode()) + return; + const osg::Vec3f actorDirection = mPtr.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0); - const Ogre::Vector3 actorDirection = mPtr.getRefData().getBaseNode()->getOrientation().yAxis(); + zAngleRadians = std::atan2(direction.x(), direction.y()) - std::atan2(actorDirection.x(), actorDirection.y()); + xAngleRadians = -std::asin(direction.z()); - 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)); + 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 8e63fecfb..d36aded24 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 e30f2b082..bd864c936 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 598e2fba9..92e61801e 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 28ae43144..db0b4ea0c 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 352/450] 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 2193f4ca0..3cf43749d 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 b98b26179..0dd647c9c 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 61d077df3..8a4ebb930 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 92e61801e..7283a621a 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 000000000..11f5b943d --- /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 000000000..8c3758cb0 --- /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 23a74fb95..301779c1e 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) - return; + for (int i=0; i<2; ++i) + { + mSpineControllers[i] = NULL; - float pitch = xrot * mPitchFactor; - Ogre::Node *node; + 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])); + } + } +} - // 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); +void WeaponAnimation::deleteControllers() +{ + for (int i=0; i<2; ++i) + mSpineControllers[i] = NULL; +} - 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); +void WeaponAnimation::configureControllers(float characterPitchRadians) +{ + if (!mSpineControllers[0]) + return; + + if (mPitchFactor == 0.f || characterPitchRadians == 0.f) + { + for (int i=0; i<2; ++i) + mSpineControllers[i]->setEnabled(false); + return; + } + + 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 f46638ac8..9336afd4c 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 353/450] 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 bb4724555..69998ed26 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 354/450] 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 6862bb889..a984fffa9 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 - { - decoder->open(fname); - } - catch(std::exception&) + // 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)) { - 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 355/450] 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 768177b16..926e453b8 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 356/450] 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 dd20999e0..1122a4069 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 461d8e32e..6adef5eeb 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 43df37b6d..0fab66a25 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 645a72277..75436e797 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 cd6e2405c..b673e5bd0 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 86c502580..08b205ec7 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 c26316626..db0453623 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 5dd201068..526cbaabe 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 996cc528d..1fa5d9cbf 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 357/450] Restore various raycasting --- apps/openmw/mwmechanics/character.cpp | 8 +- apps/openmw/mwphysics/physicssystem.cpp | 73 ++++++++--- 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, 158 insertions(+), 112 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 354ca998c..3843df132 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 d36aded24..c942fecb1 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); - - std::pair result = mEngine->rayTest(_from, _to,ignoreHeightMap); - return !(result.first == ""); - */ - } + public: + ClosestNotMeRayResultCallback(const btCollisionObject* me, const btVector3& from, const btVector3& to) + : btCollisionWorld::ClosestRayResultCallback(from, to) + , mMe(me) + { + } - std::pair PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to) + 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; + }; + + 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 2240a5119..7920347ad 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; + }; + + /// @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 - std::pair castRay(const osg::Vec3f &from, const osg::Vec3f &to); + /// 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 b23981f81..2279375c2 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 642909cda..42a63fc68 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 e1f1e13d1..a067422d4 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 011ceee09..e2524b360 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 c9e69b0b4..81497aa6c 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 926e453b8..f4f960d97 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); + + const float maxDist = 200.f; + osg::Vec3f dir = (dest - origin); + dir.normalize(); + dest = origin + dir * maxDist; - if (!result.first) - return MWWorld::Ptr(); + 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 358/450] 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 c942fecb1..7c083ca08 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 7920347ad..2defd7a50 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 f4f960d97..aa21ca7fb 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 359/450] 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 3c3cd9f6b..43d40c2ef 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 397b4a762..000000000 --- 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 a45298180..000000000 --- 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 a06c002df..000000000 --- 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 360/450] 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 69998ed26..e28b6befa 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 361/450] 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 7c083ca08..c0e7a80b9 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 2defd7a50..d4f7e25b1 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 e28b6befa..9080d3164 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 68f0870d7..a655e1c1f 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 a067422d4..021835839 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 e2524b360..57a2df60e 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 aa21ca7fb..2f47c19e6 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 362/450] 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 7283a621a..0bbec707f 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 363/450] 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 0dd647c9c..9d1fccdb2 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 42a63fc68..c4e457a1f 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 0bbec707f..da44d7f20 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 5c3d9f151..8de08bd9d 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 625c1cd5e..f4ca0dea2 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 364/450] 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 021835839..31ff9b02b 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 8ed229aa6..66e40f3e1 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 56f832a08..a4fcd7866 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 365/450] 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 3cf43749d..c46a83183 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 f7fc515f5..1d3619d3d 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 4d01f9529..f258eb300 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 64850d127..ea67884d3 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 791c2f57e..4307fe9be 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 88b0bd321..1182de151 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 84e97487a..81dbca58a 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 70f1b47d9..f9e58ab4f 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 9ec5bc19a..83f9dffb4 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 ee48d124f..b013dbb1b 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 a2fd8b006..0a31a1a7e 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 0ae9395c5..8fbb31fb7 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 d08334ae8..f695ec57a 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 ba35af777..d6f5da88d 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 373a2a105..6e22c0582 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 8965d3b0d..cdca6eeaa 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 f50584edf..4241c9e3e 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 c0e7a80b9..f97c5fd13 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 d4f7e25b1..7e3c27951 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 efdb49cf7..8580eb8f8 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 d153b7e61..68d7c69e9 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 acbe819f1..84d86fba7 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); - - 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) + 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 f46f544d2..f42bc040f 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 2f47c19e6..126267fd4 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 b1718f030..4c4df2c99 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 51cd5d8c4..38429e459 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 bb7f3cf7c..07a7655c7 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 2c4025ec72dfd021a9252536c2385672b74e39a5 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 2 Jun 2015 00:26:31 +0300 Subject: [PATCH 366/450] Rename the method isCompleterExistFor() to hasCompleterFor() --- apps/opencs/model/world/idcompletionmanager.cpp | 4 ++-- apps/opencs/model/world/idcompletionmanager.hpp | 2 +- apps/opencs/view/world/idcompletiondelegate.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/idcompletionmanager.cpp b/apps/opencs/model/world/idcompletionmanager.cpp index ff5ec6b4b..6736e9477 100644 --- a/apps/opencs/model/world/idcompletionmanager.cpp +++ b/apps/opencs/model/world/idcompletionmanager.cpp @@ -89,14 +89,14 @@ CSMWorld::IdCompletionManager::IdCompletionManager(CSMWorld::Data &data) generateCompleters(data); } -bool CSMWorld::IdCompletionManager::isCompleterExistFor(CSMWorld::Columns::ColumnId id) const +bool CSMWorld::IdCompletionManager::hasCompleterFor(CSMWorld::Columns::ColumnId id) const { return mCompleters.find(id) != mCompleters.end(); } boost::shared_ptr CSMWorld::IdCompletionManager::getCompleter(CSMWorld::Columns::ColumnId id) { - if (!isCompleterExistFor(id)) + if (!hasCompleterFor(id)) { throw std::logic_error("This column doesn't have an ID completer"); } diff --git a/apps/opencs/model/world/idcompletionmanager.hpp b/apps/opencs/model/world/idcompletionmanager.hpp index fff9868ea..ee75ddf24 100644 --- a/apps/opencs/model/world/idcompletionmanager.hpp +++ b/apps/opencs/model/world/idcompletionmanager.hpp @@ -30,7 +30,7 @@ namespace CSMWorld public: IdCompletionManager(CSMWorld::Data &data); - bool isCompleterExistFor(CSMWorld::Columns::ColumnId id) const; + bool hasCompleterFor(CSMWorld::Columns::ColumnId id) const; boost::shared_ptr getCompleter(CSMWorld::Columns::ColumnId id); }; } diff --git a/apps/opencs/view/world/idcompletiondelegate.cpp b/apps/opencs/view/world/idcompletiondelegate.cpp index 33e1282d4..2a1e97f4b 100644 --- a/apps/opencs/view/world/idcompletiondelegate.cpp +++ b/apps/opencs/view/world/idcompletiondelegate.cpp @@ -26,7 +26,7 @@ QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent, QWidget *editor = CSVWorld::CommandDelegate::createEditor(parent, option, index, display); QLineEdit *lineEditor = qobject_cast(editor); - if (lineEditor != NULL && completionManager.isCompleterExistFor(columnId)) + if (lineEditor != NULL && completionManager.hasCompleterFor(columnId)) { lineEditor->setCompleter(completionManager.getCompleter(columnId).get()); } From 01944c33f5a28eb2c64188f9e9259c0cf3b9b780 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Jun 2015 16:35:35 +0200 Subject: [PATCH 367/450] 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 | 549 +++++----------------- 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, 234 insertions(+), 752 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 c46a83183..015d0db9a 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 edc88ac55..3003e4736 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 739ed24d9..000000000 --- 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 b9ab8deac..000000000 --- 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 31ff9b02b..a708bbe88 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 57a2df60e..d90a75c86 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 a74d9bd52..ba767bc55 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 c9ac35c67..3a0336f82 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 f2175ced5..2dd843e4e 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -1,491 +1,184 @@ #include "water.hpp" -#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 - -using namespace Ogre; +#include -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); - */ - } -} +#include +#include +#include +#include +#include +#include -CubeReflection::~CubeReflection () -{ - Ogre::TextureManager::getSingleton ().remove("CubeReflection"); - mSceneMgr->destroyCamera (mCamera); -} +#include +#include -void CubeReflection::update () -{ - if (mParentCamera->isAttached()) - mParentCamera->getParentSceneNode ()->needUpdate (); - mCamera->setPosition(mParentCamera->getDerivedPosition()); -} +#include +#include -// -------------------------------------------------------------------------------------------------------------------------------- +#include "vismask.hpp" -PlaneReflection::PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* sky) - : Reflection(sceneManager) - , mSky(sky) - , mRenderActive(false) +namespace { - mCamera = mSceneMgr->createCamera ("PlaneReflectionCamera"); - mSceneMgr->addRenderQueueListener(this); - - mTexture = TextureManager::getSingleton().createManual("WaterReflection", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, 512, 512, 0, PF_R8G8B8, TU_RENDERTARGET); - - 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); - - sh::Factory::getInstance ().setTextureAlias ("WaterReflection", mTexture->getName()); -} -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) + osg::ref_ptr createWaterGeometry(float size, int segments, float textureRepeats) { - 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); + 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)); + } + } - setHeight(mTop); + osg::ref_ptr waterGeom (new osg::Geometry); + waterGeom->setVertexArray(verts); + waterGeom->setTexCoordArray(0, texcoords); - sh::MaterialInstance* m = sh::Factory::getInstance ().getMaterialInstance ("Water"); - m->setListener (this); + waterGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,verts->size())); + return waterGeom; + } - // ---------------------------------------------------------------------------------------------- - // ---------------------------------- reflection debug overlay ---------------------------------- - // ---------------------------------------------------------------------------------------------- -/* - if (Settings::Manager::getBool("shader", "Water")) + void createWaterStateSet(Resource::ResourceSystem* resourceSystem, osg::ref_ptr node) { - OverlayManager& mgr = OverlayManager::getSingleton(); - Overlay* overlay; - // destroy if already exists - if ((overlay = mgr.getByName("ReflectionDebugOverlay"))) - mgr.destroy(overlay); + osg::ref_ptr stateset (new osg::StateSet); - overlay = mgr.create("ReflectionDebugOverlay"); + 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); - if (MaterialManager::getSingleton().resourceExists("Ogre/ReflectionDebugTexture")) - MaterialManager::getSingleton().remove("Ogre/ReflectionDebugTexture"); - MaterialPtr debugMat = MaterialManager::getSingleton().create( - "Ogre/ReflectionDebugTexture", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + stateset->setMode(GL_BLEND, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); - debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false); - debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(mReflectionTexture->getName()); + osg::ref_ptr depth (new osg::Depth); + depth->setWriteMask(false); + stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); - OverlayContainer* debugPanel; + stateset->setRenderBinDetails(9, "RenderBin"); - // destroy container if exists - try + std::vector > textures; + for (int i=0; i<32; ++i) { - if ((debugPanel = - static_cast( - mgr.getOverlayElement("Ogre/ReflectionDebugTexPanel" - )))) - mgr.destroyOverlayElement(debugPanel); + 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)); } - 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(); + 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); + } - sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty (new sh::FloatValue(active ? 1.0f : 0.0f))); } -Water::~Water() +namespace MWRender { - MeshManager::getSingleton().remove("water"); - - mWaterNode->detachObject(mWater); - mSceneMgr->destroyEntity(mWater); - mSceneMgr->destroySceneNode(mWaterNode); - delete mReflection; - delete mRefraction; - delete mSimulation; -} +// -------------------------------------------------------------------------------------------------------------------------------- -void Water::changeCell(const ESM::Cell* cell) +Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem) + : mParent(parent) + , mResourceSystem(resourceSystem) + , mEnabled(true) + , mToggled(true) + , mTop(0) { - if(cell->isExterior()) - mWaterNode->setPosition(getSceneNodeCoordinates(cell->mData.mX, cell->mData.mY)); -} + osg::ref_ptr waterGeom = createWaterGeometry(CELL_SIZE*150, 40, 900); -void Water::setHeight(const float height) -{ - mTop = height; + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(waterGeom); + geode->setNodeMask(Mask_Water); - mSimulation->setWaterHeight(height); + createWaterStateSet(mResourceSystem, geode); - mWaterPlane = Plane(Vector3::UNIT_Z, -height); + mWaterNode = new osg::PositionAttitudeTransform; + mWaterNode->addChild(geode); - if (mReflection) - mReflection->setHeight(height); - if (mRefraction) - mRefraction->setHeight(height); + mParent->addChild(mWaterNode); - mWaterNode->setPosition(0, 0, height); - sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(height))); + setHeight(mTop); } -bool Water::toggle() +Water::~Water() { - mToggled = !mToggled; - updateVisible(); - return mToggled; + mParent->removeChild(mWaterNode); } -void -Water::updateUnderwater(bool underwater) +void Water::setEnabled(bool enabled) { - if (!mActive) { - return; - } - mIsUnderwater = - underwater && - mWater->isVisible() && - mCamera->getPolygonMode() == Ogre::PM_SOLID; - - if (mReflection) - mReflection->setUnderwater (mIsUnderwater); - if (mRefraction) - mRefraction->setUnderwater (mIsUnderwater); - + mEnabled = enabled; updateVisible(); } -Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) +void Water::changeCell(const MWWorld::CellStore* store) { - return Vector3(static_cast(gridX * CELL_SIZE + (CELL_SIZE / 2)), static_cast(gridY * CELL_SIZE + (CELL_SIZE / 2)), mTop); + 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::setViewportBackground(const ColourValue& bg) +void Water::setHeight(const float height) { - if (mReflection) - mReflection->setViewportBackground(bg); -} + mTop = height; -void Water::updateVisible() -{ - mWater->setVisible(mToggled && mActive); - if (mReflection) - mReflection->setActive(mToggled && mActive); - if (mRefraction) - mRefraction->setActive(mToggled && mActive); + osg::Vec3f pos = mWaterNode->getPosition(); + pos.z() = height; + mWaterNode->setPosition(pos); } -void Water::update(float dt, Ogre::Vector3 player) +void Water::updateVisible() { - mWaterTimer += dt; - sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(mWaterTimer))); - - mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater); - - mPlayer = Ogre::Vector2(player.x, player.y); + mWaterNode->setNodeMask(mEnabled && mToggled ? ~0 : 0); } -void Water::frameStarted(float dt) -{ - if (!mActive) - return; - - mSimulation->update(dt, mPlayer); - - if (mReflection) - { - mReflection->update(); - } -} - -void Water::applyRTT() +bool Water::toggle() { - 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); - } - } - + mToggled = !mToggled; updateVisible(); + return mToggled; } -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) +bool Water::isUnderwater(const osg::Vec3f &pos) const { + return pos.z() < mTop && mToggled && mEnabled; } -void Water::createdConfiguration (sh::MaterialInstance* m, const std::string& configuration) +osg::Vec3f Water::getSceneNodeCoordinates(int gridX, int gridY) { - 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 53d54cdc9..45b4b38a6 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; - Ogre::SceneNode *mWaterNode; - Ogre::Entity *mWater; + osg::ref_ptr mParent; + osg::ref_ptr mWaterNode; + Resource::ResourceSystem* mResourceSystem; - 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 db1f9714a..1a9ae3494 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 126267fd4..799f82015 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 06d5d8792..a314910c5 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 4ebd4f41d..4877c83db 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 4b51485f2..b8b452dc3 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 368/450] 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 015d0db9a..bb71cb6c9 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 2279375c2..9fe9dd451 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 e53a55bf3..6040f9536 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 dd0c2d3e6..d5aecdbb6 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 369/450] 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 9fe9dd451..34a397f9a 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 370/450] 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 a909adb8b..36ff927d8 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 371/450] 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 d8006b581..1b02e13be 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 f84c36b500b09300d49382cdcf4de90449aa32db Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 3 Jun 2015 00:00:39 +0300 Subject: [PATCH 372/450] CommandDelegate: extract a display type from a model if it isn't specified --- apps/opencs/model/world/idtable.cpp | 3 +++ apps/opencs/model/world/idtree.cpp | 3 +++ apps/opencs/view/world/util.cpp | 8 +++++++- apps/opencs/view/world/util.hpp | 2 ++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index bde6412ec..8ca19f7e9 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -33,6 +33,9 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const if (index.row() < 0 || index.column() < 0) return QVariant(); + if (role==ColumnBase::Role_Display) + return QVariant(mIdCollection->getColumn(index.column()).mDisplayType); + if (role==ColumnBase::Role_ColumnId) return QVariant (getColumnId (index.column())); diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index a9ec2c4cd..a3dbae465 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -40,6 +40,9 @@ QVariant CSMWorld::IdTree::data (const QModelIndex & index, int role) const std::pair parentAddress(unfoldIndexAddress(index.internalId())); const NestableColumn *parentColumn = mNestedCollection->getNestableColumn(parentAddress.second); + if (role == ColumnBase::Role_Display) + return parentColumn->nestedColumn(index.column()).mColumnId; + if (role == ColumnBase::Role_ColumnId) return parentColumn->nestedColumn(index.column()).mColumnId; diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 5452214ef..3be875ffd 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -111,6 +111,12 @@ CSMDoc::Document& CSVWorld::CommandDelegate::getDocument() const return mDocument; } +CSMWorld::ColumnBase::Display CSVWorld::CommandDelegate::getDisplayTypeFromIndex(const QModelIndex &index) const +{ + int rawDisplay = index.data(CSMWorld::ColumnBase::Role_Display).toInt(); + return static_cast(rawDisplay); +} + void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const { @@ -146,7 +152,7 @@ void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemMode QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, const QModelIndex& index) const { - return createEditor (parent, option, index, CSMWorld::ColumnBase::Display_None); + return createEditor (parent, option, index, getDisplayTypeFromIndex(index)); } QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index a12e6ae36..8355e971c 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -124,6 +124,8 @@ namespace CSVWorld CSMDoc::Document& getDocument() const; + CSMWorld::ColumnBase::Display getDisplayTypeFromIndex(const QModelIndex &index) const; + virtual void setModelDataImp (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; From 4e759370def736689dfc3acc4f64a4aa5d77ad6b Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 3 Jun 2015 00:02:53 +0300 Subject: [PATCH 373/450] Change Display_String to the proper display type where appropriate --- apps/opencs/model/world/columnbase.cpp | 2 ++ apps/opencs/model/world/columnbase.hpp | 2 ++ apps/opencs/model/world/columnimp.hpp | 21 ++++++++++++-------- apps/opencs/model/world/data.cpp | 8 ++++---- apps/opencs/model/world/refidcollection.cpp | 22 ++++++++++----------- 5 files changed, 32 insertions(+), 23 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 3d13538c0..938503875 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -65,6 +65,8 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_JournalInfo, Display_Scene, Display_GlobalVariable, + Display_BodyPart, + Display_Enchantment, Display_Script, Display_Mesh, diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index bf8378e37..789823d5c 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -74,6 +74,8 @@ namespace CSMWorld Display_JournalInfo, Display_Scene, Display_GlobalVariable, + Display_BodyPart, + Display_Enchantment, //CONCRETE TYPES ENDS HERE Display_Integer, diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 6b496e0ca..8758d924b 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -709,7 +709,7 @@ namespace CSMWorld struct SleepListColumn : public Column { SleepListColumn() - : Column (Columns::ColumnId_SleepEncounter, ColumnBase::Display_String) + : Column (Columns::ColumnId_SleepEncounter, ColumnBase::Display_CreatureLevelledList) {} virtual QVariant get (const Record& record) const @@ -735,7 +735,7 @@ namespace CSMWorld template struct TextureColumn : public Column { - TextureColumn() : Column (Columns::ColumnId_Texture, ColumnBase::Display_String) {} + TextureColumn() : Column (Columns::ColumnId_Texture, ColumnBase::Display_Texture) {} virtual QVariant get (const Record& record) const { @@ -1269,7 +1269,7 @@ namespace CSMWorld template struct TrapColumn : public Column { - TrapColumn() : Column (Columns::ColumnId_Trap, ColumnBase::Display_String) {} + TrapColumn() : Column (Columns::ColumnId_Trap, ColumnBase::Display_Spell) {} virtual QVariant get (const Record& record) const { @@ -1294,7 +1294,7 @@ namespace CSMWorld template struct FilterColumn : public Column { - FilterColumn() : Column (Columns::ColumnId_Filter, ColumnBase::Display_String) {} + FilterColumn() : Column (Columns::ColumnId_Filter, ColumnBase::Display_Filter) {} virtual QVariant get (const Record& record) const { @@ -1497,7 +1497,10 @@ namespace CSMWorld template struct TopicColumn : public Column { - TopicColumn (bool journal) : Column (journal ? Columns::ColumnId_Journal : Columns::ColumnId_Topic, ColumnBase::Display_String) {} + TopicColumn (bool journal) + : Column (journal ? Columns::ColumnId_Journal : Columns::ColumnId_Topic, + journal ? ColumnBase::Display_Journal : ColumnBase::Display_Topic) + {} virtual QVariant get (const Record& record) const { @@ -1527,7 +1530,7 @@ namespace CSMWorld template struct ActorColumn : public Column { - ActorColumn() : Column (Columns::ColumnId_Actor, ColumnBase::Display_String) {} + ActorColumn() : Column (Columns::ColumnId_Actor, ColumnBase::Display_Npc) {} virtual QVariant get (const Record& record) const { @@ -1830,7 +1833,7 @@ namespace CSMWorld template struct ModelColumn : public Column { - ModelColumn() : Column (Columns::ColumnId_Model, ColumnBase::Display_String) {} + ModelColumn() : Column (Columns::ColumnId_Model, ColumnBase::Display_Mesh) {} virtual QVariant get (const Record& record) const { @@ -2158,7 +2161,9 @@ namespace CSMWorld struct EffectTextureColumn : public Column { EffectTextureColumn (Columns::ColumnId columnId) - : Column (columnId, ColumnBase::Display_Texture) + : Column (columnId, + columnId == Columns::ColumnId_Particle ? ColumnBase::Display_Texture + : ColumnBase::Display_Icon) { assert (this->mColumnId==Columns::ColumnId_Icon || this->mColumnId==Columns::ColumnId_Particle); diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index c27c068f1..529c8f88f 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -115,7 +115,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mFactions.getColumns()-1; mFactions.addAdapter (std::make_pair(&mFactions.getColumn(index), new FactionReactionsAdapter ())); mFactions.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Faction, ColumnBase::Display_String)); + new NestedChildColumn (Columns::ColumnId_Faction, ColumnBase::Display_Faction)); mFactions.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_FactionReaction, ColumnBase::Display_Integer)); @@ -135,7 +135,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mRaces.getColumns()-1; mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new SpellListAdapter ())); mRaces.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); + new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_Spell)); // Race attributes mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_RaceAttributes)); index = mRaces.getColumns()-1; @@ -180,7 +180,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mRegions.getColumns()-1; mRegions.addAdapter (std::make_pair(&mRegions.getColumn(index), new RegionSoundListAdapter ())); mRegions.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_String)); + new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_Sound)); mRegions.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_SoundChance, ColumnBase::Display_Integer)); @@ -196,7 +196,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mBirthsigns.addAdapter (std::make_pair(&mBirthsigns.getColumn(index), new SpellListAdapter ())); mBirthsigns.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); + new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_Spell)); mSpells.addColumn (new StringIdColumn); mSpells.addColumn (new RecordStateColumn); diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index cda19c87b..5495926b4 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -99,7 +99,7 @@ CSMWorld::RefIdCollection::RefIdCollection() EnchantableColumns enchantableColumns (inventoryColumns); - mColumns.push_back (RefIdColumn (Columns::ColumnId_Enchantment, ColumnBase::Display_String)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_Enchantment, ColumnBase::Display_Enchantment)); enchantableColumns.mEnchantment = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_EnchantmentPoints, ColumnBase::Display_Integer)); enchantableColumns.mEnchantmentPoints = &mColumns.back(); @@ -135,7 +135,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new NestedInventoryRefIdAdapter (UniversalId::Type_Creature))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), inventoryMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_Referenceable)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer)); @@ -150,7 +150,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new NestedSpellRefIdAdapter (UniversalId::Type_Creature))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), spellsMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_Spell)); // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, @@ -163,7 +163,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new NestedTravelRefIdAdapter (UniversalId::Type_Creature))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), destMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_Cell)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float)); mColumns.back().addColumn( @@ -289,7 +289,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new NestedInventoryRefIdAdapter (UniversalId::Type_Container))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), contMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_Referenceable)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer)); @@ -301,7 +301,7 @@ CSMWorld::RefIdCollection::RefIdCollection() 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_String)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_OriginalCreature, ColumnBase::Display_Creature)); creatureColumns.mOriginal = &mColumns.back(); mColumns.push_back ( RefIdColumn (Columns::ColumnId_CombatState, ColumnBase::Display_Integer)); @@ -409,10 +409,10 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_Faction, ColumnBase::Display_Faction)); npcColumns.mFaction = &mColumns.back(); - mColumns.push_back (RefIdColumn (Columns::Columnid_Hair, ColumnBase::Display_String)); + mColumns.push_back (RefIdColumn (Columns::Columnid_Hair, ColumnBase::Display_BodyPart)); npcColumns.mHair = &mColumns.back(); - mColumns.push_back (RefIdColumn (Columns::ColumnId_Head, ColumnBase::Display_String)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_Head, ColumnBase::Display_BodyPart)); npcColumns.mHead = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_Female, ColumnBase::Display_Boolean)); @@ -539,9 +539,9 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_PartRefType, CSMWorld::ColumnBase::Display_PartRefType)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_PartRefMale, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_PartRefMale, CSMWorld::ColumnBase::Display_BodyPart)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_PartRefFemale, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_PartRefFemale, CSMWorld::ColumnBase::Display_BodyPart)); LevListColumns levListColumns (baseColumns); @@ -556,7 +556,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new NestedLevListRefIdAdapter (UniversalId::Type_ItemLevelledList))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), levListMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_LevelledItemId, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_LevelledItemId, CSMWorld::ColumnBase::Display_Referenceable)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_LevelledItemLevel, CSMWorld::ColumnBase::Display_Integer)); From 10f938ff8763960afb873c283c57afd829690ede Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 01:18:03 +0200 Subject: [PATCH 374/450] 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 e2f2f9820..bf1d66fe8 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 375/450] 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 | 375 ++----------- 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 | 221 ++++---- components/terrain/terraingrid.hpp | 49 +- components/terrain/world.cpp | 56 +- components/terrain/world.hpp | 82 +-- 37 files changed, 529 insertions(+), 2489 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 43d40c2ef..d13437214 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 064e96150..9772a68fa 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 93cd46d86..a41946687 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 343d0d2e6..063413248 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 259ab1779..f4272b887 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 a14eea5dd..fe302cef1 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 bb71cb6c9..ef0c4e135 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 3003e4736..16957a585 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 a708bbe88..6205c3ad8 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 d90a75c86..c22d3c7bf 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 8ad2ea321..269e7f99f 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 e6f4a04ad..93531a552 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 3a0336f82..b794ac24a 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 2dd843e4e..c2149358b 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 45b4b38a6..d389392ba 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 799f82015..e676977de 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 6a5b7f59a..51cb55aee 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 e510616af..edaeadb03 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 5a69fd27a..0795a3ffc 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 e184cbc4c..8f4a3aa92 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 1b000fabb..7dc93f1d6 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 887f0822e..575e9bca2 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 e3bae1173..000000000 --- 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 22b4f26ef..000000000 --- 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 7bc73ddda..000000000 --- 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 4caef8462..000000000 --- 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 6d173d136..7b40ad479 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 4d2318aa6..17acd940b 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) - { - - } - - 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() + FixedFunctionTechnique::FixedFunctionTechnique(const std::vector >& layers, + const std::vector >& blendmaps) { - 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); + 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); } - 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); - } - } - - return mat; - } -#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) + int texunit = 0; + if(!firstLayer) { - sh::MaterialInstancePass* p = material->createPass (); + osg::ref_ptr blendmap = blendmaps.at(i++); - 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))); + stateset->setTextureAttributeAndModes(texunit, blendmap.get()); - 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"))); + // 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)); - // 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)))); + stateset->setTextureAttributeAndModes(texunit, new osg::TexMat(texMat)); - p->mShaderProperties.setProperty ("pass_index", sh::makeProperty(new sh::IntValue(0))); + ++texunit; } - 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; + // Add the actual layer texture multiplied by the alpha map. + osg::ref_ptr tex = *it; + stateset->setTextureAttributeAndModes(texunit, tex.get()); - 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 + 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); - // 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 - } + firstLayer = false; + addPass(stateset); + } + } - 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)))); + 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); - // 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))); + selectTechnique(0); + } - assert ((int)p->mTexUnits.size() == OGRE_MAX_TEXTURE_LAYERS - remainingTextureUnits); + bool Effect::define_techniques() + { + addTechnique(new FixedFunctionTechnique(mLayers, mBlendmaps)); - 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 b79df9f48..47c5142c9 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 (); - - 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; } + FixedFunctionTechnique( + const std::vector >& layers, + const std::vector >& blendmaps); - 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; } + protected: + virtual void define_passes() {} + }; - /// Creates a material suitable for displaying a chunk of terrain using alpha-blending. - Ogre::MaterialPtr generate (); + 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 a ready-made composite map. - Ogre::MaterialPtr generateForCompositeMap (); + virtual bool define_techniques(); - /// 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 89e5e34a3..000000000 --- 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 e44b64600..000000000 --- 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 14009127d..857713a82 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 7846e91c6..a302c8f8c 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 bb99ca23e..e99126a2a 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 +#include + +#include + +#include +#include +#include + +#include + +#include -#include "chunk.hpp" +#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,143 +75,118 @@ 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(), - 0.5f*mStorage->getCellWorldSize(), - maxH); - - Ogre::AxisAlignedBox bounds(min, max); + std::auto_ptr element (new GridElement); - GridElement element; + 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); - Ogre::Vector2 worldCenter = center*mStorage->getCellWorldSize(); - element.mSceneNode = mRootNode->createChildSceneNode(Ogre::Vector3(worldCenter.x, worldCenter.y, 0)); + osg::ref_ptr positions (new osg::Vec3Array); + osg::ref_ptr normals (new osg::Vec3Array); + osg::ref_ptr colors (new osg::Vec4Array); - std::vector positions; - std::vector normals; - std::vector colours; - mStorage->fillVertexBuffers(0, 1, center, mAlign, positions, normals, colours); + mStorage->fillVertexBuffers(0, 1, center, positions, normals, colors); - 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); + 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); - std::vector blendmaps; - std::vector layerList; - mStorage->getBlendmaps(1, center, mShaders, blendmaps, layerList); + geometry->addPrimitiveSet(mCache.getIndexBuffer(0)); - element.mMaterialGenerator.setLayerList(layerList); - - // upload blendmaps to GPU - std::vector blendTextures; - for (std::vector::const_iterator it = blendmaps.begin(); it != blendmaps.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); - } + // 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)); - element.mMaterialGenerator.setBlendmapList(blendTextures); + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(geometry); - element.mSceneNode->attachObject(element.mChunk); - updateMaterial(element); + std::vector layerList; + std::vector > blendmaps; + mStorage->getBlendmaps(1.f, center, false, blendmaps, layerList); - mGrid[std::make_pair(x,y)] = element; -} + // For compiling textures, I don't think the osgFX::Effect does it correctly + osg::ref_ptr textureCompileDummy (new osg::Node); -void TerrainGrid::updateMaterial(GridElement &element) -{ - element.mMaterialGenerator.enableShadows(getShadowsEnabled()); - element.mMaterialGenerator.enableSplitShadows(getSplitShadowsEnabled()); - element.mChunk->setMaterial(element.mMaterialGenerator.generate()); -} + 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()); + } -void TerrainGrid::unloadCell(int x, int y) -{ - Grid::iterator it = mGrid.find(std::make_pair(x,y)); - if (it == mGrid.end()) - return; + 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()); + } - GridElement& element = it->second; - delete element.mChunk; - element.mChunk = NULL; + for (unsigned int i=0; isetTexCoordArray(i, mCache.getUVBuffer()); - 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()); + osg::ref_ptr effect (new Terrain::Effect(layerTextures, blendmapTextures)); - mSceneMgr->destroySceneNode(element.mSceneNode); - element.mSceneNode = NULL; + effect->addCullCallback(new SceneUtil::LightListCallback); - mGrid.erase(it); -} + effect->addChild(geode); + element->mNode->addChild(effect); -void TerrainGrid::applyMaterials(bool shadows, bool splitShadows) -{ - mShadows = shadows; - mSplitShadows = splitShadows; - for (Grid::iterator it = mGrid.begin(); it != mGrid.end(); ++it) + if (mIncrementalCompileOperation) { - updateMaterial(it->second); + mIncrementalCompileOperation->add(geode); + mIncrementalCompileOperation->add(textureCompileDummy); } -} -bool TerrainGrid::getVisible() -{ - return mVisible; -} - -void TerrainGrid::setVisible(bool visible) -{ - mVisible = visible; - mRootNode->setVisible(visible); + mGrid[std::make_pair(x,y)] = element.release(); } -Ogre::AxisAlignedBox TerrainGrid::getWorldBoundingBox (const Ogre::Vector2& center) +void TerrainGrid::unloadCell(int x, int y) { - 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)); + Grid::iterator it = mGrid.find(std::make_pair(x,y)); 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; -} + return; -void TerrainGrid::syncLoad() -{ + GridElement* element = it->second; + mTerrainRoot->removeChild(element->mNode); + delete element; + mGrid.erase(it); } } diff --git a/components/terrain/terraingrid.hpp b/components/terrain/terraingrid.hpp index 97ef6d14d..3a6d71793 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 3baaaed44..1cfcc80ac 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 3e63b4c93..70ec30410 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; + + Resource::ResourceSystem* mResourceSystem; - // 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); + 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 376/450] 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 17acd940b..ddfa10f12 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 377/450] 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 7dc93f1d6..dfb3eff88 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 e99126a2a..7ae4d8511 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 378/450] 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 e676977de..93a34f233 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 379/450] 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 593775970..a9c9a8c6b 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 ddfa10f12..2af8ddcda 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 380/450] 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 93a34f233..6376772c3 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 381/450] 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 | 50 +++++++++++++------------------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6376772c3..2f9a13f78 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2638,42 +2638,32 @@ 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::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; + 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; - } + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(origin, dest, actor); + target = result.mHitObject; + hitPosition = result.mHitPos; std::string selectedSpell = stats.getSpells().getSelectedSpell(); From 41cce5240fc4e225288b924daddaec9a62a3868e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 03:29:21 +0200 Subject: [PATCH 382/450] 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 ef0c4e135..b23828254 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 2693d68b2..000000000 --- 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 6974f37b9..000000000 --- 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 f75061af4..000000000 --- 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 4551476a4..000000000 --- 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 f2e60b11b..000000000 --- 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 fe125f54c..000000000 --- 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 b25cc6bc556ff688fcf5becd4d71c3551f5681af Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 3 Jun 2015 12:01:13 +0300 Subject: [PATCH 383/450] IdCompletionManager uses Display type instread of ColumnId for creating completers --- .../model/world/idcompletionmanager.cpp | 117 +++++++----------- .../model/world/idcompletionmanager.hpp | 17 +-- apps/opencs/view/doc/viewmanager.cpp | 38 ++---- .../view/world/idcompletiondelegate.cpp | 16 ++- 4 files changed, 70 insertions(+), 118 deletions(-) diff --git a/apps/opencs/model/world/idcompletionmanager.cpp b/apps/opencs/model/world/idcompletionmanager.cpp index 6736e9477..b59987cba 100644 --- a/apps/opencs/model/world/idcompletionmanager.cpp +++ b/apps/opencs/model/world/idcompletionmanager.cpp @@ -11,102 +11,77 @@ namespace { - std::map generateModelTypes() + std::map generateModelTypes() { - std::map types; + std::map types; - types[CSMWorld::Columns::ColumnId_Actor] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_AreaObject] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_AreaSound] = CSMWorld::UniversalId::Type_Sound; - types[CSMWorld::Columns::ColumnId_BoltObject] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_BoltSound] = CSMWorld::UniversalId::Type_Sound; - types[CSMWorld::Columns::ColumnId_CastingObject] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_CastingSound] = CSMWorld::UniversalId::Type_Sound; - types[CSMWorld::Columns::ColumnId_Cell] = CSMWorld::UniversalId::Type_Cell; - types[CSMWorld::Columns::ColumnId_Class] = CSMWorld::UniversalId::Type_Class; - types[CSMWorld::Columns::ColumnId_CloseSound] = CSMWorld::UniversalId::Type_Sound; - types[CSMWorld::Columns::ColumnId_Creature] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_DestinationCell] = CSMWorld::UniversalId::Type_Cell; - types[CSMWorld::Columns::ColumnId_Enchantment] = CSMWorld::UniversalId::Type_Enchantment; - types[CSMWorld::Columns::ColumnId_Faction] = CSMWorld::UniversalId::Type_Faction; - types[CSMWorld::Columns::Columnid_Hair] = CSMWorld::UniversalId::Type_BodyPart; - types[CSMWorld::Columns::ColumnId_Head] = CSMWorld::UniversalId::Type_BodyPart; - types[CSMWorld::Columns::ColumnId_HitObject] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_HitSound] = CSMWorld::UniversalId::Type_Sound; - types[CSMWorld::Columns::ColumnId_Icon] = CSMWorld::UniversalId::Type_Icon; - types[CSMWorld::Columns::ColumnId_InventoryItemId] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_Key] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_LevelledItemId] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_MajorSkill1] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_MajorSkill2] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_MajorSkill3] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_MajorSkill4] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_MajorSkill5] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_MinorSkill1] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_MinorSkill2] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_MinorSkill3] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_MinorSkill4] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_MinorSkill5] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_Model] = CSMWorld::UniversalId::Type_Mesh; - types[CSMWorld::Columns::ColumnId_OpenSound] = CSMWorld::UniversalId::Type_Sound; - types[CSMWorld::Columns::ColumnId_OriginalCreature] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_Owner] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_OwnerGlobal] = CSMWorld::UniversalId::Type_Global; - types[CSMWorld::Columns::ColumnId_Particle] = CSMWorld::UniversalId::Type_Texture; - types[CSMWorld::Columns::ColumnId_PartRefMale] = CSMWorld::UniversalId::Type_BodyPart; - types[CSMWorld::Columns::ColumnId_PartRefFemale] = CSMWorld::UniversalId::Type_BodyPart; - types[CSMWorld::Columns::ColumnId_PcFaction] = CSMWorld::UniversalId::Type_Faction; - types[CSMWorld::Columns::ColumnId_Race] = CSMWorld::UniversalId::Type_Race; - types[CSMWorld::Columns::ColumnId_ReferenceableId] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_Region] = CSMWorld::UniversalId::Type_Region; - types[CSMWorld::Columns::ColumnId_Skill1] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_Skill2] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_Skill3] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_Skill4] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_Skill5] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_Skill6] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_Skill7] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_SleepEncounter] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_Soul] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_Sound] = CSMWorld::UniversalId::Type_Sound; - types[CSMWorld::Columns::ColumnId_SoundFile] = CSMWorld::UniversalId::Type_SoundRes; - types[CSMWorld::Columns::ColumnId_SoundName] = CSMWorld::UniversalId::Type_Sound; - types[CSMWorld::Columns::ColumnId_SpellId] = CSMWorld::UniversalId::Type_Spell; - types[CSMWorld::Columns::ColumnId_Script] = CSMWorld::UniversalId::Type_Script; - types[CSMWorld::Columns::ColumnId_TeleportCell] = CSMWorld::UniversalId::Type_Cell; - types[CSMWorld::Columns::ColumnId_Texture] = CSMWorld::UniversalId::Type_Texture; - types[CSMWorld::Columns::ColumnId_Trap] = CSMWorld::UniversalId::Type_Spell; + types[CSMWorld::ColumnBase::Display_BodyPart ] = CSMWorld::UniversalId::Type_BodyPart; + types[CSMWorld::ColumnBase::Display_Cell ] = CSMWorld::UniversalId::Type_Cell; + types[CSMWorld::ColumnBase::Display_Class ] = CSMWorld::UniversalId::Type_Class; + types[CSMWorld::ColumnBase::Display_CreatureLevelledList] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::ColumnBase::Display_Creature ] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::ColumnBase::Display_Enchantment ] = CSMWorld::UniversalId::Type_Enchantment; + types[CSMWorld::ColumnBase::Display_Faction ] = CSMWorld::UniversalId::Type_Faction; + types[CSMWorld::ColumnBase::Display_GlobalVariable ] = CSMWorld::UniversalId::Type_Global; + types[CSMWorld::ColumnBase::Display_Icon ] = CSMWorld::UniversalId::Type_Icon; + types[CSMWorld::ColumnBase::Display_Mesh ] = CSMWorld::UniversalId::Type_Mesh; + types[CSMWorld::ColumnBase::Display_Miscellaneous ] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::ColumnBase::Display_Npc ] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::ColumnBase::Display_Race ] = CSMWorld::UniversalId::Type_Race; + types[CSMWorld::ColumnBase::Display_Region ] = CSMWorld::UniversalId::Type_Region; + types[CSMWorld::ColumnBase::Display_Referenceable ] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::ColumnBase::Display_Script ] = CSMWorld::UniversalId::Type_Script; + types[CSMWorld::ColumnBase::Display_Skill ] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::ColumnBase::Display_Sound ] = CSMWorld::UniversalId::Type_Sound; + types[CSMWorld::ColumnBase::Display_SoundRes ] = CSMWorld::UniversalId::Type_SoundRes; + types[CSMWorld::ColumnBase::Display_Spell ] = CSMWorld::UniversalId::Type_Spell; + types[CSMWorld::ColumnBase::Display_Static ] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::ColumnBase::Display_Texture ] = CSMWorld::UniversalId::Type_Texture; + types[CSMWorld::ColumnBase::Display_Weapon ] = CSMWorld::UniversalId::Type_Referenceable; return types; } + + typedef std::map::const_iterator ModelTypeConstIterator; } -const std::map +const std::map CSMWorld::IdCompletionManager::sCompleterModelTypes = generateModelTypes(); +std::vector CSMWorld::IdCompletionManager::getDisplayTypes() +{ + std::vector types; + ModelTypeConstIterator current = sCompleterModelTypes.begin(); + ModelTypeConstIterator end = sCompleterModelTypes.end(); + for (; current != end; ++current) + { + types.push_back(current->first); + } + return types; +} + CSMWorld::IdCompletionManager::IdCompletionManager(CSMWorld::Data &data) { generateCompleters(data); } -bool CSMWorld::IdCompletionManager::hasCompleterFor(CSMWorld::Columns::ColumnId id) const +bool CSMWorld::IdCompletionManager::hasCompleterFor(CSMWorld::ColumnBase::Display display) const { - return mCompleters.find(id) != mCompleters.end(); + return mCompleters.find(display) != mCompleters.end(); } -boost::shared_ptr CSMWorld::IdCompletionManager::getCompleter(CSMWorld::Columns::ColumnId id) +boost::shared_ptr CSMWorld::IdCompletionManager::getCompleter(CSMWorld::ColumnBase::Display display) { - if (!hasCompleterFor(id)) + if (!hasCompleterFor(display)) { throw std::logic_error("This column doesn't have an ID completer"); } - return mCompleters[id]; + return mCompleters[display]; } void CSMWorld::IdCompletionManager::generateCompleters(CSMWorld::Data &data) { - typedef std::map::const_iterator ModelTypeConstIterator; - ModelTypeConstIterator current = sCompleterModelTypes.begin(); ModelTypeConstIterator end = sCompleterModelTypes.end(); for (; current != end; ++current) diff --git a/apps/opencs/model/world/idcompletionmanager.hpp b/apps/opencs/model/world/idcompletionmanager.hpp index ee75ddf24..7944e6777 100644 --- a/apps/opencs/model/world/idcompletionmanager.hpp +++ b/apps/opencs/model/world/idcompletionmanager.hpp @@ -1,11 +1,12 @@ #ifndef CSM_WORLD_IDCOMPLETIONMANAGER_HPP #define CSM_WORLD_IDCOMPLETIONMANAGER_HPP +#include #include #include -#include "columns.hpp" +#include "columnbase.hpp" #include "universalid.hpp" class QCompleter; @@ -17,21 +18,23 @@ namespace CSMWorld /// \brief Creates and stores all ID completers class IdCompletionManager { - static const std::map sCompleterModelTypes; + static const std::map sCompleterModelTypes; - std::map > mCompleters; + std::map > mCompleters; // Don't allow copying IdCompletionManager(const IdCompletionManager &); IdCompletionManager &operator = (const IdCompletionManager &); - void generateCompleters(CSMWorld::Data &data); + void generateCompleters(Data &data); public: - IdCompletionManager(CSMWorld::Data &data); + static std::vector getDisplayTypes(); - bool hasCompleterFor(CSMWorld::Columns::ColumnId id) const; - boost::shared_ptr getCompleter(CSMWorld::Columns::ColumnId id); + IdCompletionManager(Data &data); + + bool hasCompleterFor(ColumnBase::Display display) const; + boost::shared_ptr getCompleter(ColumnBase::Display display); }; } diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index f48513703..b2f681df1 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -1,6 +1,7 @@ #include "viewmanager.hpp" +#include #include #include @@ -10,6 +11,7 @@ #include "../../model/doc/document.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/universalid.hpp" +#include "../../model/world/idcompletionmanager.hpp" #include "../world/util.hpp" #include "../world/enumdelegate.hpp" @@ -61,38 +63,12 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) mDelegateFactories->add (CSMWorld::ColumnBase::Display_RefRecordType, new CSVWorld::IdTypeDelegateFactory()); - // Columns with QLineEdit editor - static const CSMWorld::ColumnBase::Display sIdCompletionColumns[] = + std::vector idCompletionColumns = CSMWorld::IdCompletionManager::getDisplayTypes(); + for (std::vector::const_iterator current = idCompletionColumns.begin(); + current != idCompletionColumns.end(); + ++current) { - CSMWorld::ColumnBase::Display_Cell, - CSMWorld::ColumnBase::Display_Class, - CSMWorld::ColumnBase::Display_Creature, - CSMWorld::ColumnBase::Display_Faction, - CSMWorld::ColumnBase::Display_String, - CSMWorld::ColumnBase::Display_GlobalVariable, - CSMWorld::ColumnBase::Display_Icon, - CSMWorld::ColumnBase::Display_Mesh, - CSMWorld::ColumnBase::Display_Miscellaneous, - CSMWorld::ColumnBase::Display_Music, - CSMWorld::ColumnBase::Display_None, // Inplace editing (Table SubView) creates QLineEdit using Display_None - CSMWorld::ColumnBase::Display_Npc, - CSMWorld::ColumnBase::Display_Race, - CSMWorld::ColumnBase::Display_Referenceable, - CSMWorld::ColumnBase::Display_Region, - CSMWorld::ColumnBase::Display_Script, - CSMWorld::ColumnBase::Display_Skill, - CSMWorld::ColumnBase::Display_Sound, - CSMWorld::ColumnBase::Display_SoundRes, - CSMWorld::ColumnBase::Display_Static, - CSMWorld::ColumnBase::Display_String, - CSMWorld::ColumnBase::Display_Texture, - CSMWorld::ColumnBase::Display_Video, - CSMWorld::ColumnBase::Display_Weapon - }; - - for (std::size_t i = 0; i < sizeof(sIdCompletionColumns) / sizeof(CSMWorld::ColumnBase::Display); ++i) - { - mDelegateFactories->add(sIdCompletionColumns[i], new CSVWorld::IdCompletionDelegateFactory()); + mDelegateFactories->add(*current, new CSVWorld::IdCompletionDelegateFactory()); } struct Mapping diff --git a/apps/opencs/view/world/idcompletiondelegate.cpp b/apps/opencs/view/world/idcompletiondelegate.cpp index 2a1e97f4b..056026471 100644 --- a/apps/opencs/view/world/idcompletiondelegate.cpp +++ b/apps/opencs/view/world/idcompletiondelegate.cpp @@ -12,7 +12,7 @@ QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { - return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_None); + return createEditor(parent, option, index, getDisplayTypeFromIndex(index)); } QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent, @@ -20,16 +20,14 @@ QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent, const QModelIndex &index, CSMWorld::ColumnBase::Display display) const { - int columnIdData = index.data(CSMWorld::ColumnBase::Role_ColumnId).toInt(); - CSMWorld::Columns::ColumnId columnId = static_cast(columnIdData); - CSMWorld::IdCompletionManager &completionManager = getDocument().getIdCompletionManager(); - - QWidget *editor = CSVWorld::CommandDelegate::createEditor(parent, option, index, display); - QLineEdit *lineEditor = qobject_cast(editor); - if (lineEditor != NULL && completionManager.hasCompleterFor(columnId)) + if (!index.data(Qt::EditRole).isValid() && !index.data(Qt::DisplayRole).isValid()) { - lineEditor->setCompleter(completionManager.getCompleter(columnId).get()); + return NULL; } + + CSMWorld::IdCompletionManager &completionManager = getDocument().getIdCompletionManager(); + DropLineEdit *editor = new DropLineEdit(parent); + editor->setCompleter(completionManager.getCompleter(display).get()); return editor; } From bd46ddcf47c3a50943a14ea2772dac9e8ef247f8 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 3 Jun 2015 15:51:34 +0300 Subject: [PATCH 384/450] Correct the return type in IdTree::data() for Display_Role --- apps/opencs/model/world/idtree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index a3dbae465..1e81d6ac2 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -41,7 +41,7 @@ QVariant CSMWorld::IdTree::data (const QModelIndex & index, int role) const const NestableColumn *parentColumn = mNestedCollection->getNestableColumn(parentAddress.second); if (role == ColumnBase::Role_Display) - return parentColumn->nestedColumn(index.column()).mColumnId; + return parentColumn->nestedColumn(index.column()).mDisplayType; if (role == ColumnBase::Role_ColumnId) return parentColumn->nestedColumn(index.column()).mColumnId; From 24551c7bab5cc818f258af5e366ff8da03b56481 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 14:56:57 +0200 Subject: [PATCH 385/450] 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 16957a585..77138a124 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 386/450] 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 f258eb300..bb48afc9d 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 6205c3ad8..7af21a5a6 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 c22d3c7bf..4452ae9f8 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 d403590dd..ce4d8f958 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 37f38f8df..59dc919d1 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 7528e9286..7bc46c078 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 4c4df2c99..20d6bf9a1 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 387/450] 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 fed1f134b..a37d84621 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 8b792c5a8..8ac6098b8 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 a9209bf58..f607b7046 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 388/450] 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 5f2ca19ef..50cfd9d57 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 389/450] 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 7635c43da..131336683 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 bf1d66fe8..e00b0221d 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 390/450] 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 6fec6f194..7c539fb14 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 407933ec6..2dc3c02b6 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 8743cc438..dae2a8fa3 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 705759104..000000000 --- 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 ead8f3e13..000000000 --- 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 5d9a03468..000000000 --- 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 d1e09d236..000000000 --- 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 950e137a7..000000000 --- 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 e30722f75..000000000 --- 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 c5f3eda96..000000000 --- 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 7796eb9e7..000000000 --- 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 58a7d8552..73f7dc810 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 a9c9a8c6b..6136abb40 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 acfc0bbd4..58c376418 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 e935daae2..fe4555820 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 391/450] Fix for recent merge --- cmake/FindMyGUI.cmake | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index e883a29c1..eccfb54ed 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 392/450] 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 901d9ad42..dc58daed9 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 d94238ad6..b2634d8c7 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 393/450] 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 bb48afc9d..95553de76 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 ea67884d3..c88691515 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 f5a2402f3..93ef3959c 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 4307fe9be..c9de1f6ff 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 f72a9bb2c..b786286f7 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 0fab66a25..44f944c3b 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 ba6fc2a78..7985e7eda 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 1182de151..1ae5cabed 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 81dbca58a..03ab3d020 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 83f9dffb4..9d32aa97b 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 36ff927d8..495aaf82b 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 ddfc14581..24a50cbd6 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 52a975320..8db62dea8 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 bb078f883..0606e5146 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 2824e2c6c..f9fddf575 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 6593bbf89..71508ac51 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 7f8fc5088..b4eb3d21c 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 3843df132..f17f2331f 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 5795f818a..d338cf01a 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 0f4d42775..8386de70f 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 9f887f5ca..219a23655 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 91df49f0d..4b29dc1d9 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 5999979de..b757b1c91 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 02afd8960..935718348 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 09f6de072..a612ff80b 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 25d8981cd..8d29163e6 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 7bc46c078..a5f15da8e 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 20d6bf9a1..c70a102c3 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 394/450] 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 a5f15da8e..1ac92cf16 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 395/450] 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 f17f2331f..c5282bdf8 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 a9a78d035..90fd300ec 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 396/450] 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 91d290f33..ec396761c 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; + } + } + + 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; } - Ogre::DataStreamPtr encoded = image2.encode("png"); - mContext->mGlobalMapState.mImageData.resize(encoded->size()); - encoded->read(&mContext->mGlobalMapState.mImageData[0], encoded->size()); + 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 5711e6754..f00b25438 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 d5ed43b8a..3959a8f5c 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 397/450] 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 c5282bdf8..b0db1dfa0 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 8fbb31fb7..b89b8c94a 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 7cfa6fcd5..ae2cbcafe 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 8386de70f..ce0b54192 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 4140fd3c0..768afc35a 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 1f05d93b6..71c48a489 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 db0b4ea0c..23b663565 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 9336afd4c..226d59c53 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 8580eb8f8..e706140fb 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 6ede67932..093506113 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 fccd176a8..cd6698c98 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 1a9ae3494..78d093104 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 1ac92cf16..9a42d4587 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 c70a102c3..bbc04ffdc 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 07a7655c7..3ab2ef049 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 398/450] 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 487d07aa5..8dbad2924 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 ec396761c..2ef10ee34 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 f00b25438..fb8fb8c9f 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 3959a8f5c..65f318297 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 7c539fb14..4ade2df44 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 b23828254..8e17f2f31 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 44f944c3b..56a4b0807 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 d748bef6c..34a9db1e1 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 8ba46339a..a50c30507 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 7985e7eda..6ea6301ad 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 f9e58ab4f..4baaea28d 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 9d32aa97b..29bf19942 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 495aaf82b..f31e0ff77 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 307df3872..e5454dc05 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 24a50cbd6..524a7f904 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 8db62dea8..b5d62ee31 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 f9fddf575..6da5614d2 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 71508ac51..51b169eba 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 b4eb3d21c..4b83179d5 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 b0db1dfa0..d4ba561ed 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 2b2131061..797c2e623 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 0a31a1a7e..9412f62e7 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 f695ec57a..5cc2ce254 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 d6f5da88d..4949d9b12 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 ae2cbcafe..3d2ab7d3d 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 d338cf01a..584bf84a0 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 ce0b54192..4867c4c21 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 4241c9e3e..2540b87db 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 768afc35a..541026ee1 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 7e3c27951..8cb31ed25 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 43d213c5a..8af2e5ef3 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 80f46e457..61a31e115 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 093506113..0f9faa11a 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 bdc8cf459..96f59cea0 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 b757b1c91..f6170da7f 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 935718348..87325144a 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 8d29163e6..2327b4dd5 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 54860fc31..c4f63137a 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 78d093104..62bc1f47e 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 af0b82fc3..ca6ed83b9 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 77d961057..d7dfee99b 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 bbc04ffdc..6b09fbb65 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 eccfb54ed..320765b53 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 f2acf9d33..000000000 --- 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 7b0094b3f..5a4ec605b 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 3ab2ef049..a80df2456 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 399/450] 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 9bd4a2df3..9ec815130 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 4a4f2fc6b..72a2aab18 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 400/450] 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 1b02e13be..8a9cce1b7 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 401/450] 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 27cb71463..5823825ae 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 402/450] Minor cleanup --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8dbad2924..9f47b5fae 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 403/450] 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 b886257e7..79f9edb1c 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 404/450] 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 978f0f5fb..ffeef94e1 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 405/450] 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 50f83aaa2..cf577aec5 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 406/450] 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 1fc85dca3..7b5155137 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 407/450] 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 8ee3ea36b..d33c6f33b 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 4bd348c46..000000000 --- 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 4641b55a3..000000000 --- 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 22d5b5441..000000000 --- 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 3b21a17d6..000000000 --- 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 68fe043f3..000000000 --- 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 408/450] 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 7ae4d8511..322c15196 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 409/450] 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 bcf9e74bf..9109be799 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 77138a124..6ce54a4ba 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 410/450] 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 7b5155137..d2b2ad079 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 5823825ae..2408a5822 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 411/450] 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 131336683..b66fbbb20 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 412/450] 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 5b01edb16..c742d1c90 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 413/450] 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 8e17f2f31..19889ad13 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 414/450] 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 581f45d07..19f0ecf99 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 415/450] 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 1785575fc..139862a5a 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 aec503e87..086b5ef2f 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 416/450] 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 6863994b8..44a988523 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 8ad4f6830..881b9997c 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 4433f9ef8..4b3bab5d0 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 dc460e2fc..d37f0c4e4 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 83650b195..e4312914f 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 7ff16b10a..14caa7748 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 1317e1e25..ecf4ddcf0 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 87ae993a5..520bce9d9 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 c6f2180c9..03cf1cab6 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 a54e99cf4..7014b5fad 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 b96e79ca9..e3d87de60 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 aade232d2..7391bb8fb 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 9aeba6752..6c2dea339 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 dbc513049..e24894e89 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 34a9db1e1..3e855c4d0 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 ab8d93a87..d490d49cd 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 85d1c8c4e..01ce7767e 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 3c9e718b6..961f1b675 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 a50c30507..af081391c 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 6d86b4a23..cb7bfc4a6 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 7af1bda7a..d40277282 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 ca5ec20bd..d2ea67ea9 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 e6a2555b6..581533060 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 1ae5cabed..298d4812e 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 df7e7d61d..c5a459f22 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 aed69da79..cc7b75c2f 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 417/450] 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 e3d87de60..3ecfc64b2 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 fc579ae62..a8a1b15a1 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 6e81ed626..c647ecaf5 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 59d1a0b06..b4121fed3 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 34a397f9a..80877e08b 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 bd864c936..419ae6bc0 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 71c48a489..6831daa4b 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 23b663565..3eb4c4754 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 418/450] 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 b7d09777d..dc5cd2299 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 d31a9ceaa..2daca16f7 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 419/450] 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 8a9cce1b7..f143088e8 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 72a2aab18..247e04ec4 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 420/450] 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 f31e0ff77..9d92423e9 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 c40987338d93c6121997630f539ba7e9138540a3 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 4 Jun 2015 23:09:40 +0300 Subject: [PATCH 421/450] Scrollbars don't save their positions between openings --- apps/openmw/mwgui/alchemywindow.cpp | 1 + apps/openmw/mwgui/companionwindow.cpp | 1 + apps/openmw/mwgui/container.cpp | 1 + apps/openmw/mwgui/itemselection.cpp | 1 + apps/openmw/mwgui/itemview.cpp | 5 +++++ apps/openmw/mwgui/itemview.hpp | 2 ++ apps/openmw/mwgui/merchantrepair.cpp | 2 ++ apps/openmw/mwgui/quickkeysmenu.cpp | 1 + apps/openmw/mwgui/recharge.cpp | 2 ++ apps/openmw/mwgui/repair.cpp | 2 ++ apps/openmw/mwgui/settingswindow.cpp | 17 +++++++++++++++++ apps/openmw/mwgui/settingswindow.hpp | 5 +++++ apps/openmw/mwgui/spellcreationdialog.cpp | 1 + apps/openmw/mwgui/spellview.cpp | 4 ++++ apps/openmw/mwgui/spellview.hpp | 2 ++ apps/openmw/mwgui/tradewindow.cpp | 1 + 16 files changed, 48 insertions(+) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index a54744370..768ad82e4 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -130,6 +130,7 @@ namespace MWGui mSortModel = new SortFilterItemModel(model); mSortModel->setFilter(SortFilterItemModel::Filter_OnlyIngredients); mItemView->setModel (mSortModel); + mItemView->resetScrollBars(); mNameEdit->setCaption(""); diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 4433f9ef8..69b6aa9f9 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -114,6 +114,7 @@ void CompanionWindow::open(const MWWorld::Ptr& npc) mModel = new CompanionItemModel(npc); mSortModel = new SortFilterItemModel(mModel); mItemView->setModel(mSortModel); + mItemView->resetScrollBars(); setTitle(npc.getClass().getName(npc)); } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 1317e1e25..76e9cbb5b 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -151,6 +151,7 @@ namespace MWGui mSortModel = new SortFilterItemModel(mModel); mItemView->setModel (mSortModel); + mItemView->resetScrollBars(); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton); diff --git a/apps/openmw/mwgui/itemselection.cpp b/apps/openmw/mwgui/itemselection.cpp index 916f13360..095f392b7 100644 --- a/apps/openmw/mwgui/itemselection.cpp +++ b/apps/openmw/mwgui/itemselection.cpp @@ -39,6 +39,7 @@ namespace MWGui mModel = new InventoryItemModel(container); mSortModel = new SortFilterItemModel(mModel); mItemView->setModel(mSortModel); + mItemView->resetScrollBars(); } void ItemSelectionDialog::setCategory(int category) diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index aade232d2..c5320a2be 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -128,6 +128,11 @@ void ItemView::update() layoutWidgets(); } +void ItemView::resetScrollBars() +{ + mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); +} + void ItemView::onSelectedItem(MyGUI::Widget *sender) { ItemModel::ModelIndex index = (*sender->getUserData >()).first; diff --git a/apps/openmw/mwgui/itemview.hpp b/apps/openmw/mwgui/itemview.hpp index 9aeba6752..f87a48aa6 100644 --- a/apps/openmw/mwgui/itemview.hpp +++ b/apps/openmw/mwgui/itemview.hpp @@ -30,6 +30,8 @@ namespace MWGui void update(); + void resetScrollBars(); + private: virtual void initialiseOverride(); diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 4407bf927..862b719d4 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -114,6 +114,8 @@ void MerchantRepair::onMouseWheel(MyGUI::Widget* _sender, int _rel) void MerchantRepair::open() { center(); + // Reset scrollbars + mList->setViewOffset(MyGUI::IntPoint(0, 0)); } void MerchantRepair::exit() diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 834c156f9..685c7d45c 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -548,6 +548,7 @@ namespace MWGui WindowModal::open(); mMagicList->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); + mMagicList->resetScrollbars(); } void MagicSelectionDialog::onModelIndexSelected(SpellModel::ModelIndex index) diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index a0e5991b4..b7280565b 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -44,6 +44,8 @@ Recharge::Recharge() void Recharge::open() { center(); + // Reset scrollbars + mView->setViewOffset(MyGUI::IntPoint(0, 0)); } void Recharge::exit() diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 9f26923d4..534226aeb 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -36,6 +36,8 @@ Repair::Repair() void Repair::open() { center(); + // Reset scrollbars + mRepairView->setViewOffset(MyGUI::IntPoint(0, 0)); } void Repair::exit() diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index d895a28ea..6991bb294 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -170,6 +171,7 @@ namespace MWGui setTitle("#{sOptions}"); + getWidget(mSettingsTab, "SettingsTab"); getWidget(mOkButton, "OkButton"); getWidget(mResolutionList, "ResolutionList"); getWidget(mFullscreenButton, "FullscreenButton"); @@ -208,6 +210,7 @@ namespace MWGui mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &SettingsWindow::onWindowResize); + mSettingsTab->eventTabChangeSelect += MyGUI::newDelegate(this, &SettingsWindow::onTabChanged); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); mShaderModeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShaderModeToggled); mTextureFilteringButton->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onTextureFilteringChanged); @@ -275,6 +278,11 @@ namespace MWGui mControllerSwitch->setStateSelected(false); } + void SettingsWindow::onTabChanged(MyGUI::TabControl* /*_sender*/, size_t /*index*/) + { + resetScrollbars(); + } + void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) { exit(); @@ -480,6 +488,7 @@ namespace MWGui mKeyboardSwitch->setStateSelected(true); mControllerSwitch->setStateSelected(false); updateControlsBox(); + resetScrollbars(); } void SettingsWindow::onControllerSwitchClicked(MyGUI::Widget* _sender) @@ -490,6 +499,7 @@ namespace MWGui mKeyboardSwitch->setStateSelected(false); mControllerSwitch->setStateSelected(true); updateControlsBox(); + resetScrollbars(); } void SettingsWindow::updateControlsBox() @@ -584,6 +594,7 @@ namespace MWGui void SettingsWindow::open() { updateControlsBox (); + resetScrollbars(); } void SettingsWindow::exit() @@ -595,4 +606,10 @@ namespace MWGui { updateControlsBox(); } + + void SettingsWindow::resetScrollbars() + { + mResolutionList->setScrollPosition(0); + mControlsBox->setViewOffset(MyGUI::IntPoint(0, 0)); + } } diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 1b970b8de..8910960b2 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -22,6 +22,7 @@ namespace MWGui void updateControlsBox(); protected: + MyGUI::TabControl* mSettingsTab; MyGUI::Button* mOkButton; // graphics @@ -50,6 +51,7 @@ namespace MWGui MyGUI::Button* mControllerSwitch; bool mKeyboardMode; //if true, setting up the keyboard. Otherwise, it's controller + 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); @@ -74,6 +76,9 @@ namespace MWGui void apply(); void configureWidgets(MyGUI::Widget* widget); + + private: + void resetScrollbars(); }; } diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 1c670838f..a492ea7aa 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -551,6 +551,7 @@ namespace MWGui ++i; } mAvailableEffectsList->adjustSize (); + mAvailableEffectsList->scrollToTop(); for (std::vector::const_iterator it = knownEffects.begin(); it != knownEffects.end(); ++it) { diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 6d86b4a23..af6ff00a5 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -311,4 +311,8 @@ namespace MWGui mScrollView->setViewOffset(MyGUI::IntPoint(0, static_cast(mScrollView->getViewOffset().top + _rel*0.3f))); } + void SpellView::resetScrollbars() + { + mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); + } } diff --git a/apps/openmw/mwgui/spellview.hpp b/apps/openmw/mwgui/spellview.hpp index 7af1bda7a..0f0b8a7d2 100644 --- a/apps/openmw/mwgui/spellview.hpp +++ b/apps/openmw/mwgui/spellview.hpp @@ -51,6 +51,8 @@ namespace MWGui virtual void setSize(const MyGUI::IntSize& _value); virtual void setCoord(const MyGUI::IntCoord& _value); + void resetScrollbars(); + private: MyGUI::ScrollView* mScrollView; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index aecfce98d..bdcf28bf2 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -136,6 +136,7 @@ namespace MWGui mTradeModel = new TradeItemModel(new ContainerItemModel(itemSources, worldItems), mPtr); mSortModel = new SortFilterItemModel(mTradeModel); mItemView->setModel (mSortModel); + mItemView->resetScrollBars(); updateLabels(); From d8d43f94b94d023c441ac84ad2e0d77924bef9da Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Jun 2015 02:06:13 +0200 Subject: [PATCH 422/450] 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 bf1dbe6b5..54f067e98 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 423/450] 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 7af21a5a6..d1811ed67 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 4452ae9f8..8ed590df4 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 9a42d4587..9179f94f6 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 424/450] 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 f9ea63efe..2d84d9f26 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 425/450] 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 2d84d9f26..0afda6ac7 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 426/450] 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 a37d84621..f23e414ab 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 427/450] 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 f23e414ab..eda33637b 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 428/450] 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 f97c5fd13..c7df22aef 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 429/450] 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 d4ba561ed..ea6b39481 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 b89b8c94a..7bc6a34ae 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 9179f94f6..a2e66a96f 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 5c37079f0c06d1837da2b3d6e3f3763d709550dc Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 5 Jun 2015 12:19:21 +1000 Subject: [PATCH 430/450] Include only the columns that are visible for sorting. Should resolve Bug #2611. --- apps/opencs/model/world/idtableproxymodel.cpp | 12 ++++++++++++ apps/opencs/model/world/idtableproxymodel.hpp | 6 ++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 987d27462..3697b055f 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -21,6 +21,18 @@ void CSMWorld::IdTableProxyModel::updateColumnMap() } } +bool CSMWorld::IdTableProxyModel::filterAcceptsColumn (int sourceColumn, const QModelIndex& sourceParent) + const +{ + int flags = + sourceModel()->headerData (sourceColumn, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); + + if (flags & CSMWorld::ColumnBase::Flag_Table) + return true; + else + return false; +} + bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const { diff --git a/apps/opencs/model/world/idtableproxymodel.hpp b/apps/opencs/model/world/idtableproxymodel.hpp index 8683c2b9e..89480f288 100644 --- a/apps/opencs/model/world/idtableproxymodel.hpp +++ b/apps/opencs/model/world/idtableproxymodel.hpp @@ -24,8 +24,6 @@ namespace CSMWorld void updateColumnMap(); - bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const; - public: IdTableProxyModel (QObject *parent = 0); @@ -39,6 +37,10 @@ namespace CSMWorld protected: bool lessThan(const QModelIndex &left, const QModelIndex &right) const; + + virtual bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const; + + virtual bool filterAcceptsColumn (int sourceColumn, const QModelIndex& sourceParent) const; }; } From 0afc03b6b74e4df7b348260ae13bcd9d292db06e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Jun 2015 16:56:38 +0200 Subject: [PATCH 431/450] 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 0795a3ffc..1811f58e6 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 15fe5d88e2b3c7d172a28bd453b3e0d5f89295aa Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 6 Jun 2015 20:35:55 +1000 Subject: [PATCH 432/450] Allow comments (lines starting with # character) and blank lines in openmw.cfg. Should resolve Feature #2535. - controlled via a checkbox in launcher settings --- apps/launcher/maindialog.cpp | 21 ++++- apps/launcher/settingspage.cpp | 8 ++ components/config/gamesettings.cpp | 128 +++++++++++++++++++++++++++++ components/config/gamesettings.hpp | 2 + files/ui/settingspage.ui | 10 +++ 5 files changed, 166 insertions(+), 3 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index fd36993bf..27d37dbf0 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -490,7 +490,16 @@ bool Launcher::MainDialog::writeSettings() // Game settings QFile file(userPath + QString("openmw.cfg")); - if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { + QIODevice::OpenMode mode(0); + bool keepComments = mLauncherSettings.value(QString("Settings/keep-comments"), QString("true")) + == QLatin1String("true"); + + if (keepComments) + mode = QIODevice::ReadWrite | QIODevice::Text; + else + mode = QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate; + + if (!file.open(mode)) { // File cannot be opened or created QMessageBox msgBox; msgBox.setWindowTitle(tr("Error writing OpenMW configuration file")); @@ -504,9 +513,15 @@ bool Launcher::MainDialog::writeSettings() } QTextStream stream(&file); - stream.setCodec(QTextCodec::codecForName("UTF-8")); - mGameSettings.writeFile(stream); + if (keepComments) + mGameSettings.writeFileWithComments(file); + else + { + stream.setCodec(QTextCodec::codecForName("UTF-8")); + mGameSettings.writeFile(stream); + } + file.close(); // Graphics settings diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index 843b51391..bc8ffe618 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -260,6 +260,10 @@ void Launcher::SettingsPage::saveSettings() } else { mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1252")); } + + QString keepComments(saveCommentsCheckBox->isChecked() ? "true" : "false"); + + mLauncherSettings.setValue(QLatin1String("Settings/keep-comments"), keepComments); } bool Launcher::SettingsPage::loadSettings() @@ -271,5 +275,9 @@ bool Launcher::SettingsPage::loadSettings() if (index != -1) languageComboBox->setCurrentIndex(index); + QString keepComments(mLauncherSettings.value(QLatin1String("Settings/keep-comments"))); + + saveCommentsCheckBox->setChecked(keepComments == "true"); + return true; } diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index 0481235c7..51c7883ad 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -1,6 +1,7 @@ #include "gamesettings.hpp" #include "launchersettings.hpp" +#include #include #include #include @@ -173,6 +174,133 @@ bool Config::GameSettings::writeFile(QTextStream &stream) return true; } +// Policy: +// +// - Always ignore a line beginning with '#' or empty lines +// +// - If a line in file exists with matching key and first part of value (before ',', +// '\n', etc) also matches, then replace the line with that of mUserSettings. +// - else remove line (maybe replace the line with '#' in front instead?) +// +// - If there is no corresponding line in file, add at the end +// +bool Config::GameSettings::writeFileWithComments(QFile &file) +{ + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + // slurp + std::vector fileCopy; + QString line = stream.readLine(); + while (!line.isNull()) + { + fileCopy.push_back(line); + line = stream.readLine(); + } + stream.seek(0); + + // empty file, no comments to keep + if (fileCopy.empty()) + return writeFile(stream); + + // Temp copy of settings to save, but with the keys appended with the first part of the value + // + // ATTENTION! + // + // A hack to avoid looping through each line, makes use of the fact that fallbacks values + // are comma separated. + QMap userSettingsCopy; + QRegExp settingRegex("^([^=]+)\\s*=\\s*([^,]+)(.*)$"); + QString settingLine; + QMap::const_iterator settingsIter = mUserSettings.begin(); + for (; settingsIter != mUserSettings.end(); ++settingsIter) + { + settingLine = settingsIter.key()+"="+settingsIter.value(); + if (settingRegex.indexIn(settingLine) != -1) + { + userSettingsCopy[settingRegex.cap(1)+"="+settingRegex.cap(2)] = + (settingRegex.captureCount() < 3) ? "" : settingRegex.cap(3); + } + } + + QString keyVal; + for (std::vector::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) + { + // skip empty or comment lines + if ((*iter).isEmpty() || (*iter).startsWith("#")) + continue; + + // look for a key in the line + if (settingRegex.indexIn(*iter) == -1 || settingRegex.captureCount() < 2) + { + // no key or first part of value found in line, replace with a null string which + // will be remved later + *iter = QString(); + continue; + } + + // look for a matching key in user settings + keyVal = settingRegex.cap(1)+"="+settingRegex.cap(2); + QMap::iterator it = userSettingsCopy.find(keyVal); + if (it == userSettingsCopy.end()) + { + // no such key+valStart, replace with a null string which will be remved later + *iter = QString(); + } + else + { + *iter = QString(it.key()+it.value()); + userSettingsCopy.erase(it); + } + } + + // write the new config file + QString key; + QString value; + for (std::vector::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) + { + if ((*iter).isNull()) + continue; + + if ((*iter).isEmpty() || (*iter).startsWith("#")) + stream << *iter << "\n"; + + if (settingRegex.indexIn(*iter) == -1 || settingRegex.captureCount() < 2) + continue; + + // Quote paths with spaces + key = settingRegex.cap(1); + value = settingRegex.cap(2)+settingRegex.cap(3); + if (key == QLatin1String("data") + || key == QLatin1String("data-local") + || key == QLatin1String("resources")) + { + if (value.contains(QChar(' '))) + { + value.remove(QChar('\"')); // Remove quotes + + stream << key << "=\"" << value << "\"\n"; + continue; + } + } + stream << key << "=" << value << "\n"; + } + + if (!userSettingsCopy.empty()) + { + stream << "# new entries" << "\n"; + QMap::const_iterator it = userSettingsCopy.begin(); + for (; it != userSettingsCopy.end(); ++it) + { + stream << it.key() << it.value() << "\n"; + } + } + + file.resize(file.pos()); + + return true; +} + bool Config::GameSettings::hasMaster() { bool result = false; diff --git a/components/config/gamesettings.hpp b/components/config/gamesettings.hpp index cc5033f35..35614113f 100644 --- a/components/config/gamesettings.hpp +++ b/components/config/gamesettings.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -66,6 +67,7 @@ namespace Config bool readUserFile(QTextStream &stream); bool writeFile(QTextStream &stream); + bool writeFileWithComments(QFile &file); void setContentList(const QStringList& fileNames); QStringList getContentList() const; diff --git a/files/ui/settingspage.ui b/files/ui/settingspage.ui index 7f5e4a7de..f38ba764c 100644 --- a/files/ui/settingspage.ui +++ b/files/ui/settingspage.ui @@ -40,6 +40,16 @@ + + + + Keep comments in openmw.cfg + + + false + + + From d63b01dde3ebe251d9dafd157ca1104bcf413db9 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 6 Jun 2015 15:41:25 +0300 Subject: [PATCH 433/450] Checkboxes in the table view use a combobox editor --- apps/opencs/view/world/util.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 3be875ffd..e1d165a24 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -152,7 +152,17 @@ void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemMode QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, const QModelIndex& index) const { - return createEditor (parent, option, index, getDisplayTypeFromIndex(index)); + 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. + // TODO: Find a better solution? + if (display == CSMWorld::ColumnBase::Display_Boolean) + { + return QStyledItemDelegate::createEditor(parent, option, index); + } + return createEditor (parent, option, index, display); } QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, From 4902c6679210dee8b5158d05d99b072c2f06a494 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 7 Jun 2015 07:21:15 +1000 Subject: [PATCH 434/450] Allow space characters in front of comments. --- components/config/gamesettings.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index 51c7883ad..1215f0850 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -180,7 +180,7 @@ bool Config::GameSettings::writeFile(QTextStream &stream) // // - If a line in file exists with matching key and first part of value (before ',', // '\n', etc) also matches, then replace the line with that of mUserSettings. -// - else remove line (maybe replace the line with '#' in front instead?) +// - else remove line (TODO: maybe replace the line with '#' in front instead?) // // - If there is no corresponding line in file, add at the end // @@ -224,10 +224,10 @@ bool Config::GameSettings::writeFileWithComments(QFile &file) } QString keyVal; - for (std::vector::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) + for (std::vector::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) { // skip empty or comment lines - if ((*iter).isEmpty() || (*iter).startsWith("#")) + if ((*iter).isEmpty() || (*iter).contains(QRegExp("^\\s*#"))) continue; // look for a key in the line @@ -257,12 +257,14 @@ bool Config::GameSettings::writeFileWithComments(QFile &file) // write the new config file QString key; QString value; - for (std::vector::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) + for (std::vector::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) { if ((*iter).isNull()) continue; - if ((*iter).isEmpty() || (*iter).startsWith("#")) + // Below is based on readFile() code, if that changes corresponding change may be + // required (for example duplicates may be inserted if the rules don't match) + if ((*iter).isEmpty() || (*iter).contains(QRegExp("^\\s*#"))) stream << *iter << "\n"; if (settingRegex.indexIn(*iter) == -1 || settingRegex.captureCount() < 2) From a439f49c4db32a340826ae9b77c940ca59e79e5f Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 7 Jun 2015 07:38:52 +1000 Subject: [PATCH 435/450] Fix loop where there was a potential for double entry. --- components/config/gamesettings.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index 1215f0850..2b3a8ba4b 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -265,7 +265,10 @@ bool Config::GameSettings::writeFileWithComments(QFile &file) // Below is based on readFile() code, if that changes corresponding change may be // required (for example duplicates may be inserted if the rules don't match) if ((*iter).isEmpty() || (*iter).contains(QRegExp("^\\s*#"))) + { stream << *iter << "\n"; + continue; + } if (settingRegex.indexIn(*iter) == -1 || settingRegex.captureCount() < 2) continue; From 68e322f969344f571a99a44b3ba99bf630363f46 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 01:47:19 +0200 Subject: [PATCH 436/450] 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 aeda3191d..b361e3f42 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 437/450] 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 80877e08b..6af8a49a4 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 1f089f0c4..530aa3dec 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 d3b7cf44d391ba9624f28070e68784352e6f514d Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 7 Jun 2015 13:29:45 +1000 Subject: [PATCH 438/450] Remove user preference setting option. --- apps/launcher/maindialog.cpp | 22 +++------------------- apps/launcher/settingspage.cpp | 8 -------- files/ui/settingspage.ui | 10 ---------- 3 files changed, 3 insertions(+), 37 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 27d37dbf0..2f7a9db33 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -490,16 +490,7 @@ bool Launcher::MainDialog::writeSettings() // Game settings QFile file(userPath + QString("openmw.cfg")); - QIODevice::OpenMode mode(0); - bool keepComments = mLauncherSettings.value(QString("Settings/keep-comments"), QString("true")) - == QLatin1String("true"); - - if (keepComments) - mode = QIODevice::ReadWrite | QIODevice::Text; - else - mode = QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate; - - if (!file.open(mode)) { + if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { // File cannot be opened or created QMessageBox msgBox; msgBox.setWindowTitle(tr("Error writing OpenMW configuration file")); @@ -512,16 +503,8 @@ bool Launcher::MainDialog::writeSettings() return false; } - QTextStream stream(&file); - - if (keepComments) - mGameSettings.writeFileWithComments(file); - else - { - stream.setCodec(QTextCodec::codecForName("UTF-8")); - mGameSettings.writeFile(stream); - } + mGameSettings.writeFileWithComments(file); file.close(); // Graphics settings @@ -540,6 +523,7 @@ bool Launcher::MainDialog::writeSettings() return false; } + QTextStream stream(&file); stream.setDevice(&file); stream.setCodec(QTextCodec::codecForName("UTF-8")); diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index bc8ffe618..843b51391 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -260,10 +260,6 @@ void Launcher::SettingsPage::saveSettings() } else { mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1252")); } - - QString keepComments(saveCommentsCheckBox->isChecked() ? "true" : "false"); - - mLauncherSettings.setValue(QLatin1String("Settings/keep-comments"), keepComments); } bool Launcher::SettingsPage::loadSettings() @@ -275,9 +271,5 @@ bool Launcher::SettingsPage::loadSettings() if (index != -1) languageComboBox->setCurrentIndex(index); - QString keepComments(mLauncherSettings.value(QLatin1String("Settings/keep-comments"))); - - saveCommentsCheckBox->setChecked(keepComments == "true"); - return true; } diff --git a/files/ui/settingspage.ui b/files/ui/settingspage.ui index f38ba764c..7f5e4a7de 100644 --- a/files/ui/settingspage.ui +++ b/files/ui/settingspage.ui @@ -40,16 +40,6 @@ - - - - Keep comments in openmw.cfg - - - false - - - From b33fe8fb6242e6b0030340429ac122de883237b9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 16:50:34 +0200 Subject: [PATCH 439/450] 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 6831daa4b..7de3e1d5a 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 62d58f729..3fe86a511 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 6b906207e..a60d1f464 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 440/450] 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 c7df22aef..b7d02e159 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 8cb31ed25..c3b22c385 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 a2e66a96f..7b4c33fd8 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 441/450] 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 6af8a49a4..d92e57f19 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 442/450] 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 e00b0221d..ece667eb2 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 443/450] 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 c742d1c90..0cd1f64d2 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 652de28b4..d7cd88de5 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 444/450] 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 56a4b0807..76a7248ee 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 445/450] 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 f6a9f5ccd..774faa003 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 baacc7133..194535eee 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 446/450] 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 b8b452dc3..a2c1cdcd3 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 66e40f3e1..36aa683db 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 f16c0bca4..84aafa100 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 447/450] 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 530aa3dec..44784fd7e 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 448/450] 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 829e08978..6be6dca9e 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 449/450] Make install fix --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f47b5fae..77b054ff5 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 450/450] 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 ac304bdf3..92a849a0d 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 5e463aae3..c7d5d585d 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)