mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-21 06:53:53 +00:00
Merge remote-tracking branch 'upstream/master' into wizard
This commit is contained in:
commit
8fe837ae6e
168 changed files with 3592 additions and 1538 deletions
|
@ -7,7 +7,6 @@ branches:
|
||||||
- /openmw-.*$/
|
- /openmw-.*$/
|
||||||
before_install:
|
before_install:
|
||||||
- pwd
|
- pwd
|
||||||
- git fetch --tags
|
|
||||||
- echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse"
|
- echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse"
|
||||||
- echo "yes" | sudo apt-add-repository ppa:openmw/openmw
|
- echo "yes" | sudo apt-add-repository ppa:openmw/openmw
|
||||||
- sudo apt-get update -qq
|
- sudo apt-get update -qq
|
||||||
|
|
|
@ -6,34 +6,63 @@ if (APPLE)
|
||||||
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}")
|
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}")
|
||||||
endif (APPLE)
|
endif (APPLE)
|
||||||
|
|
||||||
# Macros
|
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
|
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
|
||||||
|
|
||||||
include(OpenMWMacros)
|
|
||||||
|
|
||||||
# Version
|
# Version
|
||||||
|
message(STATUS "Configuring OpenMW...")
|
||||||
|
|
||||||
|
set(OPENMW_VERSION_MAJOR 0)
|
||||||
|
set(OPENMW_VERSION_MINOR 29)
|
||||||
|
set(OPENMW_VERSION_RELEASE 0)
|
||||||
|
|
||||||
|
set(OPENMW_VERSION_COMMITHASH "")
|
||||||
|
set(OPENMW_VERSION_TAGHASH "")
|
||||||
|
|
||||||
|
set(OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
|
||||||
|
|
||||||
|
if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||||
|
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
|
||||||
|
find_package(Git)
|
||||||
|
|
||||||
|
if(GIT_FOUND)
|
||||||
include(GetGitRevisionDescription)
|
include(GetGitRevisionDescription)
|
||||||
|
get_git_tag_revision(TAGHASH --tags --max-count=1)
|
||||||
get_git_tag_revision(TAGHASH --tags --max-count=1 "HEAD...")
|
|
||||||
get_git_head_revision(REFSPEC COMMITHASH)
|
get_git_head_revision(REFSPEC COMMITHASH)
|
||||||
git_describe(VERSION --tags ${TAGHASH})
|
git_describe(VERSION --tags ${TAGHASH})
|
||||||
|
|
||||||
string(REGEX MATCH "^openmw-[^0-9]*[0-9]+\\.[0-9]+\\.[0-9]+.*" MATCH "${VERSION}")
|
string(REGEX MATCH "^openmw-[^0-9]*[0-9]+\\.[0-9]+\\.[0-9]+.*" MATCH "${VERSION}")
|
||||||
if(MATCH)
|
if(MATCH)
|
||||||
string(REGEX REPLACE "^openmw-([0-9]+)\\..*" "\\1" OPENMW_VERSION_MAJOR "${VERSION}")
|
string(REGEX REPLACE "^openmw-([0-9]+)\\..*" "\\1" GIT_VERSION_MAJOR "${VERSION}")
|
||||||
string(REGEX REPLACE "^openmw-[0-9]+\\.([0-9]+).*" "\\1" OPENMW_VERSION_MINOR "${VERSION}")
|
string(REGEX REPLACE "^openmw-[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_MINOR "${VERSION}")
|
||||||
string(REGEX REPLACE "^openmw-[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" OPENMW_VERSION_RELEASE "${VERSION}")
|
string(REGEX REPLACE "^openmw-[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_RELEASE "${VERSION}")
|
||||||
|
|
||||||
|
set(GIT_VERSION "${GIT_VERSION_MAJOR}.${GIT_VERSION_MINOR}.${GIT_VERSION_RELEASE}")
|
||||||
|
|
||||||
|
if(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION})
|
||||||
|
message(FATAL_ERROR "Silly Zini forgot to update the version again...")
|
||||||
|
else(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION})
|
||||||
|
set(OPENMW_VERSION_MAJOR ${GIT_VERSION_MAJOR})
|
||||||
|
set(OPENMW_VERSION_MINOR ${GIT_VERSION_MINOR})
|
||||||
|
set(OPENMW_VERSION_RELEASE ${GIT_VERSION_RELEASE})
|
||||||
|
|
||||||
set(OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
|
|
||||||
set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}")
|
set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}")
|
||||||
set(OPENMW_VERSION_TAGHASH "${TAGHASH}")
|
set(OPENMW_VERSION_TAGHASH "${TAGHASH}")
|
||||||
|
endif(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION})
|
||||||
|
|
||||||
message(STATUS "Configuring OpenMW ${OPENMW_VERSION}...")
|
message(STATUS "OpenMW version ${OPENMW_VERSION}")
|
||||||
else(MATCH)
|
else(MATCH)
|
||||||
message(FATAL_ERROR "Failed to get valid version information from Git")
|
message(WARNING "Failed to get valid version information from Git")
|
||||||
endif(MATCH)
|
endif(MATCH)
|
||||||
|
else(GIT_FOUND)
|
||||||
|
message(WARNING "Git executable not found")
|
||||||
|
endif(GIT_FOUND)
|
||||||
|
else(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
|
||||||
|
message(STATUS "Shallow Git clone detected, not attempting to retrieve version info")
|
||||||
|
endif(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
|
||||||
|
endif(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||||
|
|
||||||
|
# Macros
|
||||||
|
include(OpenMWMacros)
|
||||||
|
|
||||||
# doxygen main page
|
# doxygen main page
|
||||||
|
|
||||||
|
@ -210,6 +239,14 @@ if (UNIX AND NOT APPLE)
|
||||||
find_package (Threads)
|
find_package (Threads)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Look for stdint.h
|
||||||
|
include(CheckIncludeFile)
|
||||||
|
check_include_file(stdint.h HAVE_STDINT_H)
|
||||||
|
if(NOT HAVE_STDINT_H)
|
||||||
|
unset(HAVE_STDINT_H CACHE)
|
||||||
|
message(FATAL_ERROR "stdint.h was not found" )
|
||||||
|
endif()
|
||||||
|
|
||||||
include (CheckIncludeFileCXX)
|
include (CheckIncludeFileCXX)
|
||||||
check_include_file_cxx(unordered_map HAVE_UNORDERED_MAP)
|
check_include_file_cxx(unordered_map HAVE_UNORDERED_MAP)
|
||||||
if (HAVE_UNORDERED_MAP)
|
if (HAVE_UNORDERED_MAP)
|
||||||
|
|
|
@ -79,6 +79,8 @@ Launcher::MainDialog::MainDialog(QWidget *parent)
|
||||||
QString revision(OPENMW_VERSION_COMMITHASH);
|
QString revision(OPENMW_VERSION_COMMITHASH);
|
||||||
QString tag(OPENMW_VERSION_TAGHASH);
|
QString tag(OPENMW_VERSION_TAGHASH);
|
||||||
|
|
||||||
|
if (!revision.isEmpty() && !tag.isEmpty())
|
||||||
|
{
|
||||||
if (revision == tag) {
|
if (revision == tag) {
|
||||||
versionLabel->setText(tr("OpenMW %0 release").arg(OPENMW_VERSION));
|
versionLabel->setText(tr("OpenMW %0 release").arg(OPENMW_VERSION));
|
||||||
} else {
|
} else {
|
||||||
|
@ -90,6 +92,7 @@ Launcher::MainDialog::MainDialog(QWidget *parent)
|
||||||
QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate),
|
QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate),
|
||||||
QLocale(QLocale::C).toTime(QString(__TIME__).simplified(),
|
QLocale(QLocale::C).toTime(QString(__TIME__).simplified(),
|
||||||
QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate)));
|
QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate)));
|
||||||
|
}
|
||||||
|
|
||||||
createIcons();
|
createIcons();
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,11 @@ opencs_units (view/world
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units (view/render
|
opencs_units (view/render
|
||||||
scenewidget
|
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
|
||||||
|
)
|
||||||
|
|
||||||
|
opencs_units_noqt (view/render
|
||||||
|
navigation navigation1st navigationfree navigationorbit
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (view/world
|
opencs_units_noqt (view/world
|
||||||
|
|
|
@ -9,15 +9,22 @@
|
||||||
#include <OgreRoot.h>
|
#include <OgreRoot.h>
|
||||||
#include <OgreRenderWindow.h>
|
#include <OgreRenderWindow.h>
|
||||||
|
|
||||||
|
#include <components/ogreinit/ogreinit.hpp>
|
||||||
|
|
||||||
#include "model/doc/document.hpp"
|
#include "model/doc/document.hpp"
|
||||||
#include "model/world/data.hpp"
|
#include "model/world/data.hpp"
|
||||||
|
|
||||||
CS::Editor::Editor()
|
CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
|
||||||
: mDocumentManager (mCfgMgr), mViewManager (mDocumentManager)
|
: mDocumentManager (mCfgMgr), mViewManager (mDocumentManager),
|
||||||
|
mIpcServerName ("org.openmw.OpenCS")
|
||||||
{
|
{
|
||||||
mIpcServerName = "org.openmw.OpenCS";
|
Files::PathContainer dataDirs = readConfig();
|
||||||
|
|
||||||
setupDataFiles();
|
setupDataFiles (dataDirs);
|
||||||
|
|
||||||
|
CSMSettings::UserSettings::instance().loadSettings ("opencs.cfg");
|
||||||
|
|
||||||
|
ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string());
|
||||||
|
|
||||||
mNewGame.setLocalData (mLocal);
|
mNewGame.setLocalData (mLocal);
|
||||||
mFileDialog.setLocalData (mLocal);
|
mFileDialog.setLocalData (mLocal);
|
||||||
|
@ -42,7 +49,16 @@ CS::Editor::Editor()
|
||||||
this, SLOT (createNewGame (const boost::filesystem::path&)));
|
this, SLOT (createNewGame (const boost::filesystem::path&)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CS::Editor::setupDataFiles()
|
void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs)
|
||||||
|
{
|
||||||
|
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
|
||||||
|
{
|
||||||
|
QString path = QString::fromStdString(iter->string());
|
||||||
|
mFileDialog.addFiles(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Files::PathContainer CS::Editor::readConfig()
|
||||||
{
|
{
|
||||||
boost::program_options::variables_map variables;
|
boost::program_options::variables_map variables;
|
||||||
boost::program_options::options_description desc("Syntax: opencs <options>\nAllowed options");
|
boost::program_options::options_description desc("Syntax: opencs <options>\nAllowed options");
|
||||||
|
@ -58,6 +74,8 @@ void CS::Editor::setupDataFiles()
|
||||||
|
|
||||||
mCfgMgr.readConfiguration(variables, desc);
|
mCfgMgr.readConfiguration(variables, desc);
|
||||||
|
|
||||||
|
mDocumentManager.setResourceDir (variables["resources"].as<std::string>());
|
||||||
|
|
||||||
Files::PathContainer dataDirs, dataLocal;
|
Files::PathContainer dataDirs, dataLocal;
|
||||||
if (!variables["data"].empty()) {
|
if (!variables["data"].empty()) {
|
||||||
dataDirs = Files::PathContainer(variables["data"].as<Files::PathContainer>());
|
dataDirs = Files::PathContainer(variables["data"].as<Files::PathContainer>());
|
||||||
|
@ -83,23 +101,11 @@ void CS::Editor::setupDataFiles()
|
||||||
messageBox.exec();
|
messageBox.exec();
|
||||||
|
|
||||||
QApplication::exit (1);
|
QApplication::exit (1);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end());
|
dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end());
|
||||||
|
|
||||||
mDocumentManager.setResourceDir (variables["resources"].as<std::string>());
|
return dataDirs;
|
||||||
|
|
||||||
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
|
|
||||||
{
|
|
||||||
|
|
||||||
QString path = QString::fromStdString(iter->string());
|
|
||||||
mFileDialog.addFiles(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
//load the settings into the userSettings instance.
|
|
||||||
const QString settingFileName = "opencs.cfg";
|
|
||||||
CSMSettings::UserSettings::instance().loadSettings(settingFileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CS::Editor::createGame()
|
void CS::Editor::createGame()
|
||||||
|
@ -210,8 +216,6 @@ int CS::Editor::run()
|
||||||
if (mLocal.empty())
|
if (mLocal.empty())
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// temporarily disable OGRE-integration (need to fix path problem first)
|
|
||||||
#if 0
|
|
||||||
// TODO: setting
|
// TODO: setting
|
||||||
Ogre::Root::getSingleton().setRenderSystem(Ogre::Root::getSingleton().getRenderSystemByName("OpenGL Rendering Subsystem"));
|
Ogre::Root::getSingleton().setRenderSystem(Ogre::Root::getSingleton().getRenderSystemByName("OpenGL Rendering Subsystem"));
|
||||||
|
|
||||||
|
@ -228,7 +232,6 @@ int CS::Editor::run()
|
||||||
#endif
|
#endif
|
||||||
Ogre::RenderWindow* hiddenWindow = Ogre::Root::getSingleton().createRenderWindow("InactiveHidden", 1, 1, false, ¶ms);
|
Ogre::RenderWindow* hiddenWindow = Ogre::Root::getSingleton().createRenderWindow("InactiveHidden", 1, 1, false, ¶ms);
|
||||||
hiddenWindow->setActive(false);
|
hiddenWindow->setActive(false);
|
||||||
#endif
|
|
||||||
|
|
||||||
mStartup.show();
|
mStartup.show();
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include <components/files/configurationmanager.hpp>
|
#include <components/files/configurationmanager.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <components/files/multidircollection.hpp>
|
||||||
|
|
||||||
#include "model/settings/usersettings.hpp"
|
#include "model/settings/usersettings.hpp"
|
||||||
#include "model/doc/documentmanager.hpp"
|
#include "model/doc/documentmanager.hpp"
|
||||||
|
|
||||||
|
@ -20,6 +22,11 @@
|
||||||
|
|
||||||
#include "view/settings/usersettingsdialog.hpp"
|
#include "view/settings/usersettingsdialog.hpp"
|
||||||
|
|
||||||
|
namespace OgreInit
|
||||||
|
{
|
||||||
|
class OgreInit;
|
||||||
|
}
|
||||||
|
|
||||||
namespace CS
|
namespace CS
|
||||||
{
|
{
|
||||||
class Editor : public QObject
|
class Editor : public QObject
|
||||||
|
@ -37,7 +44,10 @@ namespace CS
|
||||||
|
|
||||||
boost::filesystem::path mLocal;
|
boost::filesystem::path mLocal;
|
||||||
|
|
||||||
void setupDataFiles();
|
void setupDataFiles (const Files::PathContainer& dataDirs);
|
||||||
|
|
||||||
|
Files::PathContainer readConfig();
|
||||||
|
///< \return data paths
|
||||||
|
|
||||||
// not implemented
|
// not implemented
|
||||||
Editor (const Editor&);
|
Editor (const Editor&);
|
||||||
|
@ -45,7 +55,7 @@ namespace CS
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Editor();
|
Editor (OgreInit::OgreInit& ogreInit);
|
||||||
|
|
||||||
bool makeIPCServer();
|
bool makeIPCServer();
|
||||||
void connectToIPCServer();
|
void connectToIPCServer();
|
||||||
|
|
|
@ -40,15 +40,9 @@ int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
Q_INIT_RESOURCE (resources);
|
Q_INIT_RESOURCE (resources);
|
||||||
|
|
||||||
// TODO: Ogre startup shouldn't be here, but it currently has to:
|
|
||||||
// SceneWidget destructor will delete the created render window, which would be called _after_ Root has shut down :(
|
|
||||||
|
|
||||||
Application mApplication (argc, argv);
|
|
||||||
// temporarily disable OGRE-integration (need to fix path problem first)
|
|
||||||
#if 0
|
|
||||||
OgreInit::OgreInit ogreInit;
|
OgreInit::OgreInit ogreInit;
|
||||||
ogreInit.init("./opencsOgre.log"); // TODO log path?
|
|
||||||
#endif
|
Application application (argc, argv);
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
QDir dir(QCoreApplication::applicationDirPath());
|
QDir dir(QCoreApplication::applicationDirPath());
|
||||||
|
@ -66,12 +60,12 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
QStringList libraryPaths;
|
QStringList libraryPaths;
|
||||||
libraryPaths << pluginsPath.path() << QCoreApplication::applicationDirPath();
|
libraryPaths << pluginsPath.path() << QCoreApplication::applicationDirPath();
|
||||||
mApplication.setLibraryPaths(libraryPaths);
|
application.setLibraryPaths(libraryPaths);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mApplication.setWindowIcon (QIcon (":./opencs.png"));
|
application.setWindowIcon (QIcon (":./opencs.png"));
|
||||||
|
|
||||||
CS::Editor editor;
|
CS::Editor editor (ogreInit);
|
||||||
|
|
||||||
if(!editor.makeIPCServer())
|
if(!editor.makeIPCServer())
|
||||||
{
|
{
|
||||||
|
|
|
@ -247,12 +247,12 @@ CSMWorld::Data::Data() : mRefs (mCells)
|
||||||
addModel (new IdTable (&mSpells), UniversalId::Type_Spells, UniversalId::Type_Spell);
|
addModel (new IdTable (&mSpells), UniversalId::Type_Spells, UniversalId::Type_Spell);
|
||||||
addModel (new IdTable (&mTopics), UniversalId::Type_Topics, UniversalId::Type_Topic);
|
addModel (new IdTable (&mTopics), UniversalId::Type_Topics, UniversalId::Type_Topic);
|
||||||
addModel (new IdTable (&mJournals), UniversalId::Type_Journals, UniversalId::Type_Journal);
|
addModel (new IdTable (&mJournals), UniversalId::Type_Journals, UniversalId::Type_Journal);
|
||||||
addModel (new IdTable (&mTopicInfos), UniversalId::Type_TopicInfos, UniversalId::Type_TopicInfo);
|
addModel (new IdTable (&mTopicInfos, IdTable::Reordering_WithinTopic), UniversalId::Type_TopicInfos, UniversalId::Type_TopicInfo);
|
||||||
addModel (new IdTable (&mJournalInfos), UniversalId::Type_JournalInfos, UniversalId::Type_JournalInfo);
|
addModel (new IdTable (&mJournalInfos, IdTable::Reordering_WithinTopic), UniversalId::Type_JournalInfos, UniversalId::Type_JournalInfo);
|
||||||
addModel (new IdTable (&mCells), UniversalId::Type_Cells, UniversalId::Type_Cell);
|
addModel (new IdTable (&mCells, IdTable::Reordering_None, IdTable::Viewing_Id), UniversalId::Type_Cells, UniversalId::Type_Cell);
|
||||||
addModel (new IdTable (&mReferenceables), UniversalId::Type_Referenceables,
|
addModel (new IdTable (&mReferenceables), UniversalId::Type_Referenceables,
|
||||||
UniversalId::Type_Referenceable);
|
UniversalId::Type_Referenceable);
|
||||||
addModel (new IdTable (&mRefs), UniversalId::Type_References, UniversalId::Type_Reference, false);
|
addModel (new IdTable (&mRefs, IdTable::Reordering_None, IdTable::Viewing_Cell), UniversalId::Type_References, UniversalId::Type_Reference, false);
|
||||||
addModel (new IdTable (&mFilters), UniversalId::Type_Filters, UniversalId::Type_Filter, false);
|
addModel (new IdTable (&mFilters), UniversalId::Type_Filters, UniversalId::Type_Filter, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,9 @@
|
||||||
#include "collectionbase.hpp"
|
#include "collectionbase.hpp"
|
||||||
#include "columnbase.hpp"
|
#include "columnbase.hpp"
|
||||||
|
|
||||||
CSMWorld::IdTable::IdTable (CollectionBase *idCollection, Reordering reordering)
|
CSMWorld::IdTable::IdTable (CollectionBase *idCollection, Reordering reordering,
|
||||||
: mIdCollection (idCollection), mReordering (reordering)
|
Viewing viewing)
|
||||||
|
: mIdCollection (idCollection), mReordering (reordering), mViewing (viewing)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
CSMWorld::IdTable::~IdTable()
|
CSMWorld::IdTable::~IdTable()
|
||||||
|
@ -189,3 +190,44 @@ CSMWorld::IdTable::Reordering CSMWorld::IdTable::getReordering() const
|
||||||
{
|
{
|
||||||
return mReordering;
|
return mReordering;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CSMWorld::IdTable::Viewing CSMWorld::IdTable::getViewing() const
|
||||||
|
{
|
||||||
|
return mViewing;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<CSMWorld::UniversalId, std::string> CSMWorld::IdTable::view (int row) const
|
||||||
|
{
|
||||||
|
std::string id;
|
||||||
|
std::string hint;
|
||||||
|
|
||||||
|
if (mViewing==Viewing_Cell)
|
||||||
|
{
|
||||||
|
int cellColumn = mIdCollection->searchColumnIndex (Columns::ColumnId_Cell);
|
||||||
|
int idColumn = mIdCollection->searchColumnIndex (Columns::ColumnId_Id);
|
||||||
|
|
||||||
|
if (cellColumn!=-1 && idColumn!=-1)
|
||||||
|
{
|
||||||
|
id = mIdCollection->getData (row, cellColumn).toString().toUtf8().constData();
|
||||||
|
hint = "r:" + std::string (mIdCollection->getData (row, idColumn).toString().toUtf8().constData());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mViewing==Viewing_Id)
|
||||||
|
{
|
||||||
|
int column = mIdCollection->searchColumnIndex (Columns::ColumnId_Id);
|
||||||
|
|
||||||
|
if (column!=-1)
|
||||||
|
{
|
||||||
|
id = mIdCollection->getData (row, column).toString().toUtf8().constData();
|
||||||
|
hint = "c:" + id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id.empty())
|
||||||
|
return std::make_pair (UniversalId::Type_None, "");
|
||||||
|
|
||||||
|
if (id[0]=='#')
|
||||||
|
id = "sys::default";
|
||||||
|
|
||||||
|
return std::make_pair (UniversalId (UniversalId::Type_Scene, id), hint);
|
||||||
|
}
|
|
@ -25,10 +25,20 @@ namespace CSMWorld
|
||||||
Reordering_WithinTopic
|
Reordering_WithinTopic
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum Viewing
|
||||||
|
{
|
||||||
|
Viewing_None,
|
||||||
|
Viewing_Id, // use ID column to generate view request (ID is transformed into
|
||||||
|
// worldspace and original ID is passed as hint with c: prefix)
|
||||||
|
Viewing_Cell // use cell column to generate view request (cell ID is transformed
|
||||||
|
// into worldspace and record ID is passed as hint with r: prefix)
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
CollectionBase *mIdCollection;
|
CollectionBase *mIdCollection;
|
||||||
Reordering mReordering;
|
Reordering mReordering;
|
||||||
|
Viewing mViewing;
|
||||||
|
|
||||||
// not implemented
|
// not implemented
|
||||||
IdTable (const IdTable&);
|
IdTable (const IdTable&);
|
||||||
|
@ -36,7 +46,8 @@ namespace CSMWorld
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
IdTable (CollectionBase *idCollection, Reordering reordering = Reordering_WithinTopic);
|
IdTable (CollectionBase *idCollection, Reordering reordering = Reordering_None,
|
||||||
|
Viewing viewing = Viewing_None);
|
||||||
///< The ownership of \a idCollection is not transferred.
|
///< The ownership of \a idCollection is not transferred.
|
||||||
|
|
||||||
virtual ~IdTable();
|
virtual ~IdTable();
|
||||||
|
@ -86,6 +97,12 @@ namespace CSMWorld
|
||||||
/// given in \a newOrder (baseIndex+newOrder[0] specifies the new index of row baseIndex).
|
/// given in \a newOrder (baseIndex+newOrder[0] specifies the new index of row baseIndex).
|
||||||
|
|
||||||
Reordering getReordering() const;
|
Reordering getReordering() const;
|
||||||
|
|
||||||
|
Viewing getViewing() const;
|
||||||
|
|
||||||
|
std::pair<UniversalId, std::string> view (int row) const;
|
||||||
|
///< Return the UniversalId and the hint for viewing \a row. If viewing is not
|
||||||
|
/// supported by this table, return (UniversalId::Type_None, "").
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,14 +90,14 @@ namespace
|
||||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Weapon, "Weapon", ":./weapon.png" },
|
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Weapon, "Weapon", ":./weapon.png" },
|
||||||
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Reference, "Reference", 0 },
|
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Reference, "Reference", 0 },
|
||||||
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Filter, "Filter", ":./filter.png" },
|
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Filter, "Filter", ":./filter.png" },
|
||||||
|
{ CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Scene, "Scene", 0 },
|
||||||
|
|
||||||
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
|
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
|
||||||
};
|
};
|
||||||
|
|
||||||
static const TypeData sIndexArg[] =
|
static const TypeData sIndexArg[] =
|
||||||
{
|
{
|
||||||
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults, "Verification Results", 0 },
|
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults, "Verification Results", 0 },
|
||||||
{ CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Scene, "Scene", 0 },
|
|
||||||
|
|
||||||
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
|
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,3 +17,5 @@ void CSVDoc::SubView::updateEditorSetting (const QString &settingName, const QSt
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVDoc::SubView::setStatusBar (bool show) {}
|
void CSVDoc::SubView::setStatusBar (bool show) {}
|
||||||
|
|
||||||
|
void CSVDoc::SubView::useHint (const std::string& hint) {}
|
|
@ -40,9 +40,12 @@ namespace CSVDoc
|
||||||
virtual void setStatusBar (bool show);
|
virtual void setStatusBar (bool show);
|
||||||
///< Default implementation: ignored
|
///< Default implementation: ignored
|
||||||
|
|
||||||
|
virtual void useHint (const std::string& hint);
|
||||||
|
///< Default implementation: ignored
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void focusId (const CSMWorld::UniversalId& universalId);
|
void focusId (const CSMWorld::UniversalId& universalId, const std::string& hint);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -115,10 +115,6 @@ void CSVDoc::View::setupWorldMenu()
|
||||||
|
|
||||||
world->addSeparator(); // items that don't represent single record lists follow here
|
world->addSeparator(); // items that don't represent single record lists follow here
|
||||||
|
|
||||||
QAction *scene = new QAction (tr ("Scene"), this);
|
|
||||||
connect (scene, SIGNAL (triggered()), this, SLOT (addSceneSubView()));
|
|
||||||
world->addAction (scene);
|
|
||||||
|
|
||||||
QAction *regionMap = new QAction (tr ("Region Map"), this);
|
QAction *regionMap = new QAction (tr ("Region Map"), this);
|
||||||
connect (regionMap, SIGNAL (triggered()), this, SLOT (addRegionMapSubView()));
|
connect (regionMap, SIGNAL (triggered()), this, SLOT (addRegionMapSubView()));
|
||||||
world->addAction (regionMap);
|
world->addAction (regionMap);
|
||||||
|
@ -310,7 +306,7 @@ void CSVDoc::View::updateProgress (int current, int max, int type, int threads)
|
||||||
mOperations->setProgress (current, max, type, threads);
|
mOperations->setProgress (current, max, type, threads);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id)
|
void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::string& hint)
|
||||||
{
|
{
|
||||||
/// \todo add an user setting for limiting the number of sub views per top level view. Automatically open a new top level view if this
|
/// \todo add an user setting for limiting the number of sub views per top level view. Automatically open a new top level view if this
|
||||||
/// number is exceeded
|
/// number is exceeded
|
||||||
|
@ -322,12 +318,15 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id)
|
||||||
|
|
||||||
SubView *view = mSubViewFactory.makeSubView (id, *mDocument);
|
SubView *view = mSubViewFactory.makeSubView (id, *mDocument);
|
||||||
|
|
||||||
|
if (!hint.empty())
|
||||||
|
view->useHint (hint);
|
||||||
|
|
||||||
view->setStatusBar (mShowStatusBar->isChecked());
|
view->setStatusBar (mShowStatusBar->isChecked());
|
||||||
|
|
||||||
mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view);
|
mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view);
|
||||||
|
|
||||||
connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&)), this,
|
connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&)), this,
|
||||||
SLOT (addSubView (const CSMWorld::UniversalId&)));
|
SLOT (addSubView (const CSMWorld::UniversalId&, const std::string&)));
|
||||||
|
|
||||||
CSMSettings::UserSettings::instance().updateSettings("Display Format");
|
CSMSettings::UserSettings::instance().updateSettings("Display Format");
|
||||||
|
|
||||||
|
@ -429,11 +428,6 @@ void CSVDoc::View::addFiltersSubView()
|
||||||
addSubView (CSMWorld::UniversalId::Type_Filters);
|
addSubView (CSMWorld::UniversalId::Type_Filters);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVDoc::View::addSceneSubView()
|
|
||||||
{
|
|
||||||
addSubView (CSMWorld::UniversalId::Type_Scene);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSVDoc::View::addTopicsSubView()
|
void CSVDoc::View::addTopicsSubView()
|
||||||
{
|
{
|
||||||
addSubView (CSMWorld::UniversalId::Type_Topics);
|
addSubView (CSMWorld::UniversalId::Type_Topics);
|
||||||
|
|
|
@ -120,7 +120,9 @@ namespace CSVDoc
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void addSubView (const CSMWorld::UniversalId& id);
|
void addSubView (const CSMWorld::UniversalId& id, const std::string& hint = "");
|
||||||
|
///< \param hint Suggested view point (e.g. coordinates in a 3D scene or a line number
|
||||||
|
/// in a script).
|
||||||
|
|
||||||
void abortOperation (int type);
|
void abortOperation (int type);
|
||||||
|
|
||||||
|
@ -166,8 +168,6 @@ namespace CSVDoc
|
||||||
|
|
||||||
void addFiltersSubView();
|
void addFiltersSubView();
|
||||||
|
|
||||||
void addSceneSubView();
|
|
||||||
|
|
||||||
void addTopicsSubView();
|
void addTopicsSubView();
|
||||||
|
|
||||||
void addJournalsSubView();
|
void addJournalsSubView();
|
||||||
|
|
19
apps/opencs/view/render/navigation.cpp
Normal file
19
apps/opencs/view/render/navigation.cpp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
#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() {}
|
||||||
|
|
||||||
|
void CSVRender::Navigation::setFastModeFactor (float factor)
|
||||||
|
{
|
||||||
|
mFastModeFactor = factor;
|
||||||
|
}
|
46
apps/opencs/view/render/navigation.hpp
Normal file
46
apps/opencs/view/render/navigation.hpp
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#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:
|
||||||
|
|
||||||
|
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
|
85
apps/opencs/view/render/navigation1st.cpp
Normal file
85
apps/opencs/view/render/navigation1st.cpp
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
|
||||||
|
#include "navigation1st.hpp"
|
||||||
|
|
||||||
|
#include <OgreCamera.h>
|
||||||
|
|
||||||
|
#include <QPoint>
|
||||||
|
|
||||||
|
CSVRender::Navigation1st::Navigation1st() : mCamera (0) {}
|
||||||
|
|
||||||
|
bool CSVRender::Navigation1st::activate (Ogre::Camera *camera)
|
||||||
|
{
|
||||||
|
mCamera = camera;
|
||||||
|
mCamera->setFixedYawAxis (true);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
Ogre::Radian limit (Ogre::Math::PI/2-0.5);
|
||||||
|
|
||||||
|
if ((deltaPitch>0 && newPitch<limit) || (deltaPitch<0 && newPitch>-limit))
|
||||||
|
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;
|
||||||
|
}
|
35
apps/opencs/view/render/navigation1st.hpp
Normal file
35
apps/opencs/view/render/navigation1st.hpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#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
|
66
apps/opencs/view/render/navigationfree.cpp
Normal file
66
apps/opencs/view/render/navigationfree.cpp
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
|
||||||
|
#include "navigationfree.hpp"
|
||||||
|
|
||||||
|
#include <OgreCamera.h>
|
||||||
|
|
||||||
|
#include <QPoint>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
35
apps/opencs/view/render/navigationfree.hpp
Normal file
35
apps/opencs/view/render/navigationfree.hpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#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
|
100
apps/opencs/view/render/navigationorbit.cpp
Normal file
100
apps/opencs/view/render/navigationorbit.cpp
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
|
||||||
|
#include "navigationorbit.hpp"
|
||||||
|
|
||||||
|
#include <OgreCamera.h>
|
||||||
|
|
||||||
|
#include <QPoint>
|
||||||
|
|
||||||
|
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()<mDistance)
|
||||||
|
{
|
||||||
|
// move camera out of the centre area
|
||||||
|
Ogre::Vector3 direction = mCentre-mCamera->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;
|
||||||
|
}
|
42
apps/opencs/view/render/navigationorbit.hpp
Normal file
42
apps/opencs/view/render/navigationorbit.hpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef OPENCS_VIEW_NAVIGATIONORBIT_H
|
||||||
|
#define OPENCS_VIEW_NAVIGATIONORBIT_H
|
||||||
|
|
||||||
|
#include "navigation.hpp"
|
||||||
|
|
||||||
|
#include <OgreVector3.h>
|
||||||
|
|
||||||
|
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
|
6
apps/opencs/view/render/pagedworldspacewidget.cpp
Normal file
6
apps/opencs/view/render/pagedworldspacewidget.cpp
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#include "pagedworldspacewidget.hpp"
|
||||||
|
|
||||||
|
CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget *parent)
|
||||||
|
: WorldspaceWidget (parent)
|
||||||
|
{}
|
18
apps/opencs/view/render/pagedworldspacewidget.hpp
Normal file
18
apps/opencs/view/render/pagedworldspacewidget.hpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef OPENCS_VIEW_PAGEDWORLDSPACEWIDGET_H
|
||||||
|
#define OPENCS_VIEW_PAGEDWORLDSPACEWIDGET_H
|
||||||
|
|
||||||
|
#include "worldspacewidget.hpp"
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
class PagedWorldspaceWidget : public WorldspaceWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
PagedWorldspaceWidget (QWidget *parent);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -2,24 +2,34 @@
|
||||||
|
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
#include <QResizeEvent>
|
#include <QResizeEvent>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
#include <OgreRoot.h>
|
#include <OgreRoot.h>
|
||||||
#include <OgreRenderWindow.h>
|
#include <OgreRenderWindow.h>
|
||||||
#include <OgreEntity.h>
|
#include <OgreEntity.h>
|
||||||
#include <OgreCamera.h>
|
#include <OgreCamera.h>
|
||||||
|
#include <OgreSceneNode.h>
|
||||||
|
#include <OgreViewport.h>
|
||||||
|
|
||||||
|
#include "navigation.hpp"
|
||||||
|
|
||||||
namespace CSVRender
|
namespace CSVRender
|
||||||
{
|
{
|
||||||
|
|
||||||
SceneWidget::SceneWidget(QWidget *parent)
|
SceneWidget::SceneWidget(QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, mWindow(NULL)
|
, mWindow(NULL)
|
||||||
, mCamera(NULL)
|
, mCamera(NULL)
|
||||||
, mSceneMgr(NULL)
|
, mSceneMgr(NULL), mNavigation (0), mUpdate (false)
|
||||||
|
, mKeyForward (false), mKeyBackward (false), mKeyLeft (false), mKeyRight (false)
|
||||||
|
, mKeyRollLeft (false), mKeyRollRight (false)
|
||||||
|
, mFast (false), mDragging (false), mMod1 (false)
|
||||||
|
, mFastFactor (4) /// \todo make this configurable
|
||||||
{
|
{
|
||||||
setAttribute(Qt::WA_PaintOnScreen);
|
setAttribute(Qt::WA_PaintOnScreen);
|
||||||
setAttribute(Qt::WA_NoSystemBackground);
|
setAttribute(Qt::WA_NoSystemBackground);
|
||||||
|
|
||||||
|
setFocusPolicy (Qt::StrongFocus);
|
||||||
|
|
||||||
mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC);
|
mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC);
|
||||||
|
|
||||||
// Throw in a random color just to make sure multiple scenes work
|
// Throw in a random color just to make sure multiple scenes work
|
||||||
|
@ -44,6 +54,16 @@ namespace CSVRender
|
||||||
mCamera->lookAt(0,0,0);
|
mCamera->lookAt(0,0,0);
|
||||||
mCamera->setNearClipDistance(0.1);
|
mCamera->setNearClipDistance(0.1);
|
||||||
mCamera->setFarClipDistance(3000);
|
mCamera->setFarClipDistance(3000);
|
||||||
|
|
||||||
|
QTimer *timer = new QTimer (this);
|
||||||
|
|
||||||
|
connect (timer, SIGNAL (timeout()), this, SLOT (update()));
|
||||||
|
timer->start (20); /// \todo make this configurable
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneWidget::setAmbient (const Ogre::ColourValue& colour)
|
||||||
|
{
|
||||||
|
mSceneMgr->setAmbientLight (colour);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneWidget::updateOgreWindow()
|
void SceneWidget::updateOgreWindow()
|
||||||
|
@ -81,7 +101,21 @@ namespace CSVRender
|
||||||
|
|
||||||
SceneWidget::~SceneWidget()
|
SceneWidget::~SceneWidget()
|
||||||
{
|
{
|
||||||
|
if (mWindow)
|
||||||
Ogre::Root::getSingleton().destroyRenderTarget (mWindow);
|
Ogre::Root::getSingleton().destroyRenderTarget (mWindow);
|
||||||
|
|
||||||
|
if (mSceneMgr)
|
||||||
|
Ogre::Root::getSingleton().destroySceneManager (mSceneMgr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneWidget::setNavigation (Navigation *navigation)
|
||||||
|
{
|
||||||
|
if ((mNavigation = navigation))
|
||||||
|
{
|
||||||
|
mNavigation->setFastModeFactor (mFast ? mFastFactor : 1);
|
||||||
|
if (mNavigation->activate (mCamera))
|
||||||
|
mUpdate = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneWidget::paintEvent(QPaintEvent* e)
|
void SceneWidget::paintEvent(QPaintEvent* e)
|
||||||
|
@ -93,7 +127,6 @@ namespace CSVRender
|
||||||
e->accept();
|
e->accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QPaintEngine* SceneWidget::paintEngine() const
|
QPaintEngine* SceneWidget::paintEngine() const
|
||||||
{
|
{
|
||||||
// We don't want another paint engine to get in the way.
|
// We don't want another paint engine to get in the way.
|
||||||
|
@ -130,4 +163,151 @@ namespace CSVRender
|
||||||
return QWidget::event(e);
|
return QWidget::event(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SceneWidget::keyPressEvent (QKeyEvent *event)
|
||||||
|
{
|
||||||
|
switch (event->key())
|
||||||
|
{
|
||||||
|
case Qt::Key_W: mKeyForward = true; break;
|
||||||
|
case Qt::Key_S: mKeyBackward = true; break;
|
||||||
|
case Qt::Key_A: mKeyLeft = true; break;
|
||||||
|
case Qt::Key_D: mKeyRight = true; break;
|
||||||
|
case Qt::Key_Q: mKeyRollLeft = true; break;
|
||||||
|
case Qt::Key_E: mKeyRollRight = true; break;
|
||||||
|
case Qt::Key_Control: mMod1 = true; break;
|
||||||
|
|
||||||
|
case Qt::Key_Shift:
|
||||||
|
|
||||||
|
mFast = true;
|
||||||
|
|
||||||
|
if (mNavigation)
|
||||||
|
mNavigation->setFastModeFactor (mFastFactor);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: QWidget::keyPressEvent (event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneWidget::keyReleaseEvent (QKeyEvent *event)
|
||||||
|
{
|
||||||
|
switch (event->key())
|
||||||
|
{
|
||||||
|
case Qt::Key_W: mKeyForward = false; break;
|
||||||
|
case Qt::Key_S: mKeyBackward = false; break;
|
||||||
|
case Qt::Key_A: mKeyLeft = false; break;
|
||||||
|
case Qt::Key_D: mKeyRight = false; break;
|
||||||
|
case Qt::Key_Q: mKeyRollLeft = false; break;
|
||||||
|
case Qt::Key_E: mKeyRollRight = false; break;
|
||||||
|
case Qt::Key_Control: mMod1 = false; break;
|
||||||
|
|
||||||
|
case Qt::Key_Shift:
|
||||||
|
|
||||||
|
mFast = false;
|
||||||
|
|
||||||
|
if (mNavigation)
|
||||||
|
mNavigation->setFastModeFactor (1);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: QWidget::keyReleaseEvent (event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneWidget::wheelEvent (QWheelEvent *event)
|
||||||
|
{
|
||||||
|
if (mNavigation)
|
||||||
|
if (event->delta())
|
||||||
|
if (mNavigation->wheelMoved (event->delta()))
|
||||||
|
mUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneWidget::leaveEvent (QEvent *event)
|
||||||
|
{
|
||||||
|
mDragging = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneWidget::mouseMoveEvent (QMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (event->buttons() & Qt::LeftButton)
|
||||||
|
{
|
||||||
|
if (mDragging)
|
||||||
|
{
|
||||||
|
QPoint diff = mOldPos-event->pos();
|
||||||
|
mOldPos = event->pos();
|
||||||
|
|
||||||
|
if (mNavigation)
|
||||||
|
if (mNavigation->mouseMoved (diff, mMod1 ? 1 : 0))
|
||||||
|
mUpdate = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mDragging = true;
|
||||||
|
mOldPos = event->pos();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneWidget::mouseReleaseEvent (QMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (!(event->buttons() & Qt::LeftButton))
|
||||||
|
mDragging = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneWidget::focusOutEvent (QFocusEvent *event)
|
||||||
|
{
|
||||||
|
mKeyForward = false;
|
||||||
|
mKeyBackward = false;
|
||||||
|
mKeyLeft = false;
|
||||||
|
mKeyRight = false;
|
||||||
|
mFast = false;
|
||||||
|
mMod1 = false;
|
||||||
|
|
||||||
|
QWidget::focusOutEvent (event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneWidget::update()
|
||||||
|
{
|
||||||
|
if (mNavigation)
|
||||||
|
{
|
||||||
|
int horizontal = 0;
|
||||||
|
int vertical = 0;
|
||||||
|
|
||||||
|
if (mKeyForward && !mKeyBackward)
|
||||||
|
vertical = 1;
|
||||||
|
else if (!mKeyForward && mKeyBackward)
|
||||||
|
vertical = -1;
|
||||||
|
|
||||||
|
if (mKeyLeft && !mKeyRight)
|
||||||
|
horizontal = -1;
|
||||||
|
else if (!mKeyLeft && mKeyRight)
|
||||||
|
horizontal = 1;
|
||||||
|
|
||||||
|
if (horizontal || vertical)
|
||||||
|
if (mNavigation->handleMovementKeys (vertical, horizontal))
|
||||||
|
mUpdate = true;
|
||||||
|
|
||||||
|
int roll = 0;
|
||||||
|
|
||||||
|
if (mKeyRollLeft && !mKeyRollRight)
|
||||||
|
roll = 1;
|
||||||
|
else if (!mKeyRollLeft && mKeyRollRight)
|
||||||
|
roll = -1;
|
||||||
|
|
||||||
|
if (roll)
|
||||||
|
if (mNavigation->handleRollKeys (roll))
|
||||||
|
mUpdate = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mUpdate)
|
||||||
|
{
|
||||||
|
mUpdate = false;
|
||||||
|
mWindow->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int SceneWidget::getFastFactor() const
|
||||||
|
{
|
||||||
|
return mFast ? mFastFactor : 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,33 +8,77 @@ namespace Ogre
|
||||||
class Camera;
|
class Camera;
|
||||||
class SceneManager;
|
class SceneManager;
|
||||||
class RenderWindow;
|
class RenderWindow;
|
||||||
|
class ColourValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace CSVRender
|
namespace CSVRender
|
||||||
{
|
{
|
||||||
|
class Navigation;
|
||||||
|
|
||||||
class SceneWidget : public QWidget
|
class SceneWidget : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SceneWidget(QWidget *parent);
|
SceneWidget(QWidget *parent);
|
||||||
virtual ~SceneWidget(void);
|
virtual ~SceneWidget();
|
||||||
|
|
||||||
QPaintEngine* paintEngine() const;
|
QPaintEngine* paintEngine() const;
|
||||||
|
|
||||||
|
void setAmbient (const Ogre::ColourValue& colour);
|
||||||
|
///< \note The actual ambient colour may differ based on lighting settings.
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void setNavigation (Navigation *navigation);
|
||||||
|
///< \attention The ownership of \a navigation is not transferred to *this.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void paintEvent(QPaintEvent* e);
|
void paintEvent(QPaintEvent* e);
|
||||||
void resizeEvent(QResizeEvent* e);
|
void resizeEvent(QResizeEvent* e);
|
||||||
bool event(QEvent* e);
|
bool event(QEvent* e);
|
||||||
|
|
||||||
|
void keyPressEvent (QKeyEvent *event);
|
||||||
|
|
||||||
|
void keyReleaseEvent (QKeyEvent *event);
|
||||||
|
|
||||||
|
void focusOutEvent (QFocusEvent *event);
|
||||||
|
|
||||||
|
void wheelEvent (QWheelEvent *event);
|
||||||
|
|
||||||
|
void leaveEvent (QEvent *event);
|
||||||
|
|
||||||
|
void mouseMoveEvent (QMouseEvent *event);
|
||||||
|
|
||||||
|
void mouseReleaseEvent (QMouseEvent *event);
|
||||||
|
|
||||||
void updateOgreWindow();
|
void updateOgreWindow();
|
||||||
|
|
||||||
|
int getFastFactor() const;
|
||||||
|
|
||||||
Ogre::Camera* mCamera;
|
Ogre::Camera* mCamera;
|
||||||
Ogre::SceneManager* mSceneMgr;
|
Ogre::SceneManager* mSceneMgr;
|
||||||
Ogre::RenderWindow* mWindow;
|
Ogre::RenderWindow* mWindow;
|
||||||
};
|
|
||||||
|
|
||||||
|
Navigation *mNavigation;
|
||||||
|
bool mUpdate;
|
||||||
|
bool mKeyForward;
|
||||||
|
bool mKeyBackward;
|
||||||
|
bool mKeyLeft;
|
||||||
|
bool mKeyRight;
|
||||||
|
bool mKeyRollLeft;
|
||||||
|
bool mKeyRollRight;
|
||||||
|
bool mFast;
|
||||||
|
bool mDragging;
|
||||||
|
bool mMod1;
|
||||||
|
QPoint mOldPos;
|
||||||
|
int mFastFactor;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void update();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
66
apps/opencs/view/render/unpagedworldspacewidget.cpp
Normal file
66
apps/opencs/view/render/unpagedworldspacewidget.cpp
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
|
||||||
|
#include "unpagedworldspacewidget.hpp"
|
||||||
|
|
||||||
|
#include <OgreColourValue.h>
|
||||||
|
|
||||||
|
#include "../../model/doc/document.hpp"
|
||||||
|
|
||||||
|
#include "../../model/world/data.hpp"
|
||||||
|
#include "../../model/world/idtable.hpp"
|
||||||
|
|
||||||
|
void CSVRender::UnpagedWorldspaceWidget::update()
|
||||||
|
{
|
||||||
|
const CSMWorld::Record<CSMWorld::Cell>& record =
|
||||||
|
dynamic_cast<const CSMWorld::Record<CSMWorld::Cell>&> (mCellsModel->getRecord (mCellId));
|
||||||
|
|
||||||
|
Ogre::ColourValue colour;
|
||||||
|
colour.setAsABGR (record.get().mAmbi.mAmbient);
|
||||||
|
setAmbient (colour);
|
||||||
|
|
||||||
|
/// \todo deal with mSunlight and mFog/mForDensity
|
||||||
|
}
|
||||||
|
|
||||||
|
CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& cellId,
|
||||||
|
CSMDoc::Document& document, QWidget *parent)
|
||||||
|
: WorldspaceWidget (parent), mCellId (cellId)
|
||||||
|
{
|
||||||
|
mCellsModel = &dynamic_cast<CSMWorld::IdTable&> (
|
||||||
|
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells));
|
||||||
|
|
||||||
|
connect (mCellsModel, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
|
||||||
|
this, SLOT (cellDataChanged (const QModelIndex&, const QModelIndex&)));
|
||||||
|
connect (mCellsModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
||||||
|
this, SLOT (cellRowsAboutToBeRemoved (const QModelIndex&, int, int)));
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft,
|
||||||
|
const QModelIndex& bottomRight)
|
||||||
|
{
|
||||||
|
int index = mCellsModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification);
|
||||||
|
QModelIndex cellIndex = mCellsModel->getModelIndex (mCellId, index);
|
||||||
|
|
||||||
|
if (cellIndex.row()>=topLeft.row() && cellIndex.row()<=bottomRight.row())
|
||||||
|
{
|
||||||
|
if (mCellsModel->data (cellIndex).toInt()==CSMWorld::RecordBase::State_Deleted)
|
||||||
|
{
|
||||||
|
emit closeRequest();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/// \todo possible optimisation: check columns and update only if relevant columns have
|
||||||
|
/// changed
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::UnpagedWorldspaceWidget::cellRowsAboutToBeRemoved (const QModelIndex& parent,
|
||||||
|
int start, int end)
|
||||||
|
{
|
||||||
|
QModelIndex cellIndex = mCellsModel->getModelIndex (mCellId, 0);
|
||||||
|
|
||||||
|
if (cellIndex.row()>=start && cellIndex.row()<=end)
|
||||||
|
emit closeRequest();
|
||||||
|
}
|
44
apps/opencs/view/render/unpagedworldspacewidget.hpp
Normal file
44
apps/opencs/view/render/unpagedworldspacewidget.hpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#ifndef OPENCS_VIEW_UNPAGEDWORLDSPACEWIDGET_H
|
||||||
|
#define OPENCS_VIEW_UNPAGEDWORLDSPACEWIDGET_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "worldspacewidget.hpp"
|
||||||
|
|
||||||
|
class QModelIndex;
|
||||||
|
|
||||||
|
namespace CSMDoc
|
||||||
|
{
|
||||||
|
class Document;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CSMWorld
|
||||||
|
{
|
||||||
|
class IdTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
class UnpagedWorldspaceWidget : public WorldspaceWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
std::string mCellId;
|
||||||
|
CSMWorld::IdTable *mCellsModel;
|
||||||
|
|
||||||
|
void update();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document,
|
||||||
|
QWidget *parent);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void cellDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
||||||
|
|
||||||
|
void cellRowsAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
38
apps/opencs/view/render/worldspacewidget.cpp
Normal file
38
apps/opencs/view/render/worldspacewidget.cpp
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
|
||||||
|
#include "worldspacewidget.hpp"
|
||||||
|
|
||||||
|
#include "../world/scenetoolmode.hpp"
|
||||||
|
|
||||||
|
CSVRender::WorldspaceWidget::WorldspaceWidget (QWidget *parent)
|
||||||
|
: SceneWidget (parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
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::selectDefaultNavigationMode()
|
||||||
|
{
|
||||||
|
setNavigation (&m1st);
|
||||||
|
}
|
||||||
|
|
||||||
|
CSVWorld::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector (
|
||||||
|
CSVWorld::SceneToolbar *parent)
|
||||||
|
{
|
||||||
|
CSVWorld::SceneToolMode *tool = new CSVWorld::SceneToolMode (parent);
|
||||||
|
|
||||||
|
tool->addButton (":door.png", "1st"); /// \todo replace icons
|
||||||
|
tool->addButton (":GMST.png", "free");
|
||||||
|
tool->addButton (":Info.png", "orbit");
|
||||||
|
|
||||||
|
connect (tool, SIGNAL (modeChanged (const std::string&)),
|
||||||
|
this, SLOT (selectNavigationMode (const std::string&)));
|
||||||
|
|
||||||
|
return tool;
|
||||||
|
}
|
46
apps/opencs/view/render/worldspacewidget.hpp
Normal file
46
apps/opencs/view/render/worldspacewidget.hpp
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#ifndef OPENCS_VIEW_WORLDSPACEWIDGET_H
|
||||||
|
#define OPENCS_VIEW_WORLDSPACEWIDGET_H
|
||||||
|
|
||||||
|
#include "scenewidget.hpp"
|
||||||
|
|
||||||
|
#include "navigation1st.hpp"
|
||||||
|
#include "navigationfree.hpp"
|
||||||
|
#include "navigationorbit.hpp"
|
||||||
|
|
||||||
|
namespace CSVWorld
|
||||||
|
{
|
||||||
|
class SceneToolMode;
|
||||||
|
class SceneToolbar;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
class WorldspaceWidget : public SceneWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
CSVRender::Navigation1st m1st;
|
||||||
|
CSVRender::NavigationFree mFree;
|
||||||
|
CSVRender::NavigationOrbit mOrbit;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
WorldspaceWidget (QWidget *parent = 0);
|
||||||
|
|
||||||
|
CSVWorld::SceneToolMode *makeNavigationSelector (CSVWorld::SceneToolbar *parent);
|
||||||
|
///< \important The created tool is not added to the toolbar (via addTool). Doing that
|
||||||
|
/// is the responsibility of the calling function.
|
||||||
|
|
||||||
|
void selectDefaultNavigationMode();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void selectNavigationMode (const std::string& mode);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void closeRequest();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -40,5 +40,5 @@ void CSVTools::ReportSubView::updateEditorSetting (const QString& key, const QSt
|
||||||
|
|
||||||
void CSVTools::ReportSubView::show (const QModelIndex& index)
|
void CSVTools::ReportSubView::show (const QModelIndex& index)
|
||||||
{
|
{
|
||||||
focusId (mModel->getUniversalId (index.row()));
|
focusId (mModel->getUniversalId (index.row()), "");
|
||||||
}
|
}
|
|
@ -9,7 +9,8 @@
|
||||||
|
|
||||||
#include "../filter/filterbox.hpp"
|
#include "../filter/filterbox.hpp"
|
||||||
|
|
||||||
#include "../render/scenewidget.hpp"
|
#include "../render/pagedworldspacewidget.hpp"
|
||||||
|
#include "../render/unpagedworldspacewidget.hpp"
|
||||||
|
|
||||||
#include "tablebottombox.hpp"
|
#include "tablebottombox.hpp"
|
||||||
#include "creator.hpp"
|
#include "creator.hpp"
|
||||||
|
@ -32,37 +33,20 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::D
|
||||||
layout2->setContentsMargins (QMargins (0, 0, 0, 0));
|
layout2->setContentsMargins (QMargins (0, 0, 0, 0));
|
||||||
|
|
||||||
SceneToolbar *toolbar = new SceneToolbar (48, this);
|
SceneToolbar *toolbar = new SceneToolbar (48, this);
|
||||||
// test
|
|
||||||
SceneToolMode *tool = new SceneToolMode (toolbar);
|
if (id.getId()[0]=='#')
|
||||||
tool->addButton (":door.png", "a");
|
mScene = new CSVRender::PagedWorldspaceWidget (this);
|
||||||
tool->addButton (":GMST.png", "b");
|
else
|
||||||
tool->addButton (":Info.png", "c");
|
mScene = new CSVRender::UnpagedWorldspaceWidget (id.getId(), document, this);
|
||||||
|
|
||||||
|
SceneToolMode *tool = mScene->makeNavigationSelector (toolbar);
|
||||||
toolbar->addTool (tool);
|
toolbar->addTool (tool);
|
||||||
toolbar->addTool (new SceneToolMode (toolbar));
|
|
||||||
toolbar->addTool (new SceneToolMode (toolbar));
|
|
||||||
toolbar->addTool (new SceneToolMode (toolbar));
|
|
||||||
layout2->addWidget (toolbar, 0);
|
layout2->addWidget (toolbar, 0);
|
||||||
|
|
||||||
// temporarily disable OGRE-integration (need to fix path problem first)
|
layout2->addWidget (mScene, 1);
|
||||||
#if 0
|
|
||||||
CSVRender::SceneWidget* sceneWidget = new CSVRender::SceneWidget(this);
|
|
||||||
|
|
||||||
layout2->addWidget (sceneWidget, 1);
|
|
||||||
|
|
||||||
layout->insertLayout (0, layout2, 1);
|
layout->insertLayout (0, layout2, 1);
|
||||||
#endif
|
|
||||||
/// \todo replace with rendering widget
|
|
||||||
QPalette palette2 (palette());
|
|
||||||
palette2.setColor (QPalette::Background, Qt::white);
|
|
||||||
QLabel *placeholder = new QLabel ("Here goes the 3D scene", this);
|
|
||||||
placeholder->setAutoFillBackground (true);
|
|
||||||
placeholder->setPalette (palette2);
|
|
||||||
placeholder->setAlignment (Qt::AlignHCenter);
|
|
||||||
|
|
||||||
layout2->addWidget (placeholder, 1);
|
|
||||||
|
|
||||||
layout->insertLayout (0, layout2, 1);
|
|
||||||
|
|
||||||
|
|
||||||
CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this);
|
CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this);
|
||||||
|
|
||||||
|
@ -73,6 +57,10 @@ toolbar->addTool (new SceneToolMode (toolbar));
|
||||||
widget->setLayout (layout);
|
widget->setLayout (layout);
|
||||||
|
|
||||||
setWidget (widget);
|
setWidget (widget);
|
||||||
|
|
||||||
|
mScene->selectDefaultNavigationMode();
|
||||||
|
|
||||||
|
connect (mScene, SIGNAL (closeRequest()), this, SLOT (closeRequest()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::SceneSubView::setEditLock (bool locked)
|
void CSVWorld::SceneSubView::setEditLock (bool locked)
|
||||||
|
@ -91,3 +79,8 @@ void CSVWorld::SceneSubView::setStatusBar (bool show)
|
||||||
{
|
{
|
||||||
mBottom->setStatusBar (show);
|
mBottom->setStatusBar (show);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVWorld::SceneSubView::closeRequest()
|
||||||
|
{
|
||||||
|
deleteLater();
|
||||||
|
}
|
|
@ -10,6 +10,11 @@ namespace CSMDoc
|
||||||
class Document;
|
class Document;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
class WorldspaceWidget;
|
||||||
|
}
|
||||||
|
|
||||||
namespace CSVWorld
|
namespace CSVWorld
|
||||||
{
|
{
|
||||||
class Table;
|
class Table;
|
||||||
|
@ -21,6 +26,7 @@ namespace CSVWorld
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
TableBottomBox *mBottom;
|
TableBottomBox *mBottom;
|
||||||
|
CSVRender::WorldspaceWidget *mScene;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -31,6 +37,10 @@ namespace CSVWorld
|
||||||
virtual void updateEditorSetting (const QString& key, const QString& value);
|
virtual void updateEditorSetting (const QString& key, const QString& value);
|
||||||
|
|
||||||
virtual void setStatusBar (bool show);
|
virtual void setStatusBar (bool show);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void closeRequest();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#include "table.hpp"
|
#include "table.hpp"
|
||||||
|
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
@ -10,6 +9,8 @@
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QtCore/qnamespace.h>
|
#include <QtCore/qnamespace.h>
|
||||||
|
|
||||||
|
#include "../../model/doc/document.hpp"
|
||||||
|
|
||||||
#include "../../model/world/data.hpp"
|
#include "../../model/world/data.hpp"
|
||||||
#include "../../model/world/commands.hpp"
|
#include "../../model/world/commands.hpp"
|
||||||
#include "../../model/world/idtableproxymodel.hpp"
|
#include "../../model/world/idtableproxymodel.hpp"
|
||||||
|
@ -35,8 +36,21 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
|
||||||
if (selectedRows.size()==1)
|
if (selectedRows.size()==1)
|
||||||
{
|
{
|
||||||
menu.addAction (mEditAction);
|
menu.addAction (mEditAction);
|
||||||
|
|
||||||
if (mCreateAction)
|
if (mCreateAction)
|
||||||
menu.addAction(mCloneAction);
|
menu.addAction(mCloneAction);
|
||||||
|
|
||||||
|
if (mModel->getViewing()!=CSMWorld::IdTable::Viewing_None)
|
||||||
|
{
|
||||||
|
int row = selectedRows.begin()->row();
|
||||||
|
|
||||||
|
row = mProxyModel->mapToSource (mProxyModel->index (row, 0)).row();
|
||||||
|
|
||||||
|
CSMWorld::UniversalId id = mModel->view (row).first;
|
||||||
|
|
||||||
|
if (!mDocument.getData().getCells().getRecord (id.getId()).isDeleted())
|
||||||
|
menu.addAction (mViewAction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mCreateAction)
|
if (mCreateAction)
|
||||||
|
@ -162,11 +176,12 @@ std::vector<std::string> CSVWorld::Table::listDeletableSelectedIds() const
|
||||||
return deletableIds;
|
return deletableIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack,
|
CSVWorld::Table::Table (const CSMWorld::UniversalId& id,
|
||||||
bool createAndDelete, bool sorting, const CSMDoc::Document& document)
|
bool createAndDelete, bool sorting, CSMDoc::Document& document)
|
||||||
: mUndoStack (undoStack), mCreateAction (0), mCloneAction(0), mEditLock (false), mRecordStatusDisplay (0), mDocument(document)
|
: mCreateAction (0), mCloneAction(0), mEditLock (false), mRecordStatusDisplay (0),
|
||||||
|
mDocument (document)
|
||||||
{
|
{
|
||||||
mModel = &dynamic_cast<CSMWorld::IdTable&> (*data.getTableModel (id));
|
mModel = &dynamic_cast<CSMWorld::IdTable&> (*mDocument.getData().getTableModel (id));
|
||||||
|
|
||||||
mProxyModel = new CSMWorld::IdTableProxyModel (this);
|
mProxyModel = new CSMWorld::IdTableProxyModel (this);
|
||||||
mProxyModel->setSourceModel (mModel);
|
mProxyModel->setSourceModel (mModel);
|
||||||
|
@ -190,7 +205,7 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q
|
||||||
mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt());
|
mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt());
|
||||||
|
|
||||||
CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate (display,
|
CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate (display,
|
||||||
undoStack, this);
|
mDocument.getUndoStack(), this);
|
||||||
|
|
||||||
mDelegates.push_back (delegate);
|
mDelegates.push_back (delegate);
|
||||||
setItemDelegateForColumn (i, delegate);
|
setItemDelegateForColumn (i, delegate);
|
||||||
|
@ -230,6 +245,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q
|
||||||
connect (mMoveDownAction, SIGNAL (triggered()), this, SLOT (moveDownRecord()));
|
connect (mMoveDownAction, SIGNAL (triggered()), this, SLOT (moveDownRecord()));
|
||||||
addAction (mMoveDownAction);
|
addAction (mMoveDownAction);
|
||||||
|
|
||||||
|
mViewAction = new QAction (tr ("View"), this);
|
||||||
|
connect (mViewAction, SIGNAL (triggered()), this, SLOT (viewRecord()));
|
||||||
|
addAction (mViewAction);
|
||||||
|
|
||||||
connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
|
connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
|
||||||
this, SLOT (tableSizeUpdate()));
|
this, SLOT (tableSizeUpdate()));
|
||||||
|
|
||||||
|
@ -268,13 +287,13 @@ void CSVWorld::Table::revertRecord()
|
||||||
if (revertableIds.size()>0)
|
if (revertableIds.size()>0)
|
||||||
{
|
{
|
||||||
if (revertableIds.size()>1)
|
if (revertableIds.size()>1)
|
||||||
mUndoStack.beginMacro (tr ("Revert multiple records"));
|
mDocument.getUndoStack().beginMacro (tr ("Revert multiple records"));
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator iter (revertableIds.begin()); iter!=revertableIds.end(); ++iter)
|
for (std::vector<std::string>::const_iterator iter (revertableIds.begin()); iter!=revertableIds.end(); ++iter)
|
||||||
mUndoStack.push (new CSMWorld::RevertCommand (*mModel, *iter));
|
mDocument.getUndoStack().push (new CSMWorld::RevertCommand (*mModel, *iter));
|
||||||
|
|
||||||
if (revertableIds.size()>1)
|
if (revertableIds.size()>1)
|
||||||
mUndoStack.endMacro();
|
mDocument.getUndoStack().endMacro();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -288,13 +307,13 @@ void CSVWorld::Table::deleteRecord()
|
||||||
if (deletableIds.size()>0)
|
if (deletableIds.size()>0)
|
||||||
{
|
{
|
||||||
if (deletableIds.size()>1)
|
if (deletableIds.size()>1)
|
||||||
mUndoStack.beginMacro (tr ("Delete multiple records"));
|
mDocument.getUndoStack().beginMacro (tr ("Delete multiple records"));
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator iter (deletableIds.begin()); iter!=deletableIds.end(); ++iter)
|
for (std::vector<std::string>::const_iterator iter (deletableIds.begin()); iter!=deletableIds.end(); ++iter)
|
||||||
mUndoStack.push (new CSMWorld::DeleteCommand (*mModel, *iter));
|
mDocument.getUndoStack().push (new CSMWorld::DeleteCommand (*mModel, *iter));
|
||||||
|
|
||||||
if (deletableIds.size()>1)
|
if (deletableIds.size()>1)
|
||||||
mUndoStack.endMacro();
|
mDocument.getUndoStack().endMacro();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -306,7 +325,7 @@ void CSVWorld::Table::editRecord()
|
||||||
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||||
|
|
||||||
if (selectedRows.size()==1)
|
if (selectedRows.size()==1)
|
||||||
emit editRequest (selectedRows.begin()->row());
|
emit editRequest (getUniversalId (selectedRows.begin()->row()), "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,7 +366,7 @@ void CSVWorld::Table::moveUpRecord()
|
||||||
for (int i=1; i<row2-row; ++i)
|
for (int i=1; i<row2-row; ++i)
|
||||||
newOrder[i] = i;
|
newOrder[i] = i;
|
||||||
|
|
||||||
mUndoStack.push (new CSMWorld::ReorderRowsCommand (*mModel, row, newOrder));
|
mDocument.getUndoStack().push (new CSMWorld::ReorderRowsCommand (*mModel, row, newOrder));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -376,11 +395,28 @@ void CSVWorld::Table::moveDownRecord()
|
||||||
for (int i=1; i<row2-row; ++i)
|
for (int i=1; i<row2-row; ++i)
|
||||||
newOrder[i] = i;
|
newOrder[i] = i;
|
||||||
|
|
||||||
mUndoStack.push (new CSMWorld::ReorderRowsCommand (*mModel, row, newOrder));
|
mDocument.getUndoStack().push (new CSMWorld::ReorderRowsCommand (*mModel, row, newOrder));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVWorld::Table::viewRecord()
|
||||||
|
{
|
||||||
|
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||||
|
|
||||||
|
if (selectedRows.size()==1)
|
||||||
|
{
|
||||||
|
int row =selectedRows.begin()->row();
|
||||||
|
|
||||||
|
row = mProxyModel->mapToSource (mProxyModel->index (row, 0)).row();
|
||||||
|
|
||||||
|
std::pair<CSMWorld::UniversalId, std::string> params = mModel->view (row);
|
||||||
|
|
||||||
|
if (params.first.getType()!=CSMWorld::UniversalId::Type_None)
|
||||||
|
emit editRequest (params.first, params.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CSVWorld::Table::updateEditorSetting (const QString &settingName, const QString &settingValue)
|
void CSVWorld::Table::updateEditorSetting (const QString &settingName, const QString &settingValue)
|
||||||
{
|
{
|
||||||
int columns = mModel->columnCount();
|
int columns = mModel->columnCount();
|
||||||
|
@ -517,7 +553,7 @@ void CSVWorld::Table::dropEvent(QDropEvent *event)
|
||||||
std::auto_ptr<CSMWorld::ModifyCommand> command (new CSMWorld::ModifyCommand
|
std::auto_ptr<CSMWorld::ModifyCommand> command (new CSMWorld::ModifyCommand
|
||||||
(*mProxyModel, index, QVariant (QString::fromUtf8 (record.getId().c_str()))));
|
(*mProxyModel, index, QVariant (QString::fromUtf8 (record.getId().c_str()))));
|
||||||
|
|
||||||
mUndoStack.push (command.release());
|
mDocument.getUndoStack().push (command.release());
|
||||||
}
|
}
|
||||||
} //TODO handle drops from different document
|
} //TODO handle drops from different document
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,14 @@
|
||||||
#include "../../model/filter/node.hpp"
|
#include "../../model/filter/node.hpp"
|
||||||
#include "../../model/world/columnbase.hpp"
|
#include "../../model/world/columnbase.hpp"
|
||||||
|
|
||||||
namespace CSMDoc {
|
|
||||||
class Document;
|
|
||||||
}
|
|
||||||
|
|
||||||
class QUndoStack;
|
class QUndoStack;
|
||||||
class QAction;
|
class QAction;
|
||||||
|
|
||||||
|
namespace CSMDoc
|
||||||
|
{
|
||||||
|
class Document;
|
||||||
|
}
|
||||||
|
|
||||||
namespace CSMWorld
|
namespace CSMWorld
|
||||||
{
|
{
|
||||||
class Data;
|
class Data;
|
||||||
|
@ -35,7 +36,6 @@ namespace CSVWorld
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
std::vector<CommandDelegate *> mDelegates;
|
std::vector<CommandDelegate *> mDelegates;
|
||||||
QUndoStack& mUndoStack;
|
|
||||||
QAction *mEditAction;
|
QAction *mEditAction;
|
||||||
QAction *mCreateAction;
|
QAction *mCreateAction;
|
||||||
QAction *mCloneAction;
|
QAction *mCloneAction;
|
||||||
|
@ -43,14 +43,12 @@ namespace CSVWorld
|
||||||
QAction *mDeleteAction;
|
QAction *mDeleteAction;
|
||||||
QAction *mMoveUpAction;
|
QAction *mMoveUpAction;
|
||||||
QAction *mMoveDownAction;
|
QAction *mMoveDownAction;
|
||||||
|
QAction *mViewAction;
|
||||||
CSMWorld::IdTableProxyModel *mProxyModel;
|
CSMWorld::IdTableProxyModel *mProxyModel;
|
||||||
CSMWorld::IdTable *mModel;
|
CSMWorld::IdTable *mModel;
|
||||||
bool mEditLock;
|
bool mEditLock;
|
||||||
int mRecordStatusDisplay;
|
int mRecordStatusDisplay;
|
||||||
|
CSMDoc::Document& mDocument;
|
||||||
/// \brief This variable is used exclusivly for checking if dropEvents came from the same document. Most likely you
|
|
||||||
/// should NOT use it for anything else.
|
|
||||||
const CSMDoc::Document& mDocument;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -70,9 +68,8 @@ namespace CSVWorld
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, bool createAndDelete,
|
Table (const CSMWorld::UniversalId& id, bool createAndDelete,
|
||||||
bool sorting, const CSMDoc::Document& document);
|
bool sorting, CSMDoc::Document& document);
|
||||||
|
|
||||||
///< \param createAndDelete Allow creation and deletion of records.
|
///< \param createAndDelete Allow creation and deletion of records.
|
||||||
/// \param sorting Allow changing order of rows in the view via column headers.
|
/// \param sorting Allow changing order of rows in the view via column headers.
|
||||||
|
|
||||||
|
@ -86,7 +83,7 @@ namespace CSVWorld
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void editRequest (int row);
|
void editRequest (const CSMWorld::UniversalId& id, const std::string& hint);
|
||||||
|
|
||||||
void selectionSizeChanged (int size);
|
void selectionSizeChanged (int size);
|
||||||
|
|
||||||
|
@ -112,6 +109,8 @@ namespace CSVWorld
|
||||||
|
|
||||||
void moveDownRecord();
|
void moveDownRecord();
|
||||||
|
|
||||||
|
void viewRecord();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void tableSizeUpdate();
|
void tableSizeUpdate();
|
||||||
|
|
|
@ -24,7 +24,7 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D
|
||||||
new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), id, this), 0);
|
new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), id, this), 0);
|
||||||
|
|
||||||
layout->insertWidget (0, mTable =
|
layout->insertWidget (0, mTable =
|
||||||
new Table (id, document.getData(), document.getUndoStack(), mBottom->canCreateAndDelete(), sorting, document), 2);
|
new Table (id, mBottom->canCreateAndDelete(), sorting, document), 2);
|
||||||
|
|
||||||
CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this);
|
CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this);
|
||||||
|
|
||||||
|
@ -36,7 +36,8 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D
|
||||||
|
|
||||||
setWidget (widget);
|
setWidget (widget);
|
||||||
|
|
||||||
connect (mTable, SIGNAL (editRequest (int)), this, SLOT (editRequest (int)));
|
connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)),
|
||||||
|
this, SLOT (editRequest (const CSMWorld::UniversalId&, const std::string&)));
|
||||||
|
|
||||||
connect (mTable, SIGNAL (selectionSizeChanged (int)),
|
connect (mTable, SIGNAL (selectionSizeChanged (int)),
|
||||||
mBottom, SLOT (selectionSizeChanged (int)));
|
mBottom, SLOT (selectionSizeChanged (int)));
|
||||||
|
@ -81,9 +82,9 @@ void CSVWorld::TableSubView::setEditLock (bool locked)
|
||||||
mBottom->setEditLock (locked);
|
mBottom->setEditLock (locked);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::TableSubView::editRequest (int row)
|
void CSVWorld::TableSubView::editRequest (const CSMWorld::UniversalId& id, const std::string& hint)
|
||||||
{
|
{
|
||||||
focusId (mTable->getUniversalId (row));
|
focusId (id, hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::TableSubView::updateEditorSetting(const QString &settingName, const QString &settingValue)
|
void CSVWorld::TableSubView::updateEditorSetting(const QString &settingName, const QString &settingValue)
|
||||||
|
|
|
@ -53,7 +53,7 @@ namespace CSVWorld
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void editRequest (int row);
|
void editRequest (const CSMWorld::UniversalId& id, const std::string& hint);
|
||||||
void cloneRequest (const CSMWorld::UniversalId& toClone);
|
void cloneRequest (const CSMWorld::UniversalId& toClone);
|
||||||
void createFilterRequest(std::vector< CSMWorld::UniversalId >& types,
|
void createFilterRequest(std::vector< CSMWorld::UniversalId >& types,
|
||||||
Qt::DropAction action);
|
Qt::DropAction action);
|
||||||
|
|
|
@ -15,7 +15,7 @@ add_openmw_dir (mwrender
|
||||||
renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation
|
renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation
|
||||||
actors objects renderinginterface localmap occlusionquery water shadows
|
actors objects renderinginterface localmap occlusionquery water shadows
|
||||||
characterpreview globalmap videoplayer ripplesimulation refraction
|
characterpreview globalmap videoplayer ripplesimulation refraction
|
||||||
terrainstorage renderconst effectmanager
|
terrainstorage renderconst effectmanager weaponanimation
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwinput
|
add_openmw_dir (mwinput
|
||||||
|
@ -159,3 +159,10 @@ if (BUILD_WITH_CODE_COVERAGE)
|
||||||
add_definitions (--coverage)
|
add_definitions (--coverage)
|
||||||
target_link_libraries(openmw gcov)
|
target_link_libraries(openmw gcov)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
# Debug version needs increased number of sections beyond 2^16
|
||||||
|
if (CMAKE_CL_64)
|
||||||
|
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj")
|
||||||
|
endif (CMAKE_CL_64)
|
||||||
|
endif (MSVC)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "engine.hpp"
|
#include "engine.hpp"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
#include <OgreRoot.h>
|
#include <OgreRoot.h>
|
||||||
#include <OgreRenderWindow.h>
|
#include <OgreRenderWindow.h>
|
||||||
|
@ -403,7 +404,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
// Create the world
|
// Create the world
|
||||||
mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mContentFiles,
|
mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mContentFiles,
|
||||||
mResDir, mCfgMgr.getCachePath(), mEncoder, mFallbackMap,
|
mResDir, mCfgMgr.getCachePath(), mEncoder, mFallbackMap,
|
||||||
mActivationDistanceOverride));
|
mActivationDistanceOverride, mCellName));
|
||||||
MWBase::Environment::get().getWorld()->setupPlayer();
|
MWBase::Environment::get().getWorld()->setupPlayer();
|
||||||
input->setPlayer(&mEnvironment.getWorld()->getPlayer());
|
input->setPlayer(&mEnvironment.getWorld()->getPlayer());
|
||||||
|
|
||||||
|
@ -439,31 +440,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
mechanics->buildPlayer();
|
mechanics->buildPlayer();
|
||||||
window->updatePlayer();
|
window->updatePlayer();
|
||||||
|
|
||||||
// load cell
|
|
||||||
ESM::Position pos;
|
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
|
||||||
|
|
||||||
if (!mCellName.empty())
|
|
||||||
{
|
|
||||||
if (world->findExteriorPosition(mCellName, pos)) {
|
|
||||||
world->changeToExteriorCell (pos);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
world->findInteriorPosition(mCellName, pos);
|
|
||||||
world->changeToInteriorCell (mCellName, pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pos.pos[0] = pos.pos[1] = pos.pos[2] = 0;
|
|
||||||
pos.rot[0] = pos.rot[1] = pos.pos[2] = 0;
|
|
||||||
world->changeToExteriorCell (pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ogre::FrameEvent event;
|
|
||||||
event.timeSinceLastEvent = 0;
|
|
||||||
event.timeSinceLastFrame = 0;
|
|
||||||
frameRenderingQueued(event);
|
|
||||||
mOgre->getRoot()->addFrameListener (this);
|
mOgre->getRoot()->addFrameListener (this);
|
||||||
|
|
||||||
// scripts
|
// scripts
|
||||||
|
@ -501,15 +477,15 @@ void OMW::Engine::go()
|
||||||
// Play some good 'ol tunes
|
// Play some good 'ol tunes
|
||||||
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
|
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
|
||||||
|
|
||||||
if (!mStartupScript.empty())
|
|
||||||
MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript);
|
|
||||||
|
|
||||||
// start in main menu
|
// start in main menu
|
||||||
if (!mSkipMenu)
|
if (!mSkipMenu)
|
||||||
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
||||||
else
|
else
|
||||||
MWBase::Environment::get().getStateManager()->newGame (true);
|
MWBase::Environment::get().getStateManager()->newGame (true);
|
||||||
|
|
||||||
|
if (!mStartupScript.empty())
|
||||||
|
MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript);
|
||||||
|
|
||||||
// Start the main rendering loop
|
// Start the main rendering loop
|
||||||
while (!mEnvironment.get().getStateManager()->hasQuitRequest())
|
while (!mEnvironment.get().getStateManager()->hasQuitRequest())
|
||||||
Ogre::Root::getSingleton().renderOneFrame();
|
Ogre::Root::getSingleton().renderOneFrame();
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <libs/platform/stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,6 +20,9 @@ namespace MWBase
|
||||||
|
|
||||||
InputManager() {}
|
InputManager() {}
|
||||||
|
|
||||||
|
/// Clear all savegame-specific data
|
||||||
|
virtual void clear() = 0;
|
||||||
|
|
||||||
virtual ~InputManager() {}
|
virtual ~InputManager() {}
|
||||||
|
|
||||||
virtual void update(float dt, bool loading) = 0;
|
virtual void update(float dt, bool loading) = 0;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include <libs/platform/stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "../mwdialogue/journalentry.hpp"
|
#include "../mwdialogue/journalentry.hpp"
|
||||||
#include "../mwdialogue/topic.hpp"
|
#include "../mwdialogue/topic.hpp"
|
||||||
|
|
|
@ -101,7 +101,8 @@ namespace MWBase
|
||||||
|
|
||||||
virtual ~World() {}
|
virtual ~World() {}
|
||||||
|
|
||||||
virtual void startNewGame() = 0;
|
virtual void startNewGame (bool bypass) = 0;
|
||||||
|
///< \param bypass Bypass regular game start.
|
||||||
|
|
||||||
virtual void clear() = 0;
|
virtual void clear() = 0;
|
||||||
|
|
||||||
|
@ -274,7 +275,7 @@ namespace MWBase
|
||||||
virtual void moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0;
|
virtual void moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0;
|
||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore &newCell, float x, float y, float z) = 0;
|
moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, float x, float y, float z) = 0;
|
||||||
|
|
||||||
virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0;
|
virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0;
|
||||||
|
|
||||||
|
@ -282,7 +283,7 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void localRotateObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0;
|
virtual void localRotateObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0;
|
||||||
|
|
||||||
virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) = 0;
|
virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos) = 0;
|
||||||
///< place an object in a "safe" location (ie not in the void, etc).
|
///< place an object in a "safe" location (ie not in the void, etc).
|
||||||
|
|
||||||
virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false)
|
virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false)
|
||||||
|
@ -464,8 +465,10 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void castSpell (const MWWorld::Ptr& actor) = 0;
|
virtual void castSpell (const MWWorld::Ptr& actor) = 0;
|
||||||
|
|
||||||
virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
|
virtual void launchMagicBolt (const std::string& id, bool stack, const ESM::EffectList& effects,
|
||||||
const MWWorld::Ptr& actor, const std::string& sourceName) = 0;
|
const MWWorld::Ptr& actor, const std::string& sourceName) = 0;
|
||||||
|
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile,
|
||||||
|
const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed) = 0;
|
||||||
|
|
||||||
virtual const std::vector<std::string>& getContentFiles() const = 0;
|
virtual const std::vector<std::string>& getContentFiles() const = 0;
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "../mwmechanics/creaturestats.hpp"
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
#include "../mwmechanics/magiceffects.hpp"
|
#include "../mwmechanics/magiceffects.hpp"
|
||||||
#include "../mwmechanics/movement.hpp"
|
#include "../mwmechanics/movement.hpp"
|
||||||
|
#include "../mwmechanics/disease.hpp"
|
||||||
#include "../mwmechanics/spellcasting.hpp"
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
@ -243,15 +244,7 @@ namespace MWClass
|
||||||
|
|
||||||
Ogre::Vector3 hitPosition = result.second;
|
Ogre::Vector3 hitPosition = result.second;
|
||||||
|
|
||||||
MWMechanics::CreatureStats &otherstats = victim.getClass().getCreatureStats(victim);
|
float hitchance = MWMechanics::getHitChance(ptr, victim, ref->mBase->mData.mCombat);
|
||||||
const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects();
|
|
||||||
float hitchance = ref->mBase->mData.mCombat +
|
|
||||||
(stats.getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) +
|
|
||||||
(stats.getAttribute(ESM::Attribute::Luck).getModified() / 10.0f);
|
|
||||||
hitchance *= stats.getFatigueTerm();
|
|
||||||
hitchance += mageffects.get(ESM::MagicEffect::FortifyAttack).mMagnitude -
|
|
||||||
mageffects.get(ESM::MagicEffect::Blind).mMagnitude;
|
|
||||||
hitchance -= otherstats.getEvasion();
|
|
||||||
|
|
||||||
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
|
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
|
||||||
{
|
{
|
||||||
|
@ -334,6 +327,8 @@ namespace MWClass
|
||||||
if (damage > 0)
|
if (damage > 0)
|
||||||
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
||||||
|
|
||||||
|
MWMechanics::diseaseContact(victim, ptr);
|
||||||
|
|
||||||
victim.getClass().onHit(victim, damage, true, weapon, ptr, true);
|
victim.getClass().onHit(victim, damage, true, weapon, ptr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,7 +525,7 @@ namespace MWClass
|
||||||
float moveSpeed;
|
float moveSpeed;
|
||||||
if(normalizedEncumbrance >= 1.0f)
|
if(normalizedEncumbrance >= 1.0f)
|
||||||
moveSpeed = 0.0f;
|
moveSpeed = 0.0f;
|
||||||
else if(isFlying(ptr) || (mageffects.get(ESM::MagicEffect::Levitate).mMagnitude > 0 &&
|
else if(canFly(ptr) || (mageffects.get(ESM::MagicEffect::Levitate).mMagnitude > 0 &&
|
||||||
world->isLevitationEnabled()))
|
world->isLevitationEnabled()))
|
||||||
{
|
{
|
||||||
float flySpeed = 0.01f*(stats.getAttribute(ESM::Attribute::Speed).getModified() +
|
float flySpeed = 0.01f*(stats.getAttribute(ESM::Attribute::Speed).getModified() +
|
||||||
|
@ -683,7 +678,15 @@ namespace MWClass
|
||||||
return MWWorld::Ptr(&cell.get<ESM::Creature>().insert(*ref), &cell);
|
return MWWorld::Ptr(&cell.get<ESM::Creature>().insert(*ref), &cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Creature::isFlying(const MWWorld::Ptr &ptr) const
|
bool Creature::isBipedal(const MWWorld::Ptr &ptr) const
|
||||||
|
{
|
||||||
|
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||||
|
ptr.get<ESM::Creature>();
|
||||||
|
|
||||||
|
return ref->mBase->mFlags & ESM::Creature::Bipedal;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Creature::canFly(const MWWorld::Ptr &ptr) const
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||||
ptr.get<ESM::Creature>();
|
ptr.get<ESM::Creature>();
|
||||||
|
@ -691,6 +694,22 @@ namespace MWClass
|
||||||
return ref->mBase->mFlags & ESM::Creature::Flies;
|
return ref->mBase->mFlags & ESM::Creature::Flies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Creature::canSwim(const MWWorld::Ptr &ptr) const
|
||||||
|
{
|
||||||
|
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||||
|
ptr.get<ESM::Creature>();
|
||||||
|
|
||||||
|
return ref->mBase->mFlags & ESM::Creature::Swims;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Creature::canWalk(const MWWorld::Ptr &ptr) const
|
||||||
|
{
|
||||||
|
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||||
|
ptr.get<ESM::Creature>();
|
||||||
|
|
||||||
|
return ref->mBase->mFlags & ESM::Creature::Walks;
|
||||||
|
}
|
||||||
|
|
||||||
int Creature::getSndGenTypeFromName(const MWWorld::Ptr &ptr, const std::string &name)
|
int Creature::getSndGenTypeFromName(const MWWorld::Ptr &ptr, const std::string &name)
|
||||||
{
|
{
|
||||||
if(name == "left")
|
if(name == "left")
|
||||||
|
|
|
@ -124,7 +124,10 @@ namespace MWClass
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool isFlying (const MWWorld::Ptr &ptr) const;
|
virtual bool isBipedal (const MWWorld::Ptr &ptr) const;
|
||||||
|
virtual bool canFly (const MWWorld::Ptr &ptr) const;
|
||||||
|
virtual bool canSwim (const MWWorld::Ptr &ptr) const;
|
||||||
|
virtual bool canWalk (const MWWorld::Ptr &ptr) const;
|
||||||
|
|
||||||
virtual int getSkill(const MWWorld::Ptr &ptr, int skill) const;
|
virtual int getSkill(const MWWorld::Ptr &ptr, int skill) const;
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ namespace MWClass
|
||||||
MWWorld::ManualRef ref(store, id);
|
MWWorld::ManualRef ref(store, id);
|
||||||
ref.getPtr().getCellRef().mPos = ptr.getCellRef().mPos;
|
ref.getPtr().getCellRef().mPos = ptr.getCellRef().mPos;
|
||||||
// TODO: hold on to this for respawn purposes later
|
// TODO: hold on to this for respawn purposes later
|
||||||
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(), *ptr.getCell() , ptr.getCellRef().mPos);
|
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(), ptr.getCell() , ptr.getCellRef().mPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr.getRefData().setCustomData(data.release());
|
ptr.getRefData().setCustomData(data.release());
|
||||||
|
|
|
@ -498,15 +498,7 @@ namespace MWClass
|
||||||
if(!weapon.isEmpty())
|
if(!weapon.isEmpty())
|
||||||
weapskill = get(weapon).getEquipmentSkill(weapon);
|
weapskill = get(weapon).getEquipmentSkill(weapon);
|
||||||
|
|
||||||
MWMechanics::NpcStats &stats = getNpcStats(ptr);
|
float hitchance = MWMechanics::getHitChance(ptr, victim, ptr.getClass().getSkill(ptr, weapskill));
|
||||||
const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects();
|
|
||||||
float hitchance = stats.getSkill(weapskill).getModified() +
|
|
||||||
(stats.getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) +
|
|
||||||
(stats.getAttribute(ESM::Attribute::Luck).getModified() / 10.0f);
|
|
||||||
hitchance *= stats.getFatigueTerm();
|
|
||||||
hitchance += mageffects.get(ESM::MagicEffect::FortifyAttack).mMagnitude -
|
|
||||||
mageffects.get(ESM::MagicEffect::Blind).mMagnitude;
|
|
||||||
hitchance -= otherstats.getEvasion();
|
|
||||||
|
|
||||||
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
|
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
|
||||||
{
|
{
|
||||||
|
@ -516,6 +508,7 @@ namespace MWClass
|
||||||
|
|
||||||
bool healthdmg;
|
bool healthdmg;
|
||||||
float damage = 0.0f;
|
float damage = 0.0f;
|
||||||
|
MWMechanics::NpcStats &stats = getNpcStats(ptr);
|
||||||
if(!weapon.isEmpty())
|
if(!weapon.isEmpty())
|
||||||
{
|
{
|
||||||
const bool weaphashealth = get(weapon).hasItemHealth(weapon);
|
const bool weaphashealth = get(weapon).hasItemHealth(weapon);
|
||||||
|
@ -615,6 +608,8 @@ namespace MWClass
|
||||||
if (healthdmg && damage > 0)
|
if (healthdmg && damage > 0)
|
||||||
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
||||||
|
|
||||||
|
MWMechanics::diseaseContact(victim, ptr);
|
||||||
|
|
||||||
othercls.onHit(victim, damage, healthdmg, weapon, ptr, true);
|
othercls.onHit(victim, damage, healthdmg, weapon, ptr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -648,9 +643,6 @@ namespace MWClass
|
||||||
ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1);
|
ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!attacker.isEmpty())
|
|
||||||
MWMechanics::diseaseContact(ptr, attacker);
|
|
||||||
|
|
||||||
if (damage > 0.0f && !object.isEmpty())
|
if (damage > 0.0f && !object.isEmpty())
|
||||||
MWMechanics::resistNormalWeapon(ptr, attacker, object, damage);
|
MWMechanics::resistNormalWeapon(ptr, attacker, object, damage);
|
||||||
|
|
||||||
|
@ -681,12 +673,7 @@ namespace MWClass
|
||||||
else
|
else
|
||||||
getCreatureStats(ptr).setHitRecovery(true); // Is this supposed to always occur?
|
getCreatureStats(ptr).setHitRecovery(true); // Is this supposed to always occur?
|
||||||
|
|
||||||
if(object.isEmpty())
|
|
||||||
{
|
|
||||||
if(ishealth)
|
if(ishealth)
|
||||||
damage /= std::min(1.0f + getArmorRating(ptr)/std::max(1.0f, damage), 4.0f);
|
|
||||||
}
|
|
||||||
else if(ishealth)
|
|
||||||
{
|
{
|
||||||
// Hit percentages:
|
// Hit percentages:
|
||||||
// cuirass = 30%
|
// cuirass = 30%
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include "MyGUI_TextureUtility.h"
|
#include "MyGUI_TextureUtility.h"
|
||||||
#include "MyGUI_FactoryManager.h"
|
#include "MyGUI_FactoryManager.h"
|
||||||
|
|
||||||
#include <platform/stdint.h>
|
#include <stdint.h>
|
||||||
#include <boost/function.hpp>
|
#include <boost/function.hpp>
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/make_shared.hpp>
|
#include <boost/make_shared.hpp>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "MyGUI_Widget.h"
|
#include "MyGUI_Widget.h"
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <platform/stdint.h>
|
#include <stdint.h>
|
||||||
#include <boost/function.hpp>
|
#include <boost/function.hpp>
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "enchantingdialog.hpp"
|
#include "enchantingdialog.hpp"
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
|
|
@ -604,15 +604,22 @@ namespace MWGui
|
||||||
mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop());
|
mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HUD::updateEnemyHealthBar()
|
||||||
|
{
|
||||||
|
MWMechanics::CreatureStats& stats = MWWorld::Class::get(mEnemy).getCreatureStats(mEnemy);
|
||||||
|
mEnemyHealth->setProgressRange(100);
|
||||||
|
// Health is usually cast to int before displaying. Actors die whenever they are < 1 health.
|
||||||
|
// Therefore any value < 1 should show as an empty health bar. We do the same in statswindow :)
|
||||||
|
mEnemyHealth->setProgressPosition(int(stats.getHealth().getCurrent()) / stats.getHealth().getModified() * 100);
|
||||||
|
}
|
||||||
|
|
||||||
void HUD::update()
|
void HUD::update()
|
||||||
{
|
{
|
||||||
mSpellIcons->updateWidgets(mEffectBox, true);
|
mSpellIcons->updateWidgets(mEffectBox, true);
|
||||||
|
|
||||||
if (!mEnemy.isEmpty() && mEnemyHealth->getVisible())
|
if (!mEnemy.isEmpty() && mEnemyHealth->getVisible())
|
||||||
{
|
{
|
||||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get(mEnemy).getCreatureStats(mEnemy);
|
updateEnemyHealthBar();
|
||||||
mEnemyHealth->setProgressRange(100);
|
|
||||||
mEnemyHealth->setProgressPosition(stats.getHealth().getCurrent() / stats.getHealth().getModified() * 100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mIsDrowning)
|
if (mIsDrowning)
|
||||||
|
@ -629,9 +636,7 @@ namespace MWGui
|
||||||
if (!mEnemyHealth->getVisible())
|
if (!mEnemyHealth->getVisible())
|
||||||
mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() - MyGUI::IntPoint(0,20));
|
mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() - MyGUI::IntPoint(0,20));
|
||||||
mEnemyHealth->setVisible(true);
|
mEnemyHealth->setVisible(true);
|
||||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get(mEnemy).getCreatureStats(mEnemy);
|
updateEnemyHealthBar();
|
||||||
mEnemyHealth->setProgressRange(100);
|
|
||||||
mEnemyHealth->setProgressPosition(stats.getHealth().getCurrent() / stats.getHealth().getModified() * 100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,6 +112,8 @@ namespace MWGui
|
||||||
void onMagicClicked(MyGUI::Widget* _sender);
|
void onMagicClicked(MyGUI::Widget* _sender);
|
||||||
void onMapClicked(MyGUI::Widget* _sender);
|
void onMapClicked(MyGUI::Widget* _sender);
|
||||||
|
|
||||||
|
void updateEnemyHealthBar();
|
||||||
|
|
||||||
void updatePositions();
|
void updatePositions();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -514,6 +514,9 @@ namespace MWGui
|
||||||
|
|
||||||
void InventoryWindow::pickUpObject (MWWorld::Ptr object)
|
void InventoryWindow::pickUpObject (MWWorld::Ptr object)
|
||||||
{
|
{
|
||||||
|
// If the inventory is not yet enabled, don't pick anything up
|
||||||
|
if (!MWBase::Environment::get().getWindowManager()->isAllowed(GW_Inventory))
|
||||||
|
return;
|
||||||
// make sure the object is of a type that can be picked up
|
// make sure the object is of a type that can be picked up
|
||||||
std::string type = object.getTypeName();
|
std::string type = object.getTypeName();
|
||||||
if ( (type != typeid(ESM::Apparatus).name())
|
if ( (type != typeid(ESM::Apparatus).name())
|
||||||
|
|
|
@ -206,9 +206,9 @@ struct JournalViewModelImpl : JournalViewModel
|
||||||
|
|
||||||
const MWDialogue::Quest& quest = i->second;
|
const MWDialogue::Quest& quest = i->second;
|
||||||
// Unfortunately Morrowind.esm has no quest names, since the quest book was added with tribunal.
|
// Unfortunately Morrowind.esm has no quest names, since the quest book was added with tribunal.
|
||||||
if (quest.getName().empty())
|
// Note that even with Tribunal, some quests still don't have quest names. I'm assuming those are not supposed
|
||||||
visitor (reinterpret_cast <QuestId> (&i->second), toUtf8Span (i->first));
|
// to appear in the quest book.
|
||||||
else
|
if (!quest.getName().empty())
|
||||||
visitor (reinterpret_cast <QuestId> (&i->second), toUtf8Span (quest.getName()));
|
visitor (reinterpret_cast <QuestId> (&i->second), toUtf8Span (quest.getName()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <platform/stdint.h>
|
#include <stdint.h>
|
||||||
#include <boost/function.hpp>
|
#include <boost/function.hpp>
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
#include "loadingscreen.hpp"
|
#include "loadingscreen.hpp"
|
||||||
|
|
||||||
#include <OgreRenderWindow.h>
|
#include <OgreRenderWindow.h>
|
||||||
|
#include <OgreMaterialManager.h>
|
||||||
|
#include <OgreTechnique.h>
|
||||||
|
#include <OgreRectangle2D.h>
|
||||||
|
#include <OgreSceneNode.h>
|
||||||
|
#include <OgreTextureManager.h>
|
||||||
|
#include <OgreViewport.h>
|
||||||
|
#include <OgreHardwarePixelBuffer.h>
|
||||||
|
|
||||||
#include <openengine/ogre/fader.hpp>
|
#include <openengine/ogre/fader.hpp>
|
||||||
|
|
||||||
|
@ -66,6 +73,10 @@ namespace MWGui
|
||||||
|
|
||||||
void LoadingScreen::loadingOn()
|
void LoadingScreen::loadingOn()
|
||||||
{
|
{
|
||||||
|
// Early-out if already on
|
||||||
|
if (mRectangle->getVisible())
|
||||||
|
return;
|
||||||
|
|
||||||
// Temporarily turn off VSync, we want to do actual loading rather than waiting for the screen to sync.
|
// 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.
|
// Threaded loading would be even better, of course - especially because some drivers force VSync to on and we can't change it.
|
||||||
// In Ogre 1.8, the swapBuffers argument is useless and setVSyncEnabled is bugged with GLX, nothing we can do :/
|
// In Ogre 1.8, the swapBuffers argument is useless and setVSyncEnabled is bugged with GLX, nothing we can do :/
|
||||||
|
@ -74,16 +85,36 @@ namespace MWGui
|
||||||
mWindow->setVSyncEnabled(false);
|
mWindow->setVSyncEnabled(false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (!mFirstLoad)
|
||||||
|
{
|
||||||
|
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())
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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->setImageTexture(texture->getName());
|
||||||
|
}
|
||||||
|
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
|
|
||||||
if (mFirstLoad)
|
if (mFirstLoad)
|
||||||
{
|
{
|
||||||
changeWallpaper();
|
changeWallpaper();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
mBackgroundImage->setImageTexture("");
|
|
||||||
}
|
|
||||||
|
|
||||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(mFirstLoad ? GM_LoadingWallpaper : GM_Loading);
|
MWBase::Environment::get().getWindowManager()->pushGuiMode(mFirstLoad ? GM_LoadingWallpaper : GM_Loading);
|
||||||
}
|
}
|
||||||
|
@ -197,8 +228,6 @@ namespace MWGui
|
||||||
|
|
||||||
MWBase::Environment::get().getInputManager()->update(0, true);
|
MWBase::Environment::get().getInputManager()->update(0, true);
|
||||||
|
|
||||||
mWindow->getViewport(0)->setClearEveryFrame(false);
|
|
||||||
|
|
||||||
// First, swap buffers from last draw, then, queue an update of the
|
// First, swap buffers from last draw, then, queue an update of the
|
||||||
// window contents, but don't swap buffers (which would have
|
// window contents, but don't swap buffers (which would have
|
||||||
// caused a sync / flush and would be expensive).
|
// caused a sync / flush and would be expensive).
|
||||||
|
@ -208,9 +237,6 @@ namespace MWGui
|
||||||
|
|
||||||
mWindow->update(false);
|
mWindow->update(false);
|
||||||
|
|
||||||
mWindow->getViewport(0)->setClearEveryFrame(true);
|
|
||||||
|
|
||||||
|
|
||||||
mRectangle->setVisible(false);
|
mRectangle->setVisible(false);
|
||||||
|
|
||||||
// resume 3d rendering
|
// resume 3d rendering
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define MWGUI_LOADINGSCREEN_H
|
#define MWGUI_LOADINGSCREEN_H
|
||||||
|
|
||||||
#include <OgreSceneManager.h>
|
#include <OgreSceneManager.h>
|
||||||
|
#include <OgreTimer.h>
|
||||||
|
|
||||||
#include "windowbase.hpp"
|
#include "windowbase.hpp"
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "mainmenu.hpp"
|
#include "mainmenu.hpp"
|
||||||
|
|
||||||
|
#include <components/version/version.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
@ -20,6 +22,22 @@ namespace MWGui
|
||||||
, mButtonBox(0), mWidth (w), mHeight (h)
|
, mButtonBox(0), mWidth (w), mHeight (h)
|
||||||
, mSaveGameDialog(NULL)
|
, mSaveGameDialog(NULL)
|
||||||
{
|
{
|
||||||
|
getWidget(mVersionText, "VersionText");
|
||||||
|
std::stringstream sstream;
|
||||||
|
sstream << "OpenMW version: " << OPENMW_VERSION;
|
||||||
|
|
||||||
|
// adding info about git hash if availible
|
||||||
|
std::string rev = OPENMW_VERSION_COMMITHASH;
|
||||||
|
std::string tag = OPENMW_VERSION_TAGHASH;
|
||||||
|
if (!rev.empty() && !tag.empty())
|
||||||
|
{
|
||||||
|
rev = rev.substr(0,10);
|
||||||
|
sstream << "\nrevision: " << rev;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string output = sstream.str();
|
||||||
|
mVersionText->setCaption(output);
|
||||||
|
|
||||||
updateMenu();
|
updateMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ namespace MWGui
|
||||||
private:
|
private:
|
||||||
|
|
||||||
MyGUI::Widget* mButtonBox;
|
MyGUI::Widget* mButtonBox;
|
||||||
|
MyGUI::TextBox* mVersionText;
|
||||||
|
|
||||||
std::map<std::string, MWGui::ImageButton*> mButtons;
|
std::map<std::string, MWGui::ImageButton*> mButtons;
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
#include <OgreSceneNode.h>
|
#include <OgreSceneNode.h>
|
||||||
|
#include <OgreVector2.h>
|
||||||
|
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef MWGUI_MAPWINDOW_H
|
#ifndef MWGUI_MAPWINDOW_H
|
||||||
#define MWGUI_MAPWINDOW_H
|
#define MWGUI_MAPWINDOW_H
|
||||||
|
|
||||||
#include <libs/platform/stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "windowpinnablebase.hpp"
|
#include "windowpinnablebase.hpp"
|
||||||
|
|
||||||
|
|
|
@ -41,9 +41,13 @@ namespace MWGui
|
||||||
getWidget(mPreviewImage, "PreviewImage");
|
getWidget(mPreviewImage, "PreviewImage");
|
||||||
|
|
||||||
getWidget(mHeadRotate, "HeadRotate");
|
getWidget(mHeadRotate, "HeadRotate");
|
||||||
mHeadRotate->setScrollRange(50);
|
|
||||||
mHeadRotate->setScrollPosition(25);
|
// Mouse wheel step is hardcoded to 50 in MyGUI 3.2 ("FIXME").
|
||||||
mHeadRotate->setScrollViewPage(10);
|
// Give other steps the same value to accomodate.
|
||||||
|
mHeadRotate->setScrollRange(1000);
|
||||||
|
mHeadRotate->setScrollPosition(500);
|
||||||
|
mHeadRotate->setScrollViewPage(50);
|
||||||
|
mHeadRotate->setScrollPage(50);
|
||||||
mHeadRotate->eventScrollChangePosition += MyGUI::newDelegate(this, &RaceDialog::onHeadRotate);
|
mHeadRotate->eventScrollChangePosition += MyGUI::newDelegate(this, &RaceDialog::onHeadRotate);
|
||||||
|
|
||||||
// Set up next/previous buttons
|
// Set up next/previous buttons
|
||||||
|
@ -171,9 +175,9 @@ namespace MWGui
|
||||||
eventBack();
|
eventBack();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RaceDialog::onHeadRotate(MyGUI::ScrollBar*, size_t _position)
|
void RaceDialog::onHeadRotate(MyGUI::ScrollBar* scroll, size_t _position)
|
||||||
{
|
{
|
||||||
float angle = (float(_position) / 49.f - 0.5) * 3.14 * 2;
|
float angle = (float(_position) / (scroll->getScrollRange()-1) - 0.5) * 3.14 * 2;
|
||||||
float diff = angle - mCurrentAngle;
|
float diff = angle - mCurrentAngle;
|
||||||
mPreview->update (diff);
|
mPreview->update (diff);
|
||||||
mPreviewDirty = true;
|
mPreviewDirty = true;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "repair.hpp"
|
#include "repair.hpp"
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "tooltips.hpp"
|
#include "tooltips.hpp"
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
|
||||||
|
#include <OgreTextureManager.h>
|
||||||
|
|
||||||
#include "MyGUI_UString.h"
|
#include "MyGUI_UString.h"
|
||||||
#include "MyGUI_IPointer.h"
|
#include "MyGUI_IPointer.h"
|
||||||
#include "MyGUI_ResourceImageSetPointer.h"
|
#include "MyGUI_ResourceImageSetPointer.h"
|
||||||
|
|
|
@ -143,6 +143,13 @@ namespace MWInput
|
||||||
mControlSwitch["vanitymode"] = true;
|
mControlSwitch["vanitymode"] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InputManager::clear()
|
||||||
|
{
|
||||||
|
// Enable all controls
|
||||||
|
for (std::map<std::string, bool>::iterator it = mControlSwitch.begin(); it != mControlSwitch.end(); ++it)
|
||||||
|
it->second = true;
|
||||||
|
}
|
||||||
|
|
||||||
InputManager::~InputManager()
|
InputManager::~InputManager()
|
||||||
{
|
{
|
||||||
mInputBinder->save (mUserFile);
|
mInputBinder->save (mUserFile);
|
||||||
|
@ -455,7 +462,7 @@ namespace MWInput
|
||||||
mInputBinder->adjustMouseRegion(width, height);
|
mInputBinder->adjustMouseRegion(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InputManager::keyPressed( const SDL_KeyboardEvent &arg )
|
void InputManager::keyPressed( const SDL_KeyboardEvent &arg )
|
||||||
{
|
{
|
||||||
// Cut, copy & paste
|
// Cut, copy & paste
|
||||||
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
|
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
|
||||||
|
@ -501,7 +508,6 @@ namespace MWInput
|
||||||
|
|
||||||
if (kc != OIS::KC_UNASSIGNED)
|
if (kc != OIS::KC_UNASSIGNED)
|
||||||
MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0);
|
MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputManager::textInput(const SDL_TextInputEvent &arg)
|
void InputManager::textInput(const SDL_TextInputEvent &arg)
|
||||||
|
@ -512,23 +518,21 @@ namespace MWInput
|
||||||
MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::None, *it);
|
MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::None, *it);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InputManager::keyReleased(const SDL_KeyboardEvent &arg )
|
void InputManager::keyReleased(const SDL_KeyboardEvent &arg )
|
||||||
{
|
{
|
||||||
mInputBinder->keyReleased (arg);
|
mInputBinder->keyReleased (arg);
|
||||||
|
|
||||||
OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym);
|
OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym);
|
||||||
|
|
||||||
MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc));
|
MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc));
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id )
|
void InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id )
|
||||||
{
|
{
|
||||||
mInputBinder->mousePressed (arg, id);
|
mInputBinder->mousePressed (arg, id);
|
||||||
|
|
||||||
if (id != SDL_BUTTON_LEFT && id != SDL_BUTTON_RIGHT)
|
if (id != SDL_BUTTON_LEFT && id != SDL_BUTTON_RIGHT)
|
||||||
return true; // MyGUI has no use for these events
|
return; // MyGUI has no use for these events
|
||||||
|
|
||||||
MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI(id));
|
MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI(id));
|
||||||
if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0)
|
if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0)
|
||||||
|
@ -539,20 +543,16 @@ namespace MWInput
|
||||||
MWBase::Environment::get().getSoundManager ()->playSound ("Menu Click", 1.f, 1.f);
|
MWBase::Environment::get().getSoundManager ()->playSound ("Menu Click", 1.f, 1.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InputManager::mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id )
|
void InputManager::mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id )
|
||||||
{
|
{
|
||||||
mInputBinder->mouseReleased (arg, id);
|
mInputBinder->mouseReleased (arg, id);
|
||||||
|
|
||||||
MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI(id));
|
MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI(id));
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InputManager::mouseMoved(const SFO::MouseMotionEvent &arg )
|
void InputManager::mouseMoved(const SFO::MouseMotionEvent &arg )
|
||||||
{
|
{
|
||||||
mInputBinder->mouseMoved (arg);
|
mInputBinder->mouseMoved (arg);
|
||||||
|
|
||||||
|
@ -585,13 +585,13 @@ namespace MWInput
|
||||||
float rot[3];
|
float rot[3];
|
||||||
rot[0] = -y;
|
rot[0] = -y;
|
||||||
rot[1] = 0.0f;
|
rot[1] = 0.0f;
|
||||||
rot[2] = x;
|
rot[2] = -x;
|
||||||
|
|
||||||
// Only actually turn player when we're not in vanity mode
|
// Only actually turn player when we're not in vanity mode
|
||||||
if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot))
|
if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot))
|
||||||
{
|
{
|
||||||
mPlayer->yaw(x);
|
mPlayer->yaw(x);
|
||||||
mPlayer->pitch(-y);
|
mPlayer->pitch(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg.zrel && mControlSwitch["playerviewswitch"]) //Check to make sure you are allowed to zoomout and there is a change
|
if (arg.zrel && mControlSwitch["playerviewswitch"]) //Check to make sure you are allowed to zoomout and there is a change
|
||||||
|
@ -600,8 +600,6 @@ namespace MWInput
|
||||||
MWBase::Environment::get().getWorld()->setCameraDistance(arg.zrel, true, true);
|
MWBase::Environment::get().getWorld()->setCameraDistance(arg.zrel, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputManager::windowFocusChange(bool have_focus)
|
void InputManager::windowFocusChange(bool have_focus)
|
||||||
|
|
|
@ -65,6 +65,9 @@ namespace MWInput
|
||||||
|
|
||||||
virtual ~InputManager();
|
virtual ~InputManager();
|
||||||
|
|
||||||
|
/// Clear all savegame-specific data
|
||||||
|
virtual void clear();
|
||||||
|
|
||||||
virtual void update(float dt, bool loading);
|
virtual void update(float dt, bool loading);
|
||||||
|
|
||||||
void setPlayer (MWWorld::Player* player) { mPlayer = player; }
|
void setPlayer (MWWorld::Player* player) { mPlayer = player; }
|
||||||
|
@ -86,13 +89,13 @@ namespace MWInput
|
||||||
virtual void resetToDefaultBindings();
|
virtual void resetToDefaultBindings();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual bool keyPressed(const SDL_KeyboardEvent &arg );
|
virtual void keyPressed(const SDL_KeyboardEvent &arg );
|
||||||
virtual bool keyReleased( const SDL_KeyboardEvent &arg );
|
virtual void keyReleased( const SDL_KeyboardEvent &arg );
|
||||||
virtual void textInput (const SDL_TextInputEvent &arg);
|
virtual void textInput (const SDL_TextInputEvent &arg);
|
||||||
|
|
||||||
virtual bool mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id );
|
virtual void mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id );
|
||||||
virtual bool mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id );
|
virtual void mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id );
|
||||||
virtual bool mouseMoved( const SFO::MouseMotionEvent &arg );
|
virtual void mouseMoved( const SFO::MouseMotionEvent &arg );
|
||||||
|
|
||||||
virtual void windowVisibilityChange( bool visible );
|
virtual void windowVisibilityChange( bool visible );
|
||||||
virtual void windowFocusChange( bool have_focus );
|
virtual void windowFocusChange( bool have_focus );
|
||||||
|
|
|
@ -210,7 +210,7 @@ namespace MWMechanics
|
||||||
&& LOS
|
&& LOS
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
creatureStats.getAiSequence().stack(AiCombat(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()));
|
creatureStats.getAiSequence().stack(AiCombat(MWBase::Environment::get().getWorld()->getPlayerPtr()));
|
||||||
creatureStats.setHostile(true);
|
creatureStats.setHostile(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -541,7 +541,7 @@ namespace MWMechanics
|
||||||
// TODO: Add AI to follow player and fight for him
|
// TODO: Add AI to follow player and fight for him
|
||||||
// TODO: VFX_SummonStart, VFX_SummonEnd
|
// TODO: VFX_SummonStart, VFX_SummonEnd
|
||||||
creatureStats.mSummonedCreatures.insert(std::make_pair(it->first,
|
creatureStats.mSummonedCreatures.insert(std::make_pair(it->first,
|
||||||
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos).getRefData().getHandle()));
|
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos).getRefData().getHandle()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#include "../mwbase/dialoguemanager.hpp"
|
#include "../mwbase/dialoguemanager.hpp"
|
||||||
|
|
||||||
|
|
||||||
#include "npcstats.hpp"
|
#include "creaturestats.hpp"
|
||||||
#include "steering.hpp"
|
#include "steering.hpp"
|
||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
#include "character.hpp" // fixme: for getActiveWeapon
|
#include "character.hpp" // fixme: for getActiveWeapon
|
||||||
|
@ -140,11 +140,12 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
MWMechanics::DrawState_ state = actor.getClass().getCreatureStats(actor).getDrawState();
|
MWMechanics::DrawState_ state = actor.getClass().getCreatureStats(actor).getDrawState();
|
||||||
if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing)
|
if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing)
|
||||||
actor.getClass().getNpcStats(actor).setDrawState(MWMechanics::DrawState_Weapon);
|
actor.getClass().getCreatureStats(actor).setDrawState(MWMechanics::DrawState_Weapon);
|
||||||
|
|
||||||
//Get weapon speed and range
|
//Get weapon speed and range
|
||||||
MWWorld::ContainerStoreIterator weaponSlot =
|
MWWorld::ContainerStoreIterator weaponSlot =
|
||||||
MWMechanics::getActiveWeapon(cls.getNpcStats(actor), cls.getInventoryStore(actor), &weaptype);
|
MWMechanics::getActiveWeapon(cls.getCreatureStats(actor), cls.getInventoryStore(actor), &weaptype);
|
||||||
|
|
||||||
if (weaptype == WeapType_HandToHand)
|
if (weaptype == WeapType_HandToHand)
|
||||||
{
|
{
|
||||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||||
|
@ -242,17 +243,21 @@ namespace MWMechanics
|
||||||
//target is at far distance: build path to target OR follow target (if previously actor had reached it once)
|
//target is at far distance: build path to target OR follow target (if previously actor had reached it once)
|
||||||
mFollowTarget = false;
|
mFollowTarget = false;
|
||||||
|
|
||||||
buildNewPath(actor);
|
buildNewPath(actor); //may fail to build a path, check before use
|
||||||
|
|
||||||
//delete visited path node
|
//delete visited path node
|
||||||
mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]);
|
mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]);
|
||||||
|
|
||||||
|
//if no new path leave mTargetAngle unchanged
|
||||||
|
if(!mPathFinder.getPath().empty())
|
||||||
|
{
|
||||||
//try shortcut
|
//try shortcut
|
||||||
if(vDir.length() < mPathFinder.getDistToNext(pos.pos[0],pos.pos[1],pos.pos[2]) && MWBase::Environment::get().getWorld()->getLOS(actor, mTarget))
|
if(vDir.length() < mPathFinder.getDistToNext(pos.pos[0],pos.pos[1],pos.pos[2]) && MWBase::Environment::get().getWorld()->getLOS(actor, mTarget))
|
||||||
mTargetAngle = Ogre::Radian( Ogre::Math::ACos(vDir.y / vDir.length()) * sgn(Ogre::Math::ASin(vDir.x / vDir.length())) ).valueDegrees();
|
mTargetAngle = Ogre::Radian( Ogre::Math::ACos(vDir.y / vDir.length()) * sgn(Ogre::Math::ASin(vDir.x / vDir.length())) ).valueDegrees();
|
||||||
else
|
else
|
||||||
mTargetAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
mTargetAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
||||||
mRotate = true;
|
mRotate = true;
|
||||||
|
}
|
||||||
|
|
||||||
mMovement.mPosition[1] = 1;
|
mMovement.mPosition[1] = 1;
|
||||||
mReadyToAttack = false;
|
mReadyToAttack = false;
|
||||||
|
@ -302,9 +307,13 @@ namespace MWMechanics
|
||||||
dest.mZ = mTarget.getRefData().getPosition().pos[2];
|
dest.mZ = mTarget.getRefData().getPosition().pos[2];
|
||||||
Ogre::Vector3 newPathTarget = Ogre::Vector3(dest.mX, dest.mY, dest.mZ);
|
Ogre::Vector3 newPathTarget = Ogre::Vector3(dest.mX, dest.mY, dest.mZ);
|
||||||
|
|
||||||
|
float dist = -1; //hack to indicate first time, to construct a new path
|
||||||
|
if(!mPathFinder.getPath().empty())
|
||||||
|
{
|
||||||
ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back();
|
ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back();
|
||||||
Ogre::Vector3 currPathTarget(lastPt.mX, lastPt.mY, lastPt.mZ);
|
Ogre::Vector3 currPathTarget(lastPt.mX, lastPt.mY, lastPt.mZ);
|
||||||
float dist = Ogre::Math::Abs((newPathTarget - currPathTarget).length());
|
dist = Ogre::Math::Abs((newPathTarget - currPathTarget).length());
|
||||||
|
}
|
||||||
|
|
||||||
float targetPosThreshold;
|
float targetPosThreshold;
|
||||||
bool isOutside = actor.getCell()->getCell()->isExterior();
|
bool isOutside = actor.getCell()->getCell()->isExterior();
|
||||||
|
@ -313,7 +322,7 @@ namespace MWMechanics
|
||||||
else
|
else
|
||||||
targetPosThreshold = 100;
|
targetPosThreshold = 100;
|
||||||
|
|
||||||
if(dist > targetPosThreshold)
|
if((dist < 0) || (dist > targetPosThreshold))
|
||||||
{
|
{
|
||||||
//construct new path only if target has moved away more than on <targetPosThreshold>
|
//construct new path only if target has moved away more than on <targetPosThreshold>
|
||||||
ESM::Position pos = actor.getRefData().getPosition();
|
ESM::Position pos = actor.getRefData().getPosition();
|
||||||
|
@ -334,11 +343,14 @@ namespace MWMechanics
|
||||||
//maybe here is a mistake (?): PathFinder::getPathSize() returns number of grid points in the path,
|
//maybe here is a mistake (?): PathFinder::getPathSize() returns number of grid points in the path,
|
||||||
//not the actual path length. Here we should know if the new path is actually more effective.
|
//not the actual path length. Here we should know if the new path is actually more effective.
|
||||||
//if(pathFinder2.getPathSize() < mPathFinder.getPathSize())
|
//if(pathFinder2.getPathSize() < mPathFinder.getPathSize())
|
||||||
|
if(!mPathFinder.getPath().empty())
|
||||||
|
{
|
||||||
newPathFinder.syncStart(mPathFinder.getPath());
|
newPathFinder.syncStart(mPathFinder.getPath());
|
||||||
mPathFinder = newPathFinder;
|
mPathFinder = newPathFinder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int AiCombat::getTypeId() const
|
int AiCombat::getTypeId() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,6 +27,11 @@ namespace
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
// NOTE: determined empirically but probably need further tweaking
|
||||||
|
static const int COUNT_BEFORE_STUCK = 20;
|
||||||
|
static const int COUNT_BEFORE_RESET = 200;
|
||||||
|
static const int COUNT_EVADE = 7;
|
||||||
|
|
||||||
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<int>& idle, bool repeat):
|
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<int>& idle, bool repeat):
|
||||||
mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat)
|
mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat)
|
||||||
, mCellX(std::numeric_limits<int>::max())
|
, mCellX(std::numeric_limits<int>::max())
|
||||||
|
@ -36,6 +41,11 @@ namespace MWMechanics
|
||||||
, mX(0)
|
, mX(0)
|
||||||
, mY(0)
|
, mY(0)
|
||||||
, mZ(0)
|
, mZ(0)
|
||||||
|
, mPrevX(0)
|
||||||
|
, mPrevY(0)
|
||||||
|
, mWalkState(State_Norm)
|
||||||
|
, mStuckCount(0)
|
||||||
|
, mEvadeCount(0)
|
||||||
, mSaidGreeting(false)
|
, mSaidGreeting(false)
|
||||||
{
|
{
|
||||||
for(unsigned short counter = 0; counter < mIdle.size(); counter++)
|
for(unsigned short counter = 0; counter < mIdle.size(); counter++)
|
||||||
|
@ -298,9 +308,91 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
/* 1 n
|
||||||
|
* State_Norm <---> State_CheckStuck --> State_Evade
|
||||||
|
* ^ ^ | ^ | ^ | |
|
||||||
|
* | | | | | | | |
|
||||||
|
* | +---+ +---+ +---+ | m
|
||||||
|
* | any < n < m |
|
||||||
|
* +--------------------------------------------+
|
||||||
|
*/
|
||||||
|
bool samePosition = (abs(pos.pos[0] - mPrevX) < 1) && (abs(pos.pos[1] - mPrevY) < 1);
|
||||||
|
switch(mWalkState)
|
||||||
|
{
|
||||||
|
case State_Norm:
|
||||||
|
{
|
||||||
|
if(!samePosition)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
mWalkState = State_CheckStuck;
|
||||||
|
}
|
||||||
|
/* FALL THROUGH */
|
||||||
|
case State_CheckStuck:
|
||||||
|
{
|
||||||
|
if(!samePosition)
|
||||||
|
{
|
||||||
|
mWalkState = State_Norm;
|
||||||
|
// to do this properly need yet another variable, simply don't clear for now
|
||||||
|
//mStuckCount = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// consider stuck only if position unchanges consecutively
|
||||||
|
if((mStuckCount++ % COUNT_BEFORE_STUCK) == 0)
|
||||||
|
mWalkState = State_Evade;
|
||||||
|
// NOTE: mStuckCount is purposely not cleared here
|
||||||
|
else
|
||||||
|
break; // still in the same state, but counter got incremented
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* FALL THROUGH */
|
||||||
|
case State_Evade:
|
||||||
|
{
|
||||||
|
if(mEvadeCount++ < COUNT_EVADE)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mWalkState = State_Norm; // tried to evade, assume all is ok and start again
|
||||||
|
// NOTE: mStuckCount is purposely not cleared here
|
||||||
|
mEvadeCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* NO DEFAULT CASE */
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mWalkState == State_Evade)
|
||||||
|
{
|
||||||
|
//std::cout << "Stuck \""<<actor.getClass().getName(actor)<<"\"" << std::endl;
|
||||||
|
|
||||||
|
// diagonal should have same animation as walk forward
|
||||||
|
actor.getClass().getMovementSettings(actor).mPosition[0] = 1;
|
||||||
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 0.01f;
|
||||||
|
// change the angle a bit, too
|
||||||
|
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
||||||
|
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset
|
||||||
|
{
|
||||||
|
//std::cout << "Reset \""<<actor.getClass().getName(actor)<<"\"" << std::endl;
|
||||||
|
mWalkState = State_Norm;
|
||||||
|
mStuckCount = 0;
|
||||||
|
|
||||||
|
stopWalking(actor);
|
||||||
|
mMoveNow = false;
|
||||||
|
mWalking = false;
|
||||||
|
mChooseAction = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update position
|
||||||
|
ESM::Position updatedPos = actor.getRefData().getPosition();
|
||||||
|
mPrevX = updatedPos.pos[0];
|
||||||
|
mPrevY = updatedPos.pos[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,21 @@ namespace MWMechanics
|
||||||
float mXCell;
|
float mXCell;
|
||||||
float mYCell;
|
float mYCell;
|
||||||
|
|
||||||
|
// for checking if we're stuck (but don't check Z axis)
|
||||||
|
float mPrevX;
|
||||||
|
float mPrevY;
|
||||||
|
|
||||||
|
enum WalkState
|
||||||
|
{
|
||||||
|
State_Norm,
|
||||||
|
State_CheckStuck,
|
||||||
|
State_Evade
|
||||||
|
};
|
||||||
|
WalkState mWalkState;
|
||||||
|
|
||||||
|
int mStuckCount;
|
||||||
|
int mEvadeCount;
|
||||||
|
|
||||||
bool mStoredAvailableNodes;
|
bool mStoredAvailableNodes;
|
||||||
bool mChooseAction;
|
bool mChooseAction;
|
||||||
bool mIdleNow;
|
bool mIdleNow;
|
||||||
|
|
|
@ -313,6 +313,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
||||||
|
|
||||||
mAnimation->disable(mCurrentMovement);
|
mAnimation->disable(mCurrentMovement);
|
||||||
mCurrentMovement = movement;
|
mCurrentMovement = movement;
|
||||||
|
mMovementAnimVelocity = 0.0f;
|
||||||
if(!mCurrentMovement.empty())
|
if(!mCurrentMovement.empty())
|
||||||
{
|
{
|
||||||
float vel, speedmult = 1.0f;
|
float vel, speedmult = 1.0f;
|
||||||
|
@ -320,7 +321,10 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
||||||
bool isrunning = mPtr.getClass().getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run);
|
bool isrunning = mPtr.getClass().getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run);
|
||||||
|
|
||||||
if(mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(mCurrentMovement)) > 1.0f)
|
if(mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(mCurrentMovement)) > 1.0f)
|
||||||
|
{
|
||||||
|
mMovementAnimVelocity = vel;
|
||||||
speedmult = mMovementSpeed / vel;
|
speedmult = mMovementSpeed / vel;
|
||||||
|
}
|
||||||
else if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight)
|
else if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight)
|
||||||
speedmult = 1.f; // TODO: should get a speed mult depending on the current turning speed
|
speedmult = 1.f; // TODO: should get a speed mult depending on the current turning speed
|
||||||
else if (mMovementSpeed > 0.0f)
|
else if (mMovementSpeed > 0.0f)
|
||||||
|
@ -330,10 +334,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
||||||
speedmult = mMovementSpeed / (isrunning ? 222.857f : 154.064f);
|
speedmult = mMovementSpeed / (isrunning ? 222.857f : 154.064f);
|
||||||
mAnimation->play(mCurrentMovement, Priority_Movement, movegroup, false,
|
mAnimation->play(mCurrentMovement, Priority_Movement, movegroup, false,
|
||||||
speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul);
|
speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul);
|
||||||
|
|
||||||
mMovementAnimVelocity = vel;
|
|
||||||
}
|
}
|
||||||
else mMovementAnimVelocity = 0.0f;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1194,7 +1195,10 @@ void CharacterController::update(float duration)
|
||||||
: (sneak ? CharState_SneakBack
|
: (sneak ? CharState_SneakBack
|
||||||
: (isrunning ? CharState_RunBack : CharState_WalkBack)));
|
: (isrunning ? CharState_RunBack : CharState_WalkBack)));
|
||||||
}
|
}
|
||||||
else if(rot.z != 0.0f && !inwater && !sneak)
|
// 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)
|
||||||
{
|
{
|
||||||
if(rot.z > 0.0f)
|
if(rot.z > 0.0f)
|
||||||
movestate = CharState_TurnRight;
|
movestate = CharState_TurnRight;
|
||||||
|
|
|
@ -4,9 +4,12 @@
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/npcstats.hpp"
|
#include "../mwmechanics/npcstats.hpp"
|
||||||
#include "../mwmechanics/movement.hpp"
|
#include "../mwmechanics/movement.hpp"
|
||||||
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
@ -17,14 +20,30 @@
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
Ogre::Radian signedAngle(Ogre::Vector3 v1, Ogre::Vector3 v2, Ogre::Vector3 n)
|
Ogre::Radian signedAngle(Ogre::Vector3 v1, Ogre::Vector3 v2, Ogre::Vector3 normal)
|
||||||
{
|
{
|
||||||
return Ogre::Math::ATan2(
|
return Ogre::Math::ATan2(
|
||||||
n.dotProduct( v1.crossProduct(v2) ),
|
normal.dotProduct( v1.crossProduct(v2) ),
|
||||||
v1.dotProduct(v2)
|
v1.dotProduct(v2)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void applyEnchantment (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& object, const Ogre::Vector3& hitPosition)
|
||||||
|
{
|
||||||
|
std::string enchantmentName = !object.isEmpty() ? object.getClass().getEnchantment(object) : "";
|
||||||
|
if (!enchantmentName.empty())
|
||||||
|
{
|
||||||
|
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(
|
||||||
|
enchantmentName);
|
||||||
|
if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
|
||||||
|
{
|
||||||
|
MWMechanics::CastSpell cast(attacker, victim);
|
||||||
|
cast.mHitPosition = hitPosition;
|
||||||
|
cast.cast(object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
|
@ -135,4 +154,94 @@ namespace MWMechanics
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void projectileHit(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, MWWorld::Ptr weapon, const MWWorld::Ptr &projectile,
|
||||||
|
const Ogre::Vector3& hitPosition)
|
||||||
|
{
|
||||||
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
|
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
|
MWMechanics::CreatureStats& attackerStats = attacker.getClass().getCreatureStats(attacker);
|
||||||
|
|
||||||
|
const MWWorld::Class &othercls = victim.getClass();
|
||||||
|
if(!othercls.isActor()) // Can't hit non-actors
|
||||||
|
return;
|
||||||
|
MWMechanics::CreatureStats &otherstats = victim.getClass().getCreatureStats(victim);
|
||||||
|
if(otherstats.isDead()) // Can't hit dead actors
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(attacker.getRefData().getHandle() == "player")
|
||||||
|
MWBase::Environment::get().getWindowManager()->setEnemy(victim);
|
||||||
|
|
||||||
|
int weapskill = ESM::Skill::Marksman;
|
||||||
|
if(!weapon.isEmpty())
|
||||||
|
weapskill = weapon.getClass().getEquipmentSkill(weapon);
|
||||||
|
|
||||||
|
float skillValue = attacker.getClass().getSkill(attacker,
|
||||||
|
weapon.getClass().getEquipmentSkill(weapon));
|
||||||
|
|
||||||
|
if((::rand()/(RAND_MAX+1.0)) > getHitChance(attacker, victim, skillValue)/100.0f)
|
||||||
|
{
|
||||||
|
victim.getClass().onHit(victim, 0.0f, false, projectile, attacker, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float damage = 0.0f;
|
||||||
|
|
||||||
|
float fDamageStrengthBase = gmst.find("fDamageStrengthBase")->getFloat();
|
||||||
|
float fDamageStrengthMult = gmst.find("fDamageStrengthMult")->getFloat();
|
||||||
|
|
||||||
|
const unsigned char* attack = weapon.get<ESM::Weapon>()->mBase->mData.mChop;
|
||||||
|
damage = attack[0] + ((attack[1]-attack[0])*attackerStats.getAttackStrength()); // Bow/crossbow damage
|
||||||
|
if (weapon != projectile)
|
||||||
|
{
|
||||||
|
// Arrow/bolt damage
|
||||||
|
attack = projectile.get<ESM::Weapon>()->mBase->mData.mChop;
|
||||||
|
damage += attack[0] + ((attack[1]-attack[0])*attackerStats.getAttackStrength());
|
||||||
|
}
|
||||||
|
|
||||||
|
damage *= fDamageStrengthBase +
|
||||||
|
(attackerStats.getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1);
|
||||||
|
|
||||||
|
if(attacker.getRefData().getHandle() == "player")
|
||||||
|
attacker.getClass().skillUsageSucceeded(attacker, weapskill, 0);
|
||||||
|
|
||||||
|
bool detected = MWBase::Environment::get().getMechanicsManager()->awarenessCheck(attacker, victim);
|
||||||
|
if(!detected)
|
||||||
|
{
|
||||||
|
damage *= gmst.find("fCombatCriticalStrikeMult")->getFloat();
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}");
|
||||||
|
MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
if (victim.getClass().getCreatureStats(victim).getKnockedDown())
|
||||||
|
damage *= gmst.find("fCombatKODamageMult")->getFloat();
|
||||||
|
|
||||||
|
// Apply "On hit" effect of the weapon
|
||||||
|
applyEnchantment(attacker, victim, weapon, hitPosition);
|
||||||
|
if (weapon != projectile)
|
||||||
|
applyEnchantment(attacker, victim, projectile, hitPosition);
|
||||||
|
|
||||||
|
if (damage > 0)
|
||||||
|
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
||||||
|
|
||||||
|
float fProjectileThrownStoreChance = gmst.find("fProjectileThrownStoreChance")->getFloat();
|
||||||
|
if ((::rand()/(RAND_MAX+1.0)) < fProjectileThrownStoreChance/100.f)
|
||||||
|
victim.getClass().getContainerStore(victim).add(projectile, 1, victim);
|
||||||
|
|
||||||
|
victim.getClass().onHit(victim, damage, true, projectile, attacker, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
float getHitChance(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, int skillValue)
|
||||||
|
{
|
||||||
|
MWMechanics::CreatureStats &stats = attacker.getClass().getCreatureStats(attacker);
|
||||||
|
const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects();
|
||||||
|
float hitchance = skillValue +
|
||||||
|
(stats.getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) +
|
||||||
|
(stats.getAttribute(ESM::Attribute::Luck).getModified() / 10.0f);
|
||||||
|
hitchance *= stats.getFatigueTerm();
|
||||||
|
hitchance += mageffects.get(ESM::MagicEffect::FortifyAttack).mMagnitude -
|
||||||
|
mageffects.get(ESM::MagicEffect::Blind).mMagnitude;
|
||||||
|
hitchance -= victim.getClass().getCreatureStats(victim).getEvasion();
|
||||||
|
return hitchance;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define OPENMW_MECHANICS_COMBAT_H
|
#define OPENMW_MECHANICS_COMBAT_H
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
|
#include <OgreVector3.h>
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
@ -11,6 +12,13 @@ bool blockMeleeAttack (const MWWorld::Ptr& attacker, const MWWorld::Ptr& blocker
|
||||||
|
|
||||||
void resistNormalWeapon (const MWWorld::Ptr& actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float& damage);
|
void resistNormalWeapon (const MWWorld::Ptr& actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float& damage);
|
||||||
|
|
||||||
|
/// @note for a thrown weapon, \a weapon == \a projectile, for bows/crossbows, \a projectile is the arrow/bolt
|
||||||
|
void projectileHit (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MWWorld::Ptr weapon, const MWWorld::Ptr& projectile,
|
||||||
|
const Ogre::Vector3& 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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
|
|
||||||
#include <components/esm/loadskil.hpp>
|
#include <components/esm/loadskil.hpp>
|
||||||
|
|
|
@ -393,6 +393,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
void PathFinder::syncStart(const std::list<ESM::Pathgrid::Point> &path)
|
void PathFinder::syncStart(const std::list<ESM::Pathgrid::Point> &path)
|
||||||
{
|
{
|
||||||
|
if (mPath.size() < 2)
|
||||||
|
return; //nothing to pop
|
||||||
std::list<ESM::Pathgrid::Point>::const_iterator oldStart = path.begin();
|
std::list<ESM::Pathgrid::Point>::const_iterator oldStart = path.begin();
|
||||||
std::list<ESM::Pathgrid::Point>::iterator iter = ++mPath.begin();
|
std::list<ESM::Pathgrid::Point>::iterator iter = ++mPath.begin();
|
||||||
|
|
||||||
|
|
|
@ -587,7 +587,7 @@ namespace MWMechanics
|
||||||
inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch);
|
inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch);
|
||||||
}
|
}
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->launchProjectile(mId, false, enchantment->mEffects, mCaster, mSourceName);
|
MWBase::Environment::get().getWorld()->launchMagicBolt(mId, false, enchantment->mEffects, mCaster, mSourceName);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -666,7 +666,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->launchProjectile(mId, false, spell->mEffects, mCaster, mSourceName);
|
MWBase::Environment::get().getWorld()->launchMagicBolt(mId, false, spell->mEffects, mCaster, mSourceName);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include <OgreSceneManager.h>
|
#include <OgreSceneManager.h>
|
||||||
#include <OgreControllerManager.h>
|
#include <OgreControllerManager.h>
|
||||||
#include <OgreStaticGeometry.h>
|
#include <OgreStaticGeometry.h>
|
||||||
|
#include <OgreSceneNode.h>
|
||||||
|
#include <OgreTechnique.h>
|
||||||
|
|
||||||
#include <components/esm/loadligh.hpp>
|
#include <components/esm/loadligh.hpp>
|
||||||
#include <components/esm/loadweap.hpp>
|
#include <components/esm/loadweap.hpp>
|
||||||
|
@ -293,6 +295,17 @@ void Animation::addAnimSource(const std::string &model)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (grp == 0 && dstval->getNode()->getName() == "Bip01")
|
||||||
|
{
|
||||||
|
mNonAccumRoot = dstval->getNode();
|
||||||
|
mAccumRoot = mNonAccumRoot->getParent();
|
||||||
|
if(!mAccumRoot)
|
||||||
|
{
|
||||||
|
std::cerr<< "Non-Accum root for "<<mPtr.getCellRef().mRefID<<" is skeleton root??" <<std::endl;
|
||||||
|
mNonAccumRoot = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ctrls[i].setSource(mAnimationTimePtr[grp]);
|
ctrls[i].setSource(mAnimationTimePtr[grp]);
|
||||||
grpctrls[grp].push_back(ctrls[i]);
|
grpctrls[grp].push_back(ctrls[i]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ namespace MWRender
|
||||||
if (!mVanity.enabled && !mPreviewMode) {
|
if (!mVanity.enabled && !mPreviewMode) {
|
||||||
mCamera->getParentNode()->setOrientation(xr);
|
mCamera->getParentNode()->setOrientation(xr);
|
||||||
} else {
|
} else {
|
||||||
Ogre::Quaternion zr(Ogre::Radian(getYaw()), Ogre::Vector3::NEGATIVE_UNIT_Z);
|
Ogre::Quaternion zr(Ogre::Radian(getYaw()), Ogre::Vector3::UNIT_Z);
|
||||||
mCamera->getParentNode()->setOrientation(zr * xr);
|
mCamera->getParentNode()->setOrientation(zr * xr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
#include "characterpreview.hpp"
|
#include "characterpreview.hpp"
|
||||||
|
|
||||||
|
|
||||||
#include <OgreSceneManager.h>
|
#include <OgreSceneManager.h>
|
||||||
#include <OgreRoot.h>
|
#include <OgreRoot.h>
|
||||||
#include <OgreHardwarePixelBuffer.h>
|
#include <OgreHardwarePixelBuffer.h>
|
||||||
#include <OgreCamera.h>
|
#include <OgreCamera.h>
|
||||||
|
#include <OgreSceneNode.h>
|
||||||
|
#include <OgreTextureManager.h>
|
||||||
|
#include <OgreViewport.h>
|
||||||
|
#include <OgreRenderTexture.h>
|
||||||
|
|
||||||
#include <libs/openengine/ogre/selectionbuffer.hpp>
|
#include <libs/openengine/ogre/selectionbuffer.hpp>
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <OgreRenderTarget.h>
|
#include <OgreRenderTarget.h>
|
||||||
#include <OgreMaterialManager.h>
|
#include <OgreMaterialManager.h>
|
||||||
|
#include <OgreVector3.h>
|
||||||
|
|
||||||
#include <components/esm/loadnpc.hpp>
|
#include <components/esm/loadnpc.hpp>
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,8 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr)
|
||||||
|
|
||||||
updateParts();
|
updateParts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mWeaponAnimationTime = Ogre::SharedPtr<WeaponAnimationTime>(new WeaponAnimationTime(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreatureWeaponAnimation::showWeapons(bool showWeapon)
|
void CreatureWeaponAnimation::showWeapons(bool showWeapon)
|
||||||
|
@ -110,6 +112,20 @@ void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slo
|
||||||
setRenderProperties(scene, RV_Actors, RQG_Main, RQG_Alpha, 0,
|
setRenderProperties(scene, RV_Actors, RQG_Main, RQG_Alpha, 0,
|
||||||
!item.getClass().getEnchantment(item).empty(), &glowColor);
|
!item.getClass().getEnchantment(item).empty(), &glowColor);
|
||||||
|
|
||||||
|
// Crossbows start out with a bolt attached
|
||||||
|
if (slot == MWWorld::InventoryStore::Slot_CarriedRight &&
|
||||||
|
item.getTypeName() == typeid(ESM::Weapon).name() &&
|
||||||
|
item.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
||||||
|
{
|
||||||
|
MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||||
|
if (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Bolt)
|
||||||
|
attachArrow();
|
||||||
|
else
|
||||||
|
mAmmunition.setNull();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mAmmunition.setNull();
|
||||||
|
|
||||||
if(scene->mSkelBase)
|
if(scene->mSkelBase)
|
||||||
{
|
{
|
||||||
Ogre::SkeletonInstance *skel = scene->mSkelBase->getSkeleton();
|
Ogre::SkeletonInstance *skel = scene->mSkelBase->getSkeleton();
|
||||||
|
@ -133,15 +149,42 @@ void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slo
|
||||||
updateSkeletonInstance(mSkelBase->getSkeleton(), skel);
|
updateSkeletonInstance(mSkelBase->getSkeleton(), skel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// type == ESM::PRT_Weapon should get an animation source based on the current offset
|
|
||||||
// of the weapon attack animation (from its beginning, or start marker?)
|
|
||||||
std::vector<Ogre::Controller<Ogre::Real> >::iterator ctrl(scene->mControllers.begin());
|
std::vector<Ogre::Controller<Ogre::Real> >::iterator ctrl(scene->mControllers.begin());
|
||||||
for(;ctrl != scene->mControllers.end();ctrl++)
|
for(;ctrl != scene->mControllers.end();ctrl++)
|
||||||
{
|
{
|
||||||
if(ctrl->getSource().isNull())
|
if(ctrl->getSource().isNull())
|
||||||
|
{
|
||||||
|
if (slot == MWWorld::InventoryStore::Slot_CarriedRight)
|
||||||
|
ctrl->setSource(mWeaponAnimationTime);
|
||||||
|
else
|
||||||
ctrl->setSource(Ogre::SharedPtr<NullAnimationTime>(new NullAnimationTime()));
|
ctrl->setSource(Ogre::SharedPtr<NullAnimationTime>(new NullAnimationTime()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreatureWeaponAnimation::releaseArrow()
|
||||||
|
{
|
||||||
|
WeaponAnimation::releaseArrow(mPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ogre::Vector3 CreatureWeaponAnimation::runAnimation(float duration)
|
||||||
|
{
|
||||||
|
Ogre::Vector3 ret = Animation::runAnimation(duration);
|
||||||
|
pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton());
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define GAME_RENDER_CREATUREANIMATION_H
|
#define GAME_RENDER_CREATUREANIMATION_H
|
||||||
|
|
||||||
#include "animation.hpp"
|
#include "animation.hpp"
|
||||||
|
#include "weaponanimation.hpp"
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
|
@ -21,7 +22,7 @@ namespace MWRender
|
||||||
// For creatures with weapons and shields
|
// For creatures with weapons and shields
|
||||||
// Animation is already virtual anyway, so might as well make a separate class.
|
// 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.
|
// Most creatures don't need weapons/shields, so this will save some memory.
|
||||||
class CreatureWeaponAnimation : public Animation, public MWWorld::InventoryStoreListener
|
class CreatureWeaponAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CreatureWeaponAnimation(const MWWorld::Ptr& ptr);
|
CreatureWeaponAnimation(const MWWorld::Ptr& ptr);
|
||||||
|
@ -36,11 +37,29 @@ namespace MWRender
|
||||||
|
|
||||||
void updatePart(NifOgre::ObjectScenePtr& scene, int slot);
|
void updatePart(NifOgre::ObjectScenePtr& scene, int slot);
|
||||||
|
|
||||||
|
virtual void attachArrow();
|
||||||
|
virtual void releaseArrow();
|
||||||
|
|
||||||
|
virtual Ogre::Vector3 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 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:
|
private:
|
||||||
NifOgre::ObjectScenePtr mWeapon;
|
NifOgre::ObjectScenePtr mWeapon;
|
||||||
NifOgre::ObjectScenePtr mShield;
|
NifOgre::ObjectScenePtr mShield;
|
||||||
bool mShowWeapons;
|
bool mShowWeapons;
|
||||||
bool mShowCarriedLeft;
|
bool mShowCarriedLeft;
|
||||||
|
|
||||||
|
Ogre::SharedPtr<WeaponAnimationTime> mWeaponAnimationTime;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include <OgreMaterial.h>
|
#include <OgreMaterial.h>
|
||||||
#include <OgreMaterialManager.h>
|
#include <OgreMaterialManager.h>
|
||||||
#include <OgreManualObject.h>
|
#include <OgreManualObject.h>
|
||||||
|
#include <OgreTechnique.h>
|
||||||
|
#include <OgreSceneNode.h>
|
||||||
|
|
||||||
#include <openengine/bullet/physic.hpp>
|
#include <openengine/bullet/physic.hpp>
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#include <OgreSceneManager.h>
|
#include <OgreSceneManager.h>
|
||||||
#include <OgreParticleSystem.h>
|
#include <OgreParticleSystem.h>
|
||||||
|
#include <OgreSceneNode.h>
|
||||||
|
#include <OgreTechnique.h>
|
||||||
|
|
||||||
#include "animation.hpp"
|
#include "animation.hpp"
|
||||||
#include "renderconst.hpp"
|
#include "renderconst.hpp"
|
||||||
|
|
|
@ -75,10 +75,9 @@ namespace MWRender
|
||||||
|
|
||||||
if (land)
|
if (land)
|
||||||
{
|
{
|
||||||
if (!land->isDataLoaded(ESM::Land::DATA_VHGT))
|
int mask = ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX;
|
||||||
{
|
if (!land->isDataLoaded(mask))
|
||||||
land->loadData(ESM::Land::DATA_VHGT);
|
land->loadData(mask);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int cellY=0; cellY<cellSize; ++cellY)
|
for (int cellY=0; cellY<cellSize; ++cellY)
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#include <OgreSceneNode.h>
|
#include <OgreSceneNode.h>
|
||||||
#include <OgreCamera.h>
|
#include <OgreCamera.h>
|
||||||
#include <OgreTextureManager.h>
|
#include <OgreTextureManager.h>
|
||||||
|
#include <OgreRenderTexture.h>
|
||||||
|
#include <OgreViewport.h>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
|
@ -4,6 +4,11 @@
|
||||||
#include <OgreEntity.h>
|
#include <OgreEntity.h>
|
||||||
#include <OgreParticleSystem.h>
|
#include <OgreParticleSystem.h>
|
||||||
#include <OgreSubEntity.h>
|
#include <OgreSubEntity.h>
|
||||||
|
#include <OgreSkeleton.h>
|
||||||
|
#include <OgreSkeletonInstance.h>
|
||||||
|
#include <OgreSceneNode.h>
|
||||||
|
#include <OgreBone.h>
|
||||||
|
#include <OgreTechnique.h>
|
||||||
|
|
||||||
#include <extern/shiny/Main/Factory.hpp>
|
#include <extern/shiny/Main/Factory.hpp>
|
||||||
|
|
||||||
|
@ -71,27 +76,6 @@ float HeadAnimationTime::getValue() const
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
float WeaponAnimationTime::getValue() const
|
|
||||||
{
|
|
||||||
if (mWeaponGroup.empty())
|
|
||||||
return 0;
|
|
||||||
float current = mAnimation->getCurrentTime(mWeaponGroup);
|
|
||||||
if (current == -1)
|
|
||||||
return 0;
|
|
||||||
return current - mStartTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WeaponAnimationTime::setGroup(const std::string &group)
|
|
||||||
{
|
|
||||||
mWeaponGroup = group;
|
|
||||||
mStartTime = mAnimation->getStartTime(mWeaponGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WeaponAnimationTime::updateStartTime()
|
|
||||||
{
|
|
||||||
setGroup(mWeaponGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
static NpcAnimation::PartBoneMap createPartListMap()
|
static NpcAnimation::PartBoneMap createPartListMap()
|
||||||
{
|
{
|
||||||
NpcAnimation::PartBoneMap result;
|
NpcAnimation::PartBoneMap result;
|
||||||
|
@ -142,8 +126,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int v
|
||||||
mShowCarriedLeft(true),
|
mShowCarriedLeft(true),
|
||||||
mFirstPersonOffset(0.f, 0.f, 0.f),
|
mFirstPersonOffset(0.f, 0.f, 0.f),
|
||||||
mAlpha(1.f),
|
mAlpha(1.f),
|
||||||
mNpcType(Type_Normal),
|
mNpcType(Type_Normal)
|
||||||
mPitchFactor(0)
|
|
||||||
{
|
{
|
||||||
mNpc = mPtr.get<ESM::NPC>()->mBase;
|
mNpc = mPtr.get<ESM::NPC>()->mBase;
|
||||||
|
|
||||||
|
@ -527,20 +510,16 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
|
||||||
{
|
{
|
||||||
float pitch = mPtr.getRefData().getPosition().rot[0];
|
float pitch = mPtr.getRefData().getPosition().rot[0];
|
||||||
Ogre::Node *node = baseinst->getBone("Bip01 Neck");
|
Ogre::Node *node = baseinst->getBone("Bip01 Neck");
|
||||||
node->pitch(Ogre::Radian(pitch), Ogre::Node::TS_WORLD);
|
node->pitch(Ogre::Radian(-pitch), Ogre::Node::TS_WORLD);
|
||||||
|
|
||||||
// This has to be done before this function ends;
|
// This has to be done before this function ends;
|
||||||
// updateSkeletonInstance, below, touches the hands.
|
// updateSkeletonInstance, below, touches the hands.
|
||||||
node->translate(mFirstPersonOffset, Ogre::Node::TS_WORLD);
|
node->translate(mFirstPersonOffset, Ogre::Node::TS_WORLD);
|
||||||
}
|
}
|
||||||
else if (mPitchFactor > 0)
|
else
|
||||||
{
|
{
|
||||||
// In third person mode we may still need pitch for ranged weapon targeting
|
// In third person mode we may still need pitch for ranged weapon targeting
|
||||||
float pitch = mPtr.getRefData().getPosition().rot[0] * mPitchFactor;
|
pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst);
|
||||||
Ogre::Node *node = baseinst->getBone("Bip01 Spine2");
|
|
||||||
node->pitch(Ogre::Radian(pitch/2), Ogre::Node::TS_WORLD);
|
|
||||||
node = baseinst->getBone("Bip01 Spine1");
|
|
||||||
node->pitch(Ogre::Radian(pitch/2), Ogre::Node::TS_WORLD);
|
|
||||||
}
|
}
|
||||||
mFirstPersonOffset = 0.f; // reset the X, Y, Z offset for the next frame.
|
mFirstPersonOffset = 0.f; // reset the X, Y, Z offset for the next frame.
|
||||||
|
|
||||||
|
@ -690,13 +669,14 @@ void NpcAnimation::showWeapons(bool showWeapon)
|
||||||
{
|
{
|
||||||
MWWorld::InventoryStore &inv = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
|
MWWorld::InventoryStore &inv = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
|
||||||
MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
if(weapon != inv.end()) // special case for weapons
|
if(weapon != inv.end())
|
||||||
{
|
{
|
||||||
Ogre::Vector3 glowColor = getEnchantmentColor(*weapon);
|
Ogre::Vector3 glowColor = getEnchantmentColor(*weapon);
|
||||||
std::string mesh = MWWorld::Class::get(*weapon).getModel(*weapon);
|
std::string mesh = MWWorld::Class::get(*weapon).getModel(*weapon);
|
||||||
addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1,
|
addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1,
|
||||||
mesh, !weapon->getClass().getEnchantment(*weapon).empty(), &glowColor);
|
mesh, !weapon->getClass().getEnchantment(*weapon).empty(), &glowColor);
|
||||||
|
|
||||||
|
// Crossbows start out with a bolt attached
|
||||||
if (weapon->getTypeName() == typeid(ESM::Weapon).name() &&
|
if (weapon->getTypeName() == typeid(ESM::Weapon).name() &&
|
||||||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
||||||
{
|
{
|
||||||
|
@ -738,50 +718,24 @@ void NpcAnimation::showCarriedLeft(bool show)
|
||||||
removeIndividualPart(ESM::PRT_Shield);
|
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()
|
void NpcAnimation::attachArrow()
|
||||||
{
|
{
|
||||||
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
WeaponAnimation::attachArrow(mPtr);
|
||||||
MWWorld::ContainerStoreIterator weaponSlot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
|
||||||
if (weaponSlot != inv.end() && weaponSlot->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
|
|
||||||
showWeapons(true);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NifOgre::ObjectScenePtr weapon = mObjectParts[ESM::PRT_Weapon];
|
|
||||||
|
|
||||||
MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
|
||||||
if (ammo == inv.end())
|
|
||||||
return;
|
|
||||||
std::string model = ammo->getClass().getModel(*ammo);
|
|
||||||
|
|
||||||
mAmmunition = NifOgre::Loader::createObjects(weapon->mSkelBase, "ArrowBone", mInsert, model);
|
|
||||||
Ogre::Vector3 glowColor = getEnchantmentColor(*ammo);
|
|
||||||
setRenderProperties(mAmmunition, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha, 0,
|
|
||||||
!ammo->getClass().getEnchantment(*ammo).empty(), &glowColor);
|
|
||||||
|
|
||||||
std::for_each(mAmmunition->mEntities.begin(), mAmmunition->mEntities.end(), SetObjectGroup(MWWorld::InventoryStore::Slot_Ammunition));
|
|
||||||
std::for_each(mAmmunition->mParticles.begin(), mAmmunition->mParticles.end(), SetObjectGroup(MWWorld::InventoryStore::Slot_Ammunition));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NpcAnimation::releaseArrow()
|
void NpcAnimation::releaseArrow()
|
||||||
{
|
{
|
||||||
// Thrown weapons get detached now
|
WeaponAnimation::releaseArrow(mPtr);
|
||||||
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
|
||||||
MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
|
||||||
if (weapon != inv.end() && weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
|
|
||||||
{
|
|
||||||
showWeapons(false);
|
|
||||||
inv.remove(*weapon, 1, mPtr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// With bows and crossbows only the used arrow/bolt gets detached
|
|
||||||
MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
|
||||||
if (ammo == inv.end())
|
|
||||||
return;
|
|
||||||
inv.remove(*ammo, 1, mPtr);
|
|
||||||
mAmmunition.setNull();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew, bool playSound)
|
void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew, bool playSound)
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
|
||||||
|
#include "weaponanimation.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
struct NPC;
|
struct NPC;
|
||||||
|
@ -25,24 +27,7 @@ public:
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
class WeaponAnimationTime : public Ogre::ControllerValue<Ogre::Real>
|
class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener
|
||||||
{
|
|
||||||
private:
|
|
||||||
Animation* mAnimation;
|
|
||||||
std::string mWeaponGroup;
|
|
||||||
float mStartTime;
|
|
||||||
public:
|
|
||||||
WeaponAnimationTime(Animation* animation) : mAnimation(animation), mStartTime(0) {}
|
|
||||||
void setGroup(const std::string& group);
|
|
||||||
void updateStartTime();
|
|
||||||
|
|
||||||
virtual Ogre::Real getValue() const;
|
|
||||||
virtual void setValue(Ogre::Real value)
|
|
||||||
{ }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class NpcAnimation : public Animation, public MWWorld::InventoryStoreListener
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void equipmentChanged() { updateParts(); }
|
virtual void equipmentChanged() { updateParts(); }
|
||||||
|
@ -91,7 +76,6 @@ private:
|
||||||
Ogre::SharedPtr<WeaponAnimationTime> mWeaponAnimationTime;
|
Ogre::SharedPtr<WeaponAnimationTime> mWeaponAnimationTime;
|
||||||
|
|
||||||
float mAlpha;
|
float mAlpha;
|
||||||
float mPitchFactor;
|
|
||||||
|
|
||||||
void updateNpcBase();
|
void updateNpcBase();
|
||||||
|
|
||||||
|
@ -138,7 +122,10 @@ public:
|
||||||
virtual void attachArrow();
|
virtual void attachArrow();
|
||||||
virtual void releaseArrow();
|
virtual void releaseArrow();
|
||||||
|
|
||||||
NifOgre::ObjectScenePtr mAmmunition;
|
// 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 setViewMode(ViewMode viewMode);
|
||||||
|
|
||||||
|
|
|
@ -109,6 +109,7 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh)
|
||||||
{
|
{
|
||||||
uniqueID = uniqueID+1;
|
uniqueID = uniqueID+1;
|
||||||
sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID));
|
sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID));
|
||||||
|
sg->setOrigin(ptr.getRefData().getBaseNode()->getPosition());
|
||||||
mStaticGeometrySmall[ptr.getCell()] = sg;
|
mStaticGeometrySmall[ptr.getCell()] = sg;
|
||||||
|
|
||||||
sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance"));
|
sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance"));
|
||||||
|
@ -122,6 +123,7 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh)
|
||||||
{
|
{
|
||||||
uniqueID = uniqueID+1;
|
uniqueID = uniqueID+1;
|
||||||
sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID));
|
sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID));
|
||||||
|
sg->setOrigin(ptr.getRefData().getBaseNode()->getPosition());
|
||||||
mStaticGeometry[ptr.getCell()] = sg;
|
mStaticGeometry[ptr.getCell()] = sg;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include <OgreMeshManager.h>
|
#include <OgreMeshManager.h>
|
||||||
#include <OgreMaterialManager.h>
|
#include <OgreMaterialManager.h>
|
||||||
#include <OgreCamera.h>
|
#include <OgreCamera.h>
|
||||||
|
#include <OgreSceneNode.h>
|
||||||
|
#include <OgreMesh.h>
|
||||||
|
|
||||||
#include "renderconst.hpp"
|
#include "renderconst.hpp"
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include <OgreRenderTarget.h>
|
#include <OgreRenderTarget.h>
|
||||||
#include <OgreViewport.h>
|
#include <OgreViewport.h>
|
||||||
#include <OgreRoot.h>
|
#include <OgreRoot.h>
|
||||||
|
#include <OgreRenderTexture.h>
|
||||||
|
#include <OgreSceneNode.h>
|
||||||
|
|
||||||
#include <extern/shiny/Main/Factory.hpp>
|
#include <extern/shiny/Main/Factory.hpp>
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,14 @@
|
||||||
#include <OgreRoot.h>
|
#include <OgreRoot.h>
|
||||||
#include <OgreRenderWindow.h>
|
#include <OgreRenderWindow.h>
|
||||||
#include <OgreSceneManager.h>
|
#include <OgreSceneManager.h>
|
||||||
|
#include <OgreSceneNode.h>
|
||||||
#include <OgreViewport.h>
|
#include <OgreViewport.h>
|
||||||
#include <OgreCamera.h>
|
#include <OgreCamera.h>
|
||||||
#include <OgreTextureManager.h>
|
#include <OgreTextureManager.h>
|
||||||
#include <OgreHardwarePixelBuffer.h>
|
#include <OgreHardwarePixelBuffer.h>
|
||||||
#include <OgreControllerManager.h>
|
#include <OgreControllerManager.h>
|
||||||
#include <OgreMeshManager.h>
|
#include <OgreMeshManager.h>
|
||||||
|
#include <OgreRenderTexture.h>
|
||||||
|
|
||||||
#include <SDL_video.h>
|
#include <SDL_video.h>
|
||||||
|
|
||||||
|
@ -278,13 +280,12 @@ void RenderingManager::rotateObject(const MWWorld::Ptr &ptr)
|
||||||
|
|
||||||
if(ptr.getRefData().getHandle() == mCamera->getHandle() &&
|
if(ptr.getRefData().getHandle() == mCamera->getHandle() &&
|
||||||
!mCamera->isVanityOrPreviewModeEnabled())
|
!mCamera->isVanityOrPreviewModeEnabled())
|
||||||
mCamera->rotateCamera(rot, false);
|
mCamera->rotateCamera(-rot, false);
|
||||||
|
|
||||||
Ogre::Quaternion newo = Ogre::Quaternion(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Z);
|
Ogre::Quaternion newo = Ogre::Quaternion(Ogre::Radian(rot.z), Ogre::Vector3::NEGATIVE_UNIT_Z);
|
||||||
if(!MWWorld::Class::get(ptr).isActor())
|
if(!MWWorld::Class::get(ptr).isActor())
|
||||||
newo = Ogre::Quaternion(Ogre::Radian(-rot.x), Ogre::Vector3::UNIT_X) *
|
newo = Ogre::Quaternion(Ogre::Radian(rot.x), Ogre::Vector3::NEGATIVE_UNIT_X) *
|
||||||
Ogre::Quaternion(Ogre::Radian(-rot.y), Ogre::Vector3::UNIT_Y) * newo;
|
Ogre::Quaternion(Ogre::Radian(rot.y), Ogre::Vector3::NEGATIVE_UNIT_Y) * newo;
|
||||||
|
|
||||||
ptr.getRefData().getBaseNode()->setOrientation(newo);
|
ptr.getRefData().getBaseNode()->setOrientation(newo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,6 +650,18 @@ void RenderingManager::setGlare(bool glare)
|
||||||
mSkyManager->setGlare(glare);
|
mSkyManager->setGlare(glare);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RenderingManager::updateTerrain()
|
||||||
|
{
|
||||||
|
if (mTerrain)
|
||||||
|
{
|
||||||
|
// Avoid updating with dims.getCenter for each cell. Player position should be good enough
|
||||||
|
mTerrain->update(mRendering.getCamera()->getRealPosition());
|
||||||
|
mTerrain->syncLoad();
|
||||||
|
// need to update again so the chunks that were just loaded can be made visible
|
||||||
|
mTerrain->update(mRendering.getCamera()->getRealPosition());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RenderingManager::requestMap(MWWorld::CellStore* cell)
|
void RenderingManager::requestMap(MWWorld::CellStore* cell)
|
||||||
{
|
{
|
||||||
if (cell->getCell()->isExterior())
|
if (cell->getCell()->isExterior())
|
||||||
|
@ -659,9 +672,6 @@ void RenderingManager::requestMap(MWWorld::CellStore* cell)
|
||||||
Ogre::Vector2 center (cell->getCell()->getGridX() + 0.5, cell->getCell()->getGridY() + 0.5);
|
Ogre::Vector2 center (cell->getCell()->getGridX() + 0.5, cell->getCell()->getGridY() + 0.5);
|
||||||
dims.merge(mTerrain->getWorldBoundingBox(center));
|
dims.merge(mTerrain->getWorldBoundingBox(center));
|
||||||
|
|
||||||
if (dims.isFinite())
|
|
||||||
mTerrain->update(dims.getCenter());
|
|
||||||
|
|
||||||
mLocalMap->requestMap(cell, dims.getMinimum().z, dims.getMaximum().z);
|
mLocalMap->requestMap(cell, dims.getMinimum().z, dims.getMaximum().z);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -981,13 +991,11 @@ void RenderingManager::screenshot(Image &image, int w, int h)
|
||||||
|
|
||||||
Ogre::PixelFormat pf = rt->suggestPixelFormat();
|
Ogre::PixelFormat pf = rt->suggestPixelFormat();
|
||||||
|
|
||||||
std::vector<Ogre::uchar> data;
|
image.loadDynamicImage(
|
||||||
data.resize(w * h * Ogre::PixelUtil::getNumElemBytes(pf));
|
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
|
||||||
Ogre::PixelBox pb(w, h, 1, pf, &data[0]);
|
);
|
||||||
rt->copyContentsToMemory(pb);
|
rt->copyContentsToMemory(image.getPixelBox()); // getPixelBox returns a box sharing the same memory as the image
|
||||||
|
|
||||||
image.loadDynamicImage(&data[0], w, h, pf);
|
|
||||||
|
|
||||||
Ogre::TextureManager::getSingleton().remove(tempName);
|
Ogre::TextureManager::getSingleton().remove(tempName);
|
||||||
mRendering.getCamera()->setAspectRatio(oldAspect);
|
mRendering.getCamera()->setAspectRatio(oldAspect);
|
||||||
|
@ -1045,20 +1053,16 @@ void RenderingManager::enableTerrain(bool enable)
|
||||||
{
|
{
|
||||||
if (!mTerrain)
|
if (!mTerrain)
|
||||||
{
|
{
|
||||||
Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
mTerrain = new Terrain::World(mRendering.getScene(), new MWRender::TerrainStorage(), RV_Terrain,
|
||||||
Loading::ScopedLoad load(listener);
|
|
||||||
mTerrain = new Terrain::World(listener, mRendering.getScene(), new MWRender::TerrainStorage(), RV_Terrain,
|
|
||||||
Settings::Manager::getBool("distant land", "Terrain"),
|
Settings::Manager::getBool("distant land", "Terrain"),
|
||||||
Settings::Manager::getBool("shader", "Terrain"));
|
Settings::Manager::getBool("shader", "Terrain"), Terrain::Align_XY, 1, 64);
|
||||||
mTerrain->applyMaterials(Settings::Manager::getBool("enabled", "Shadows"),
|
mTerrain->applyMaterials(Settings::Manager::getBool("enabled", "Shadows"),
|
||||||
Settings::Manager::getBool("split", "Shadows"));
|
Settings::Manager::getBool("split", "Shadows"));
|
||||||
mTerrain->update(mRendering.getCamera()->getRealPosition());
|
mTerrain->update(mRendering.getCamera()->getRealPosition());
|
||||||
mTerrain->setLoadingListener(NULL);
|
|
||||||
}
|
}
|
||||||
mTerrain->setVisible(true);
|
mTerrain->setVisible(true);
|
||||||
}
|
}
|
||||||
else
|
else if (mTerrain)
|
||||||
if (mTerrain)
|
|
||||||
mTerrain->setVisible(false);
|
mTerrain->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1069,7 +1073,7 @@ float RenderingManager::getCameraDistance() const
|
||||||
|
|
||||||
void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const Vector3 &worldPosition, float scale)
|
void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const Vector3 &worldPosition, float scale)
|
||||||
{
|
{
|
||||||
mEffectManager->addEffect(model, "", worldPosition, scale);
|
mEffectManager->addEffect(model, texture, worldPosition, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -180,6 +180,10 @@ public:
|
||||||
void removeWaterRippleEmitter (const MWWorld::Ptr& ptr);
|
void removeWaterRippleEmitter (const MWWorld::Ptr& ptr);
|
||||||
void updateWaterRippleEmitterPtr (const MWWorld::Ptr& old, 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);
|
void requestMap (MWWorld::CellStore* cell);
|
||||||
///< request the local map for a cell
|
///< request the local map for a cell
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
#include <OgreStringConverter.h>
|
#include <OgreStringConverter.h>
|
||||||
#include <OgreHardwarePixelBuffer.h>
|
#include <OgreHardwarePixelBuffer.h>
|
||||||
#include <OgreRoot.h>
|
#include <OgreRoot.h>
|
||||||
|
#include <OgreRectangle2D.h>
|
||||||
|
#include <OgreSceneNode.h>
|
||||||
|
#include <OgreRenderTexture.h>
|
||||||
|
#include <OgreViewport.h>
|
||||||
|
|
||||||
#include <extern/shiny/Main/Factory.hpp>
|
#include <extern/shiny/Main/Factory.hpp>
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include <OgreShadowCameraSetupPSSM.h>
|
#include <OgreShadowCameraSetupPSSM.h>
|
||||||
#include <OgreHardwarePixelBuffer.h>
|
#include <OgreHardwarePixelBuffer.h>
|
||||||
#include <OgreCamera.h>
|
#include <OgreCamera.h>
|
||||||
|
#include <OgreRenderTexture.h>
|
||||||
|
#include <OgreViewport.h>
|
||||||
|
|
||||||
#include <extern/shiny/Main/Factory.hpp>
|
#include <extern/shiny/Main/Factory.hpp>
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <OgreBillboardSet.h>
|
#include <OgreBillboardSet.h>
|
||||||
#include <OgreEntity.h>
|
#include <OgreEntity.h>
|
||||||
#include <OgreSubEntity.h>
|
#include <OgreSubEntity.h>
|
||||||
|
#include <OgreTechnique.h>
|
||||||
|
|
||||||
#include <OgreMeshManager.h>
|
#include <OgreMeshManager.h>
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <OgreStringConverter.h>
|
#include <OgreStringConverter.h>
|
||||||
#include <OgreRenderSystem.h>
|
#include <OgreRenderSystem.h>
|
||||||
#include <OgreResourceGroupManager.h>
|
#include <OgreResourceGroupManager.h>
|
||||||
|
#include <OgreResourceBackgroundQueue.h>
|
||||||
#include <OgreRoot.h>
|
#include <OgreRoot.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
@ -13,12 +14,14 @@
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
|
#include <components/terrain/quadtreenode.hpp>
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
|
|
||||||
Ogre::AxisAlignedBox TerrainStorage::getBounds()
|
void TerrainStorage::getBounds(float& minX, float& maxX, float& minY, float& maxY)
|
||||||
{
|
{
|
||||||
int minX = 0, minY = 0, maxX = 0, maxY = 0;
|
minX = 0, minY = 0, maxX = 0, maxY = 0;
|
||||||
|
|
||||||
const MWWorld::ESMStore &esmStore =
|
const MWWorld::ESMStore &esmStore =
|
||||||
MWBase::Environment::get().getWorld()->getStore();
|
MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
@ -39,8 +42,6 @@ namespace MWRender
|
||||||
// since grid coords are at cell origin, we need to add 1 cell
|
// since grid coords are at cell origin, we need to add 1 cell
|
||||||
maxX += 1;
|
maxX += 1;
|
||||||
maxY += 1;
|
maxY += 1;
|
||||||
|
|
||||||
return Ogre::AxisAlignedBox(minX, minY, 0, maxX, maxY, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ESM::Land* TerrainStorage::getLand(int cellX, int cellY)
|
ESM::Land* TerrainStorage::getLand(int cellX, int cellY)
|
||||||
|
@ -48,10 +49,6 @@ namespace MWRender
|
||||||
const MWWorld::ESMStore &esmStore =
|
const MWWorld::ESMStore &esmStore =
|
||||||
MWBase::Environment::get().getWorld()->getStore();
|
MWBase::Environment::get().getWorld()->getStore();
|
||||||
ESM::Land* land = esmStore.get<ESM::Land>().search(cellX, cellY);
|
ESM::Land* land = esmStore.get<ESM::Land>().search(cellX, cellY);
|
||||||
// Load the data we are definitely going to need
|
|
||||||
int mask = ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX;
|
|
||||||
if (land && !land->isDataLoaded(mask))
|
|
||||||
land->loadData(mask);
|
|
||||||
return land;
|
return land;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,10 +166,10 @@ namespace MWRender
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerrainStorage::fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center,
|
void TerrainStorage::fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center, Terrain::Alignment align,
|
||||||
Ogre::HardwareVertexBufferSharedPtr vertexBuffer,
|
std::vector<float>& positions,
|
||||||
Ogre::HardwareVertexBufferSharedPtr normalBuffer,
|
std::vector<float>& normals,
|
||||||
Ogre::HardwareVertexBufferSharedPtr colourBuffer)
|
std::vector<Ogre::uint8>& colours)
|
||||||
{
|
{
|
||||||
// LOD level n means every 2^n-th vertex is kept
|
// LOD level n means every 2^n-th vertex is kept
|
||||||
size_t increment = 1 << lodLevel;
|
size_t increment = 1 << lodLevel;
|
||||||
|
@ -186,11 +183,8 @@ namespace MWRender
|
||||||
|
|
||||||
size_t numVerts = size*(ESM::Land::LAND_SIZE-1)/increment + 1;
|
size_t numVerts = size*(ESM::Land::LAND_SIZE-1)/increment + 1;
|
||||||
|
|
||||||
std::vector<uint8_t> colors;
|
colours.resize(numVerts*numVerts*4);
|
||||||
colors.resize(numVerts*numVerts*4);
|
|
||||||
std::vector<float> positions;
|
|
||||||
positions.resize(numVerts*numVerts*3);
|
positions.resize(numVerts*numVerts*3);
|
||||||
std::vector<float> normals;
|
|
||||||
normals.resize(numVerts*numVerts*3);
|
normals.resize(numVerts*numVerts*3);
|
||||||
|
|
||||||
Ogre::Vector3 normal;
|
Ogre::Vector3 normal;
|
||||||
|
@ -276,7 +270,7 @@ namespace MWRender
|
||||||
color.a = 1;
|
color.a = 1;
|
||||||
Ogre::uint32 rsColor;
|
Ogre::uint32 rsColor;
|
||||||
Ogre::Root::getSingleton().getRenderSystem()->convertColourValue(color, &rsColor);
|
Ogre::Root::getSingleton().getRenderSystem()->convertColourValue(color, &rsColor);
|
||||||
memcpy(&colors[vertX*numVerts*4 + vertY*4], &rsColor, sizeof(Ogre::uint32));
|
memcpy(&colours[vertX*numVerts*4 + vertY*4], &rsColor, sizeof(Ogre::uint32));
|
||||||
|
|
||||||
++vertX;
|
++vertX;
|
||||||
}
|
}
|
||||||
|
@ -289,10 +283,6 @@ namespace MWRender
|
||||||
assert(vertX_ == numVerts); // Ensure we covered whole area
|
assert(vertX_ == numVerts); // Ensure we covered whole area
|
||||||
}
|
}
|
||||||
assert(vertY_ == numVerts); // Ensure we covered whole area
|
assert(vertY_ == numVerts); // Ensure we covered whole area
|
||||||
|
|
||||||
vertexBuffer->writeData(0, vertexBuffer->getSizeInBytes(), &positions[0], true);
|
|
||||||
normalBuffer->writeData(0, normalBuffer->getSizeInBytes(), &normals[0], true);
|
|
||||||
colourBuffer->writeData(0, colourBuffer->getSizeInBytes(), &colors[0], true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TerrainStorage::UniqueTextureId TerrainStorage::getVtexIndexAt(int cellX, int cellY,
|
TerrainStorage::UniqueTextureId TerrainStorage::getVtexIndexAt(int cellX, int cellY,
|
||||||
|
@ -318,9 +308,6 @@ namespace MWRender
|
||||||
ESM::Land* land = getLand(cellX, cellY);
|
ESM::Land* land = getLand(cellX, cellY);
|
||||||
if (land)
|
if (land)
|
||||||
{
|
{
|
||||||
if (!land->isDataLoaded(ESM::Land::DATA_VTEX))
|
|
||||||
land->loadData(ESM::Land::DATA_VTEX);
|
|
||||||
|
|
||||||
int tex = land->mLandData->mTextures[y * ESM::Land::LAND_TEXTURE_SIZE + x];
|
int tex = land->mLandData->mTextures[y * ESM::Land::LAND_TEXTURE_SIZE + x];
|
||||||
if (tex == 0)
|
if (tex == 0)
|
||||||
return std::make_pair(0,0); // vtex 0 is always the base texture, regardless of plugin
|
return std::make_pair(0,0); // vtex 0 is always the base texture, regardless of plugin
|
||||||
|
@ -345,8 +332,24 @@ namespace MWRender
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TerrainStorage::getBlendmaps (const std::vector<Terrain::QuadTreeNode*>& nodes, std::vector<Terrain::LayerCollection>& out, bool pack)
|
||||||
|
{
|
||||||
|
for (std::vector<Terrain::QuadTreeNode*>::const_iterator it = nodes.begin(); it != nodes.end(); ++it)
|
||||||
|
{
|
||||||
|
out.push_back(Terrain::LayerCollection());
|
||||||
|
out.back().mTarget = *it;
|
||||||
|
getBlendmapsImpl((*it)->getSize(), (*it)->getCenter(), pack, out.back().mBlendmaps, out.back().mLayers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TerrainStorage::getBlendmaps(float chunkSize, const Ogre::Vector2 &chunkCenter,
|
void TerrainStorage::getBlendmaps(float chunkSize, const Ogre::Vector2 &chunkCenter,
|
||||||
bool pack, std::vector<Ogre::TexturePtr> &blendmaps, std::vector<Terrain::LayerInfo> &layerList)
|
bool pack, std::vector<Ogre::PixelBox> &blendmaps, std::vector<Terrain::LayerInfo> &layerList)
|
||||||
|
{
|
||||||
|
getBlendmapsImpl(chunkSize, chunkCenter, pack, blendmaps, layerList);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainStorage::getBlendmapsImpl(float chunkSize, const Ogre::Vector2 &chunkCenter,
|
||||||
|
bool pack, std::vector<Ogre::PixelBox> &blendmaps, std::vector<Terrain::LayerInfo> &layerList)
|
||||||
{
|
{
|
||||||
// TODO - blending isn't completely right yet; the blending radius appears to be
|
// 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
|
// different at a cell transition (2 vertices, not 4), so we may need to create a larger blendmap
|
||||||
|
@ -391,16 +394,14 @@ namespace MWRender
|
||||||
|
|
||||||
// Second iteration - create and fill in the blend maps
|
// Second iteration - create and fill in the blend maps
|
||||||
const int blendmapSize = ESM::Land::LAND_TEXTURE_SIZE+1;
|
const int blendmapSize = ESM::Land::LAND_TEXTURE_SIZE+1;
|
||||||
std::vector<Ogre::uchar> data;
|
|
||||||
data.resize(blendmapSize * blendmapSize * channels, 0);
|
|
||||||
|
|
||||||
for (int i=0; i<numBlendmaps; ++i)
|
for (int i=0; i<numBlendmaps; ++i)
|
||||||
{
|
{
|
||||||
Ogre::PixelFormat format = pack ? Ogre::PF_A8B8G8R8 : Ogre::PF_A8;
|
Ogre::PixelFormat format = pack ? Ogre::PF_A8B8G8R8 : Ogre::PF_A8;
|
||||||
static int count=0;
|
|
||||||
Ogre::TexturePtr map = Ogre::TextureManager::getSingleton().createManual("terrain/blend/"
|
Ogre::uchar* pData =
|
||||||
+ Ogre::StringConverter::toString(count++), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
OGRE_ALLOC_T(Ogre::uchar, blendmapSize*blendmapSize*channels, Ogre::MEMCATEGORY_GENERAL);
|
||||||
Ogre::TEX_TYPE_2D, blendmapSize, blendmapSize, 0, format);
|
memset(pData, 0, blendmapSize*blendmapSize*channels);
|
||||||
|
|
||||||
for (int y=0; y<blendmapSize; ++y)
|
for (int y=0; y<blendmapSize; ++y)
|
||||||
{
|
{
|
||||||
|
@ -412,16 +413,12 @@ namespace MWRender
|
||||||
int channel = pack ? std::max(0, (layerIndex-1) % 4) : 0;
|
int channel = pack ? std::max(0, (layerIndex-1) % 4) : 0;
|
||||||
|
|
||||||
if (blendIndex == i)
|
if (blendIndex == i)
|
||||||
data[y*blendmapSize*channels + x*channels + channel] = 255;
|
pData[y*blendmapSize*channels + x*channels + channel] = 255;
|
||||||
else
|
else
|
||||||
data[y*blendmapSize*channels + x*channels + channel] = 0;
|
pData[y*blendmapSize*channels + x*channels + channel] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
blendmaps.push_back(Ogre::PixelBox(blendmapSize, blendmapSize, 1, format, pData));
|
||||||
// All done, upload to GPU
|
|
||||||
Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size()));
|
|
||||||
map->loadRawData(stream, blendmapSize, blendmapSize, format);
|
|
||||||
blendmaps.push_back(map);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,6 +540,12 @@ namespace MWRender
|
||||||
info.mSpecular = true;
|
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;
|
mLayerInfoMap[texture] = info;
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
#ifndef MWRENDER_TERRAINSTORAGE_H
|
#ifndef MWRENDER_TERRAINSTORAGE_H
|
||||||
#define MWRENDER_TERRAINSTORAGE_H
|
#define MWRENDER_TERRAINSTORAGE_H
|
||||||
|
|
||||||
|
#include <components/esm/loadland.hpp>
|
||||||
|
#include <components/esm/loadltex.hpp>
|
||||||
|
|
||||||
#include <components/terrain/storage.hpp>
|
#include <components/terrain/storage.hpp>
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
|
@ -14,10 +17,10 @@ namespace MWRender
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// Get bounds of the whole terrain in cell units
|
/// Get bounds of the whole terrain in cell units
|
||||||
virtual Ogre::AxisAlignedBox getBounds();
|
virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY);
|
||||||
|
|
||||||
/// Get the minimum and maximum heights of a terrain chunk.
|
/// Get the minimum and maximum heights of a terrain region.
|
||||||
/// @note Should only be called for chunks <= 1 cell, i.e. leafs of the quad tree.
|
/// @note Will only be called for chunks with size = minBatchSize, i.e. leafs of the quad tree.
|
||||||
/// Larger chunks can simply merge AABB of children.
|
/// Larger chunks can simply merge AABB of children.
|
||||||
/// @param size size of the chunk in cell units
|
/// @param size size of the chunk in cell units
|
||||||
/// @param center center of the chunk in cell units
|
/// @param center center of the chunk in cell units
|
||||||
|
@ -27,20 +30,23 @@ namespace MWRender
|
||||||
virtual bool getMinMaxHeights (float size, const Ogre::Vector2& center, float& min, float& max);
|
virtual bool getMinMaxHeights (float size, const Ogre::Vector2& center, float& min, float& max);
|
||||||
|
|
||||||
/// Fill vertex buffers for a terrain chunk.
|
/// 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.
|
||||||
/// @param lodLevel LOD level, 0 = most detailed
|
/// @param lodLevel LOD level, 0 = most detailed
|
||||||
/// @param size size of the terrain chunk in cell units
|
/// @param size size of the terrain chunk in cell units
|
||||||
/// @param center center of the chunk in cell units
|
/// @param center center of the chunk in cell units
|
||||||
/// @param vertexBuffer buffer to write vertices
|
/// @param positions buffer to write vertices
|
||||||
/// @param normalBuffer buffer to write vertex normals
|
/// @param normals buffer to write vertex normals
|
||||||
/// @param colourBuffer buffer to write vertex colours
|
/// @param colours buffer to write vertex colours
|
||||||
virtual void fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center,
|
virtual void fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center, Terrain::Alignment align,
|
||||||
Ogre::HardwareVertexBufferSharedPtr vertexBuffer,
|
std::vector<float>& positions,
|
||||||
Ogre::HardwareVertexBufferSharedPtr normalBuffer,
|
std::vector<float>& normals,
|
||||||
Ogre::HardwareVertexBufferSharedPtr colourBuffer);
|
std::vector<Ogre::uint8>& colours);
|
||||||
|
|
||||||
/// Create textures holding layer blend values for a terrain chunk.
|
/// 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
|
/// @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.
|
/// have to do a ridiculous amount of different layers. For larger chunks, composite maps should be used.
|
||||||
|
/// @note May be called from *one* background thread.
|
||||||
/// @param chunkSize size of the terrain chunk in cell units
|
/// @param chunkSize size of the terrain chunk in cell units
|
||||||
/// @param chunkCenter center of the chunk in cell units
|
/// @param chunkCenter center of the chunk in cell units
|
||||||
/// @param pack Whether to pack blend values for up to 4 layers into one texture (one in each channel) -
|
/// @param pack Whether to pack blend values for up to 4 layers into one texture (one in each channel) -
|
||||||
|
@ -49,9 +55,21 @@ namespace MWRender
|
||||||
/// @param blendmaps created blendmaps will be written here
|
/// @param blendmaps created blendmaps will be written here
|
||||||
/// @param layerList names of the layer textures used 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,
|
virtual void getBlendmaps (float chunkSize, const Ogre::Vector2& chunkCenter, bool pack,
|
||||||
std::vector<Ogre::TexturePtr>& blendmaps,
|
std::vector<Ogre::PixelBox>& blendmaps,
|
||||||
std::vector<Terrain::LayerInfo>& layerList);
|
std::vector<Terrain::LayerInfo>& 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 *one* background thread.
|
||||||
|
/// @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<Terrain::QuadTreeNode*>& nodes, std::vector<Terrain::LayerCollection>& out, bool pack);
|
||||||
|
|
||||||
virtual float getHeightAt (const Ogre::Vector3& worldPos);
|
virtual float getHeightAt (const Ogre::Vector3& worldPos);
|
||||||
|
|
||||||
virtual Terrain::LayerInfo getDefaultLayer();
|
virtual Terrain::LayerInfo getDefaultLayer();
|
||||||
|
@ -81,6 +99,11 @@ namespace MWRender
|
||||||
std::map<std::string, Terrain::LayerInfo> mLayerInfoMap;
|
std::map<std::string, Terrain::LayerInfo> mLayerInfoMap;
|
||||||
|
|
||||||
Terrain::LayerInfo getLayerInfo(const std::string& texture);
|
Terrain::LayerInfo getLayerInfo(const std::string& texture);
|
||||||
|
|
||||||
|
// Non-virtual
|
||||||
|
void getBlendmapsImpl (float chunkSize, const Ogre::Vector2& chunkCenter, bool pack,
|
||||||
|
std::vector<Ogre::PixelBox>& blendmaps,
|
||||||
|
std::vector<Terrain::LayerInfo>& layerList);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue