Merge remote-tracking branch 'upstream/master' into wizard

loadfix
pvdk 11 years ago
commit 8fe837ae6e

@ -7,7 +7,6 @@ branches:
- /openmw-.*$/
before_install:
- 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 apt-add-repository ppa:openmw/openmw
- sudo apt-get update -qq

@ -6,34 +6,63 @@ if (APPLE)
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}")
endif (APPLE)
# Macros
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
include(OpenMWMacros)
# 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)
get_git_tag_revision(TAGHASH --tags --max-count=1)
get_git_head_revision(REFSPEC COMMITHASH)
git_describe(VERSION --tags ${TAGHASH})
string(REGEX MATCH "^openmw-[^0-9]*[0-9]+\\.[0-9]+\\.[0-9]+.*" MATCH "${VERSION}")
if(MATCH)
string(REGEX REPLACE "^openmw-([0-9]+)\\..*" "\\1" GIT_VERSION_MAJOR "${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" 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_COMMITHASH "${COMMITHASH}")
set(OPENMW_VERSION_TAGHASH "${TAGHASH}")
endif(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION})
message(STATUS "OpenMW version ${OPENMW_VERSION}")
else(MATCH)
message(WARNING "Failed to get valid version information from Git")
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)
include(GetGitRevisionDescription)
get_git_tag_revision(TAGHASH --tags --max-count=1 "HEAD...")
get_git_head_revision(REFSPEC COMMITHASH)
git_describe(VERSION --tags ${TAGHASH})
string(REGEX MATCH "^openmw-[^0-9]*[0-9]+\\.[0-9]+\\.[0-9]+.*" MATCH "${VERSION}")
if (MATCH)
string(REGEX REPLACE "^openmw-([0-9]+)\\..*" "\\1" OPENMW_VERSION_MAJOR "${VERSION}")
string(REGEX REPLACE "^openmw-[0-9]+\\.([0-9]+).*" "\\1" OPENMW_VERSION_MINOR "${VERSION}")
string(REGEX REPLACE "^openmw-[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" OPENMW_VERSION_RELEASE "${VERSION}")
set(OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}")
set(OPENMW_VERSION_TAGHASH "${TAGHASH}")
message(STATUS "Configuring OpenMW ${OPENMW_VERSION}...")
else (MATCH)
message(FATAL_ERROR "Failed to get valid version information from Git")
endif (MATCH)
# Macros
include(OpenMWMacros)
# doxygen main page
@ -210,6 +239,14 @@ if (UNIX AND NOT APPLE)
find_package (Threads)
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)
check_include_file_cxx(unordered_map HAVE_UNORDERED_MAP)
if (HAVE_UNORDERED_MAP)

@ -79,17 +79,20 @@ Launcher::MainDialog::MainDialog(QWidget *parent)
QString revision(OPENMW_VERSION_COMMITHASH);
QString tag(OPENMW_VERSION_TAGHASH);
if (revision == tag) {
versionLabel->setText(tr("OpenMW %0 release").arg(OPENMW_VERSION));
} else {
versionLabel->setText(tr("OpenMW development (%0)").arg(revision.left(10)));
}
if (!revision.isEmpty() && !tag.isEmpty())
{
if (revision == tag) {
versionLabel->setText(tr("OpenMW %0 release").arg(OPENMW_VERSION));
} else {
versionLabel->setText(tr("OpenMW development (%0)").arg(revision.left(10)));
}
// Add the compile date and time
versionLabel->setToolTip(tr("Compiled on %0 %1").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(),
QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate),
QLocale(QLocale::C).toTime(QString(__TIME__).simplified(),
QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate)));
// Add the compile date and time
versionLabel->setToolTip(tr("Compiled on %0 %1").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(),
QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate),
QLocale(QLocale::C).toTime(QString(__TIME__).simplified(),
QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate)));
}
createIcons();
}

@ -64,8 +64,12 @@ opencs_units (view/world
)
opencs_units (view/render
scenewidget
)
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
)
opencs_units_noqt (view/render
navigation navigation1st navigationfree navigationorbit
)
opencs_units_noqt (view/world
dialoguesubview subviews

@ -9,15 +9,22 @@
#include <OgreRoot.h>
#include <OgreRenderWindow.h>
#include <components/ogreinit/ogreinit.hpp>
#include "model/doc/document.hpp"
#include "model/world/data.hpp"
CS::Editor::Editor()
: mDocumentManager (mCfgMgr), mViewManager (mDocumentManager)
CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
: mDocumentManager (mCfgMgr), mViewManager (mDocumentManager),
mIpcServerName ("org.openmw.OpenCS")
{
mIpcServerName = "org.openmw.OpenCS";
Files::PathContainer dataDirs = readConfig();
setupDataFiles (dataDirs);
CSMSettings::UserSettings::instance().loadSettings ("opencs.cfg");
setupDataFiles();
ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string());
mNewGame.setLocalData (mLocal);
mFileDialog.setLocalData (mLocal);
@ -42,7 +49,16 @@ CS::Editor::Editor()
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::options_description desc("Syntax: opencs <options>\nAllowed options");
@ -58,6 +74,8 @@ void CS::Editor::setupDataFiles()
mCfgMgr.readConfiguration(variables, desc);
mDocumentManager.setResourceDir (variables["resources"].as<std::string>());
Files::PathContainer dataDirs, dataLocal;
if (!variables["data"].empty()) {
dataDirs = Files::PathContainer(variables["data"].as<Files::PathContainer>());
@ -83,23 +101,11 @@ void CS::Editor::setupDataFiles()
messageBox.exec();
QApplication::exit (1);
return;
}
dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end());
mDocumentManager.setResourceDir (variables["resources"].as<std::string>());
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);
return dataDirs;
}
void CS::Editor::createGame()
@ -210,8 +216,6 @@ int CS::Editor::run()
if (mLocal.empty())
return 1;
// temporarily disable OGRE-integration (need to fix path problem first)
#if 0
// TODO: setting
Ogre::Root::getSingleton().setRenderSystem(Ogre::Root::getSingleton().getRenderSystemByName("OpenGL Rendering Subsystem"));
@ -228,7 +232,6 @@ int CS::Editor::run()
#endif
Ogre::RenderWindow* hiddenWindow = Ogre::Root::getSingleton().createRenderWindow("InactiveHidden", 1, 1, false, &params);
hiddenWindow->setActive(false);
#endif
mStartup.show();

@ -10,6 +10,8 @@
#include <components/files/configurationmanager.hpp>
#endif
#include <components/files/multidircollection.hpp>
#include "model/settings/usersettings.hpp"
#include "model/doc/documentmanager.hpp"
@ -20,6 +22,11 @@
#include "view/settings/usersettingsdialog.hpp"
namespace OgreInit
{
class OgreInit;
}
namespace CS
{
class Editor : public QObject
@ -37,7 +44,10 @@ namespace CS
boost::filesystem::path mLocal;
void setupDataFiles();
void setupDataFiles (const Files::PathContainer& dataDirs);
Files::PathContainer readConfig();
///< \return data paths
// not implemented
Editor (const Editor&);
@ -45,7 +55,7 @@ namespace CS
public:
Editor();
Editor (OgreInit::OgreInit& ogreInit);
bool makeIPCServer();
void connectToIPCServer();

@ -40,15 +40,9 @@ int main(int argc, char *argv[])
{
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.init("./opencsOgre.log"); // TODO log path?
#endif
Application application (argc, argv);
#ifdef Q_OS_MAC
QDir dir(QCoreApplication::applicationDirPath());
@ -66,12 +60,12 @@ int main(int argc, char *argv[])
QStringList libraryPaths;
libraryPaths << pluginsPath.path() << QCoreApplication::applicationDirPath();
mApplication.setLibraryPaths(libraryPaths);
application.setLibraryPaths(libraryPaths);
#endif
mApplication.setWindowIcon (QIcon (":./opencs.png"));
application.setWindowIcon (QIcon (":./opencs.png"));
CS::Editor editor;
CS::Editor editor (ogreInit);
if(!editor.makeIPCServer())
{

@ -98,7 +98,7 @@ namespace CSMWorld
UniversalId::Type type = UniversalId::Type_None);
///< \param type Will be ignored, unless the collection supports multiple record types
virtual void cloneRecord(const std::string& origin,
virtual void cloneRecord(const std::string& origin,
const std::string& destination,
const UniversalId::Type type);
@ -198,7 +198,7 @@ namespace CSMWorld
}
template<typename ESXRecordT, typename IdAccessorT>
void Collection<ESXRecordT, IdAccessorT>::cloneRecord(const std::string& origin,
void Collection<ESXRecordT, IdAccessorT>::cloneRecord(const std::string& origin,
const std::string& destination,
const UniversalId::Type type)
{

@ -74,7 +74,7 @@ namespace CSMWorld
UniversalId::Type type = UniversalId::Type_None) = 0;
///< If the record type does not match, an exception is thrown.
virtual void cloneRecord(const std::string& origin,
virtual void cloneRecord(const std::string& origin,
const std::string& destination,
const UniversalId::Type type) = 0;

@ -247,12 +247,12 @@ CSMWorld::Data::Data() : mRefs (mCells)
addModel (new IdTable (&mSpells), UniversalId::Type_Spells, UniversalId::Type_Spell);
addModel (new IdTable (&mTopics), UniversalId::Type_Topics, UniversalId::Type_Topic);
addModel (new IdTable (&mJournals), UniversalId::Type_Journals, UniversalId::Type_Journal);
addModel (new IdTable (&mTopicInfos), UniversalId::Type_TopicInfos, UniversalId::Type_TopicInfo);
addModel (new IdTable (&mJournalInfos), UniversalId::Type_JournalInfos, UniversalId::Type_JournalInfo);
addModel (new IdTable (&mCells), UniversalId::Type_Cells, UniversalId::Type_Cell);
addModel (new IdTable (&mTopicInfos, IdTable::Reordering_WithinTopic), UniversalId::Type_TopicInfos, UniversalId::Type_TopicInfo);
addModel (new IdTable (&mJournalInfos, IdTable::Reordering_WithinTopic), UniversalId::Type_JournalInfos, UniversalId::Type_JournalInfo);
addModel (new IdTable (&mCells, IdTable::Reordering_None, IdTable::Viewing_Id), UniversalId::Type_Cells, UniversalId::Type_Cell);
addModel (new IdTable (&mReferenceables), UniversalId::Type_Referenceables,
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);
}

@ -4,8 +4,9 @@
#include "collectionbase.hpp"
#include "columnbase.hpp"
CSMWorld::IdTable::IdTable (CollectionBase *idCollection, Reordering reordering)
: mIdCollection (idCollection), mReordering (reordering)
CSMWorld::IdTable::IdTable (CollectionBase *idCollection, Reordering reordering,
Viewing viewing)
: mIdCollection (idCollection), mReordering (reordering), mViewing (viewing)
{}
CSMWorld::IdTable::~IdTable()
@ -188,4 +189,45 @@ void CSMWorld::IdTable::reorderRows (int baseIndex, const std::vector<int>& newO
CSMWorld::IdTable::Reordering CSMWorld::IdTable::getReordering() const
{
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
};
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:
CollectionBase *mIdCollection;
Reordering mReordering;
Viewing mViewing;
// not implemented
IdTable (const IdTable&);
@ -36,7 +46,8 @@ namespace CSMWorld
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.
virtual ~IdTable();
@ -63,8 +74,8 @@ namespace CSMWorld
void addRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None);
///< \param type Will be ignored, unless the collection supports multiple record types
void cloneRecord(const std::string& origin,
const std::string& destination,
void cloneRecord(const std::string& origin,
const std::string& destination,
UniversalId::Type type = UniversalId::Type_None);
QModelIndex getModelIndex (const std::string& id, int column) const;
@ -86,6 +97,12 @@ namespace CSMWorld
/// given in \a newOrder (baseIndex+newOrder[0] specifies the new index of row baseIndex).
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_SubRecord, CSMWorld::UniversalId::Type_Reference, "Reference", 0 },
{ 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
};
static const TypeData sIndexArg[] =
{
{ 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
};
}

@ -16,4 +16,6 @@ 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);
///< Default implementation: ignored
virtual void useHint (const std::string& hint);
///< Default implementation: ignored
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
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);
connect (regionMap, SIGNAL (triggered()), this, SLOT (addRegionMapSubView()));
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);
}
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
/// number is exceeded
@ -322,12 +318,15 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id)
SubView *view = mSubViewFactory.makeSubView (id, *mDocument);
if (!hint.empty())
view->useHint (hint);
view->setStatusBar (mShowStatusBar->isChecked());
mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view);
connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&)), this,
SLOT (addSubView (const CSMWorld::UniversalId&)));
connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&)), this,
SLOT (addSubView (const CSMWorld::UniversalId&, const std::string&)));
CSMSettings::UserSettings::instance().updateSettings("Display Format");
@ -429,11 +428,6 @@ void CSVDoc::View::addFiltersSubView()
addSubView (CSMWorld::UniversalId::Type_Filters);
}
void CSVDoc::View::addSceneSubView()
{
addSubView (CSMWorld::UniversalId::Type_Scene);
}
void CSVDoc::View::addTopicsSubView()
{
addSubView (CSMWorld::UniversalId::Type_Topics);

@ -120,7 +120,9 @@ namespace CSVDoc
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);
@ -166,8 +168,6 @@ namespace CSVDoc
void addFiltersSubView();
void addSceneSubView();
void addTopicsSubView();
void addJournalsSubView();

@ -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;
}

@ -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

@ -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;
}

@ -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

@ -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;
}

@ -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

@ -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;
}

@ -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

@ -0,0 +1,6 @@
#include "pagedworldspacewidget.hpp"
CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget *parent)
: WorldspaceWidget (parent)
{}

@ -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 <QResizeEvent>
#include <QTimer>
#include <OgreRoot.h>
#include <OgreRenderWindow.h>
#include <OgreEntity.h>
#include <OgreCamera.h>
#include <OgreSceneNode.h>
#include <OgreViewport.h>
#include "navigation.hpp"
namespace CSVRender
{
SceneWidget::SceneWidget(QWidget *parent)
: QWidget(parent)
, mWindow(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_NoSystemBackground);
setFocusPolicy (Qt::StrongFocus);
mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC);
// Throw in a random color just to make sure multiple scenes work
@ -44,6 +54,16 @@ namespace CSVRender
mCamera->lookAt(0,0,0);
mCamera->setNearClipDistance(0.1);
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()
@ -81,7 +101,21 @@ namespace CSVRender
SceneWidget::~SceneWidget()
{
Ogre::Root::getSingleton().destroyRenderTarget(mWindow);
if (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)
@ -93,7 +127,6 @@ namespace CSVRender
e->accept();
}
QPaintEngine* SceneWidget::paintEngine() const
{
// We don't want another paint engine to get in the way.
@ -130,4 +163,151 @@ namespace CSVRender
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 SceneManager;
class RenderWindow;
class ColourValue;
}
namespace CSVRender
{
class Navigation;
class SceneWidget : public QWidget
{
Q_OBJECT
public:
SceneWidget(QWidget *parent);
virtual ~SceneWidget(void);
public:
QPaintEngine* paintEngine() const;
SceneWidget(QWidget *parent);
virtual ~SceneWidget();
private:
void paintEvent(QPaintEvent* e);
void resizeEvent(QResizeEvent* e);
bool event(QEvent* e);
QPaintEngine* paintEngine() const;
void updateOgreWindow();
void setAmbient (const Ogre::ColourValue& colour);
///< \note The actual ambient colour may differ based on lighting settings.
Ogre::Camera* mCamera;
Ogre::SceneManager* mSceneMgr;
Ogre::RenderWindow* mWindow;
};
protected:
void setNavigation (Navigation *navigation);
///< \attention The ownership of \a navigation is not transferred to *this.
private:
void paintEvent(QPaintEvent* e);
void resizeEvent(QResizeEvent* 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();
int getFastFactor() const;
Ogre::Camera* mCamera;
Ogre::SceneManager* mSceneMgr;
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

@ -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();
}

@ -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

@ -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;
}

@ -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)
{
focusId (mModel->getUniversalId (index.row()));
focusId (mModel->getUniversalId (index.row()), "");
}

@ -9,7 +9,8 @@
#include "../filter/filterbox.hpp"
#include "../render/scenewidget.hpp"
#include "../render/pagedworldspacewidget.hpp"
#include "../render/unpagedworldspacewidget.hpp"
#include "tablebottombox.hpp"
#include "creator.hpp"
@ -32,38 +33,21 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::D
layout2->setContentsMargins (QMargins (0, 0, 0, 0));
SceneToolbar *toolbar = new SceneToolbar (48, this);
// test
SceneToolMode *tool = new SceneToolMode (toolbar);
tool->addButton (":door.png", "a");
tool->addButton (":GMST.png", "b");
tool->addButton (":Info.png", "c");
toolbar->addTool (tool);
toolbar->addTool (new SceneToolMode (toolbar));
toolbar->addTool (new SceneToolMode (toolbar));
toolbar->addTool (new SceneToolMode (toolbar));
layout2->addWidget (toolbar, 0);
// temporarily disable OGRE-integration (need to fix path problem first)
#if 0
CSVRender::SceneWidget* sceneWidget = new CSVRender::SceneWidget(this);
if (id.getId()[0]=='#')
mScene = new CSVRender::PagedWorldspaceWidget (this);
else
mScene = new CSVRender::UnpagedWorldspaceWidget (id.getId(), document, this);
layout2->addWidget (sceneWidget, 1);
SceneToolMode *tool = mScene->makeNavigationSelector (toolbar);
toolbar->addTool (tool);
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 (toolbar, 0);
layout2->addWidget (placeholder, 1);
layout2->addWidget (mScene, 1);
layout->insertLayout (0, layout2, 1);
CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this);
layout->insertWidget (0, filterBox);
@ -73,6 +57,10 @@ toolbar->addTool (new SceneToolMode (toolbar));
widget->setLayout (layout);
setWidget (widget);
mScene->selectDefaultNavigationMode();
connect (mScene, SIGNAL (closeRequest()), this, SLOT (closeRequest()));
}
void CSVWorld::SceneSubView::setEditLock (bool locked)
@ -91,3 +79,8 @@ void CSVWorld::SceneSubView::setStatusBar (bool show)
{
mBottom->setStatusBar (show);
}
void CSVWorld::SceneSubView::closeRequest()
{
deleteLater();
}

@ -10,6 +10,11 @@ namespace CSMDoc
class Document;
}
namespace CSVRender
{
class WorldspaceWidget;
}
namespace CSVWorld
{
class Table;
@ -21,6 +26,7 @@ namespace CSVWorld
Q_OBJECT
TableBottomBox *mBottom;
CSVRender::WorldspaceWidget *mScene;
public:
@ -31,6 +37,10 @@ namespace CSVWorld
virtual void updateEditorSetting (const QString& key, const QString& value);
virtual void setStatusBar (bool show);
private slots:
void closeRequest();
};
}

@ -2,7 +2,6 @@
#include "table.hpp"
#include <QHeaderView>
#include <QAction>
#include <QApplication>
#include <QMenu>
@ -10,6 +9,8 @@
#include <QString>
#include <QtCore/qnamespace.h>
#include "../../model/doc/document.hpp"
#include "../../model/world/data.hpp"
#include "../../model/world/commands.hpp"
#include "../../model/world/idtableproxymodel.hpp"
@ -35,8 +36,21 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
if (selectedRows.size()==1)
{
menu.addAction (mEditAction);
if (mCreateAction)
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)
@ -162,11 +176,12 @@ std::vector<std::string> CSVWorld::Table::listDeletableSelectedIds() const
return deletableIds;
}
CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack,
bool createAndDelete, bool sorting, const CSMDoc::Document& document)
: mUndoStack (undoStack), mCreateAction (0), mCloneAction(0), mEditLock (false), mRecordStatusDisplay (0), mDocument(document)
CSVWorld::Table::Table (const CSMWorld::UniversalId& id,
bool createAndDelete, bool sorting, CSMDoc::Document& 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->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());
CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate (display,
undoStack, this);
mDocument.getUndoStack(), this);
mDelegates.push_back (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()));
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)),
this, SLOT (tableSizeUpdate()));
@ -268,13 +287,13 @@ void CSVWorld::Table::revertRecord()
if (revertableIds.size()>0)
{
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)
mUndoStack.push (new CSMWorld::RevertCommand (*mModel, *iter));
mDocument.getUndoStack().push (new CSMWorld::RevertCommand (*mModel, *iter));
if (revertableIds.size()>1)
mUndoStack.endMacro();
mDocument.getUndoStack().endMacro();
}
}
}
@ -288,13 +307,13 @@ void CSVWorld::Table::deleteRecord()
if (deletableIds.size()>0)
{
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)
mUndoStack.push (new CSMWorld::DeleteCommand (*mModel, *iter));
mDocument.getUndoStack().push (new CSMWorld::DeleteCommand (*mModel, *iter));
if (deletableIds.size()>1)
mUndoStack.endMacro();
mDocument.getUndoStack().endMacro();
}
}
}
@ -306,7 +325,7 @@ void CSVWorld::Table::editRecord()
QModelIndexList selectedRows = selectionModel()->selectedRows();
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)
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)
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)
{
int columns = mModel->columnCount();
@ -517,7 +553,7 @@ void CSVWorld::Table::dropEvent(QDropEvent *event)
std::auto_ptr<CSMWorld::ModifyCommand> command (new CSMWorld::ModifyCommand
(*mProxyModel, index, QVariant (QString::fromUtf8 (record.getId().c_str()))));
mUndoStack.push (command.release());
mDocument.getUndoStack().push (command.release());
}
} //TODO handle drops from different document
}

@ -10,13 +10,14 @@
#include "../../model/filter/node.hpp"
#include "../../model/world/columnbase.hpp"
namespace CSMDoc {
class Document;
}
class QUndoStack;
class QAction;
namespace CSMDoc
{
class Document;
}
namespace CSMWorld
{
class Data;
@ -35,7 +36,6 @@ namespace CSVWorld
Q_OBJECT
std::vector<CommandDelegate *> mDelegates;
QUndoStack& mUndoStack;
QAction *mEditAction;
QAction *mCreateAction;
QAction *mCloneAction;
@ -43,14 +43,12 @@ namespace CSVWorld
QAction *mDeleteAction;
QAction *mMoveUpAction;
QAction *mMoveDownAction;
QAction *mViewAction;
CSMWorld::IdTableProxyModel *mProxyModel;
CSMWorld::IdTable *mModel;
bool mEditLock;
int mRecordStatusDisplay;
/// \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;
CSMDoc::Document& mDocument;
private:
@ -70,9 +68,8 @@ namespace CSVWorld
public:
Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, bool createAndDelete,
bool sorting, const CSMDoc::Document& document);
Table (const CSMWorld::UniversalId& id, bool createAndDelete,
bool sorting, CSMDoc::Document& document);
///< \param createAndDelete Allow creation and deletion of records.
/// \param sorting Allow changing order of rows in the view via column headers.
@ -86,7 +83,7 @@ namespace CSVWorld
signals:
void editRequest (int row);
void editRequest (const CSMWorld::UniversalId& id, const std::string& hint);
void selectionSizeChanged (int size);
@ -112,6 +109,8 @@ namespace CSVWorld
void moveDownRecord();
void viewRecord();
public slots:
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);
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);
@ -36,7 +36,8 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D
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)),
mBottom, SLOT (selectionSizeChanged (int)));
@ -81,9 +82,9 @@ void CSVWorld::TableSubView::setEditLock (bool 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)

@ -53,7 +53,7 @@ namespace CSVWorld
private slots:
void editRequest (int row);
void editRequest (const CSMWorld::UniversalId& id, const std::string& hint);
void cloneRequest (const CSMWorld::UniversalId& toClone);
void createFilterRequest(std::vector< CSMWorld::UniversalId >& types,
Qt::DropAction action);

@ -15,7 +15,7 @@ add_openmw_dir (mwrender
renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation
actors objects renderinginterface localmap occlusionquery water shadows
characterpreview globalmap videoplayer ripplesimulation refraction
terrainstorage renderconst effectmanager
terrainstorage renderconst effectmanager weaponanimation
)
add_openmw_dir (mwinput
@ -159,3 +159,10 @@ if (BUILD_WITH_CODE_COVERAGE)
add_definitions (--coverage)
target_link_libraries(openmw gcov)
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 <stdexcept>
#include <iomanip>
#include <OgreRoot.h>
#include <OgreRenderWindow.h>
@ -403,7 +404,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
// Create the world
mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mContentFiles,
mResDir, mCfgMgr.getCachePath(), mEncoder, mFallbackMap,
mActivationDistanceOverride));
mActivationDistanceOverride, mCellName));
MWBase::Environment::get().getWorld()->setupPlayer();
input->setPlayer(&mEnvironment.getWorld()->getPlayer());
@ -439,31 +440,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mechanics->buildPlayer();
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);
// scripts
@ -501,15 +477,15 @@ void OMW::Engine::go()
// Play some good 'ol tunes
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
if (!mStartupScript.empty())
MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript);
// start in main menu
if (!mSkipMenu)
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
else
MWBase::Environment::get().getStateManager()->newGame (true);
if (!mStartupScript.empty())
MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript);
// Start the main rendering loop
while (!mEnvironment.get().getStateManager()->hasQuitRequest())
Ogre::Root::getSingleton().renderOneFrame();
@ -621,4 +597,4 @@ void OMW::Engine::setActivationDistanceOverride (int distance)
void OMW::Engine::setWarningsMode (int mode)
{
mWarningsMode = mode;
}
}

@ -3,7 +3,7 @@
#include <string>
#include <libs/platform/stdint.h>
#include <stdint.h>
namespace ESM
{

@ -20,6 +20,9 @@ namespace MWBase
InputManager() {}
/// Clear all savegame-specific data
virtual void clear() = 0;
virtual ~InputManager() {}
virtual void update(float dt, bool loading) = 0;

@ -5,7 +5,7 @@
#include <deque>
#include <map>
#include <libs/platform/stdint.h>
#include <stdint.h>
#include "../mwdialogue/journalentry.hpp"
#include "../mwdialogue/topic.hpp"

@ -101,7 +101,8 @@ namespace MWBase
virtual ~World() {}
virtual void startNewGame() = 0;
virtual void startNewGame (bool bypass) = 0;
///< \param bypass Bypass regular game start.
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, 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;
@ -282,7 +283,7 @@ namespace MWBase
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).
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 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;
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;

@ -7,6 +7,7 @@
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/magiceffects.hpp"
#include "../mwmechanics/movement.hpp"
#include "../mwmechanics/disease.hpp"
#include "../mwmechanics/spellcasting.hpp"
#include "../mwbase/environment.hpp"
@ -243,15 +244,7 @@ namespace MWClass
Ogre::Vector3 hitPosition = result.second;
MWMechanics::CreatureStats &otherstats = victim.getClass().getCreatureStats(victim);
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();
float hitchance = MWMechanics::getHitChance(ptr, victim, ref->mBase->mData.mCombat);
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
{
@ -334,6 +327,8 @@ namespace MWClass
if (damage > 0)
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
MWMechanics::diseaseContact(victim, ptr);
victim.getClass().onHit(victim, damage, true, weapon, ptr, true);
}
@ -530,7 +525,7 @@ namespace MWClass
float moveSpeed;
if(normalizedEncumbrance >= 1.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()))
{
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);
}
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 =
ptr.get<ESM::Creature>();
@ -691,6 +694,22 @@ namespace MWClass
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)
{
if(name == "left")

@ -124,7 +124,10 @@ namespace MWClass
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;

@ -57,7 +57,7 @@ namespace MWClass
MWWorld::ManualRef ref(store, id);
ref.getPtr().getCellRef().mPos = ptr.getCellRef().mPos;
// 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());

@ -498,15 +498,7 @@ namespace MWClass
if(!weapon.isEmpty())
weapskill = get(weapon).getEquipmentSkill(weapon);
MWMechanics::NpcStats &stats = getNpcStats(ptr);
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();
float hitchance = MWMechanics::getHitChance(ptr, victim, ptr.getClass().getSkill(ptr, weapskill));
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
{
@ -516,6 +508,7 @@ namespace MWClass
bool healthdmg;
float damage = 0.0f;
MWMechanics::NpcStats &stats = getNpcStats(ptr);
if(!weapon.isEmpty())
{
const bool weaphashealth = get(weapon).hasItemHealth(weapon);
@ -615,6 +608,8 @@ namespace MWClass
if (healthdmg && damage > 0)
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
MWMechanics::diseaseContact(victim, ptr);
othercls.onHit(victim, damage, healthdmg, weapon, ptr, true);
}
@ -648,9 +643,6 @@ namespace MWClass
ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1);
}
if (!attacker.isEmpty())
MWMechanics::diseaseContact(ptr, attacker);
if (damage > 0.0f && !object.isEmpty())
MWMechanics::resistNormalWeapon(ptr, attacker, object, damage);
@ -681,12 +673,7 @@ namespace MWClass
else
getCreatureStats(ptr).setHitRecovery(true); // Is this supposed to always occur?
if(object.isEmpty())
{
if(ishealth)
damage /= std::min(1.0f + getArmorRating(ptr)/std::max(1.0f, damage), 4.0f);
}
else if(ishealth)
if(ishealth)
{
// Hit percentages:
// cuirass = 30%

@ -6,7 +6,7 @@
#include "MyGUI_TextureUtility.h"
#include "MyGUI_FactoryManager.h"
#include <platform/stdint.h>
#include <stdint.h>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>

@ -5,7 +5,7 @@
#include "MyGUI_Widget.h"
#include <functional>
#include <platform/stdint.h>
#include <stdint.h>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>

@ -1,5 +1,7 @@
#include "enchantingdialog.hpp"
#include <iomanip>
#include <boost/lexical_cast.hpp>
#include "../mwbase/environment.hpp"

@ -604,15 +604,22 @@ namespace MWGui
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()
{
mSpellIcons->updateWidgets(mEffectBox, true);
if (!mEnemy.isEmpty() && mEnemyHealth->getVisible())
{
MWMechanics::CreatureStats& stats = MWWorld::Class::get(mEnemy).getCreatureStats(mEnemy);
mEnemyHealth->setProgressRange(100);
mEnemyHealth->setProgressPosition(stats.getHealth().getCurrent() / stats.getHealth().getModified() * 100);
updateEnemyHealthBar();
}
if (mIsDrowning)
@ -629,9 +636,7 @@ namespace MWGui
if (!mEnemyHealth->getVisible())
mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() - MyGUI::IntPoint(0,20));
mEnemyHealth->setVisible(true);
MWMechanics::CreatureStats& stats = MWWorld::Class::get(mEnemy).getCreatureStats(mEnemy);
mEnemyHealth->setProgressRange(100);
mEnemyHealth->setProgressPosition(stats.getHealth().getCurrent() / stats.getHealth().getModified() * 100);
updateEnemyHealthBar();
}
}

@ -112,6 +112,8 @@ namespace MWGui
void onMagicClicked(MyGUI::Widget* _sender);
void onMapClicked(MyGUI::Widget* _sender);
void updateEnemyHealthBar();
void updatePositions();
};
}

@ -514,6 +514,9 @@ namespace MWGui
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
std::string type = object.getTypeName();
if ( (type != typeid(ESM::Apparatus).name())

@ -206,9 +206,9 @@ struct JournalViewModelImpl : JournalViewModel
const MWDialogue::Quest& quest = i->second;
// Unfortunately Morrowind.esm has no quest names, since the quest book was added with tribunal.
if (quest.getName().empty())
visitor (reinterpret_cast <QuestId> (&i->second), toUtf8Span (i->first));
else
// Note that even with Tribunal, some quests still don't have quest names. I'm assuming those are not supposed
// to appear in the quest book.
if (!quest.getName().empty())
visitor (reinterpret_cast <QuestId> (&i->second), toUtf8Span (quest.getName()));
}
}

@ -4,7 +4,7 @@
#include <string>
#include <memory>
#include <functional>
#include <platform/stdint.h>
#include <stdint.h>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>

@ -1,6 +1,13 @@
#include "loadingscreen.hpp"
#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>
@ -66,6 +73,10 @@ namespace MWGui
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.
// 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 :/
@ -74,16 +85,36 @@ namespace MWGui
mWindow->setVSyncEnabled(false);
#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);
if (mFirstLoad)
{
changeWallpaper();
}
else
{
mBackgroundImage->setImageTexture("");
}
MWBase::Environment::get().getWindowManager()->pushGuiMode(mFirstLoad ? GM_LoadingWallpaper : GM_Loading);
}
@ -197,8 +228,6 @@ namespace MWGui
MWBase::Environment::get().getInputManager()->update(0, true);
mWindow->getViewport(0)->setClearEveryFrame(false);
// First, swap buffers from last draw, then, queue an update of the
// window contents, but don't swap buffers (which would have
// caused a sync / flush and would be expensive).
@ -208,9 +237,6 @@ namespace MWGui
mWindow->update(false);
mWindow->getViewport(0)->setClearEveryFrame(true);
mRectangle->setVisible(false);
// resume 3d rendering

@ -2,6 +2,7 @@
#define MWGUI_LOADINGSCREEN_H
#include <OgreSceneManager.h>
#include <OgreTimer.h>
#include "windowbase.hpp"

@ -1,5 +1,7 @@
#include "mainmenu.hpp"
#include <components/version/version.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/soundmanager.hpp"
@ -20,6 +22,22 @@ namespace MWGui
, mButtonBox(0), mWidth (w), mHeight (h)
, 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();
}

@ -24,6 +24,7 @@ namespace MWGui
private:
MyGUI::Widget* mButtonBox;
MyGUI::TextBox* mVersionText;
std::map<std::string, MWGui::ImageButton*> mButtons;

@ -3,6 +3,7 @@
#include <boost/lexical_cast.hpp>
#include <OgreSceneNode.h>
#include <OgreVector2.h>
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"

@ -1,7 +1,7 @@
#ifndef MWGUI_MAPWINDOW_H
#define MWGUI_MAPWINDOW_H
#include <libs/platform/stdint.h>
#include <stdint.h>
#include "windowpinnablebase.hpp"

@ -41,9 +41,13 @@ namespace MWGui
getWidget(mPreviewImage, "PreviewImage");
getWidget(mHeadRotate, "HeadRotate");
mHeadRotate->setScrollRange(50);
mHeadRotate->setScrollPosition(25);
mHeadRotate->setScrollViewPage(10);
// Mouse wheel step is hardcoded to 50 in MyGUI 3.2 ("FIXME").
// 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);
// Set up next/previous buttons
@ -171,9 +175,9 @@ namespace MWGui
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;
mPreview->update (diff);
mPreviewDirty = true;

@ -1,5 +1,7 @@
#include "repair.hpp"
#include <iomanip>
#include <boost/lexical_cast.hpp>
#include "../mwbase/world.hpp"

@ -1,5 +1,7 @@
#include "tooltips.hpp"
#include <iomanip>
#include <boost/lexical_cast.hpp>
#include "../mwbase/world.hpp"

@ -3,6 +3,8 @@
#include <cassert>
#include <iterator>
#include <OgreTextureManager.h>
#include "MyGUI_UString.h"
#include "MyGUI_IPointer.h"
#include "MyGUI_ResourceImageSetPointer.h"

@ -143,6 +143,13 @@ namespace MWInput
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()
{
mInputBinder->save (mUserFile);
@ -455,7 +462,7 @@ namespace MWInput
mInputBinder->adjustMouseRegion(width, height);
}
bool InputManager::keyPressed( const SDL_KeyboardEvent &arg )
void InputManager::keyPressed( const SDL_KeyboardEvent &arg )
{
// Cut, copy & paste
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
@ -501,7 +508,6 @@ namespace MWInput
if (kc != OIS::KC_UNASSIGNED)
MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0);
return true;
}
void InputManager::textInput(const SDL_TextInputEvent &arg)
@ -512,23 +518,21 @@ namespace MWInput
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);
OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym);
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);
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));
if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0)
@ -539,20 +543,16 @@ namespace MWInput
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);
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);
@ -585,13 +585,13 @@ namespace MWInput
float rot[3];
rot[0] = -y;
rot[1] = 0.0f;
rot[2] = x;
rot[2] = -x;
// Only actually turn player when we're not in vanity mode
if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot))
{
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
@ -600,8 +600,6 @@ namespace MWInput
MWBase::Environment::get().getWorld()->setCameraDistance(arg.zrel, true, true);
}
}
return true;
}
void InputManager::windowFocusChange(bool have_focus)

@ -65,6 +65,9 @@ namespace MWInput
virtual ~InputManager();
/// Clear all savegame-specific data
virtual void clear();
virtual void update(float dt, bool loading);
void setPlayer (MWWorld::Player* player) { mPlayer = player; }
@ -86,13 +89,13 @@ namespace MWInput
virtual void resetToDefaultBindings();
public:
virtual bool keyPressed(const SDL_KeyboardEvent &arg );
virtual bool keyReleased( const SDL_KeyboardEvent &arg );
virtual void keyPressed(const SDL_KeyboardEvent &arg );
virtual void keyReleased( const SDL_KeyboardEvent &arg );
virtual void textInput (const SDL_TextInputEvent &arg);
virtual bool mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id );
virtual bool mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id );
virtual bool mouseMoved( const SFO::MouseMotionEvent &arg );
virtual void mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id );
virtual void mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id );
virtual void mouseMoved( const SFO::MouseMotionEvent &arg );
virtual void windowVisibilityChange( bool visible );
virtual void windowFocusChange( bool have_focus );

@ -210,7 +210,7 @@ namespace MWMechanics
&& LOS
)
{
creatureStats.getAiSequence().stack(AiCombat(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()));
creatureStats.getAiSequence().stack(AiCombat(MWBase::Environment::get().getWorld()->getPlayerPtr()));
creatureStats.setHostile(true);
}
}
@ -541,7 +541,7 @@ namespace MWMechanics
// TODO: Add AI to follow player and fight for him
// TODO: VFX_SummonStart, VFX_SummonEnd
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

@ -15,7 +15,7 @@
#include "../mwbase/dialoguemanager.hpp"
#include "npcstats.hpp"
#include "creaturestats.hpp"
#include "steering.hpp"
#include "movement.hpp"
#include "character.hpp" // fixme: for getActiveWeapon
@ -140,11 +140,12 @@ namespace MWMechanics
{
MWMechanics::DrawState_ state = actor.getClass().getCreatureStats(actor).getDrawState();
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
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)
{
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)
mFollowTarget = false;
buildNewPath(actor);
buildNewPath(actor); //may fail to build a path, check before use
//delete visited path node
mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]);
//try shortcut
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();
else
mTargetAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
mRotate = true;
//if no new path leave mTargetAngle unchanged
if(!mPathFinder.getPath().empty())
{
//try shortcut
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();
else
mTargetAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
mRotate = true;
}
mMovement.mPosition[1] = 1;
mReadyToAttack = false;
@ -302,9 +307,13 @@ namespace MWMechanics
dest.mZ = mTarget.getRefData().getPosition().pos[2];
Ogre::Vector3 newPathTarget = Ogre::Vector3(dest.mX, dest.mY, dest.mZ);
ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back();
Ogre::Vector3 currPathTarget(lastPt.mX, lastPt.mY, lastPt.mZ);
float dist = Ogre::Math::Abs((newPathTarget - currPathTarget).length());
float dist = -1; //hack to indicate first time, to construct a new path
if(!mPathFinder.getPath().empty())
{
ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back();
Ogre::Vector3 currPathTarget(lastPt.mX, lastPt.mY, lastPt.mZ);
dist = Ogre::Math::Abs((newPathTarget - currPathTarget).length());
}
float targetPosThreshold;
bool isOutside = actor.getCell()->getCell()->isExterior();
@ -313,7 +322,7 @@ namespace MWMechanics
else
targetPosThreshold = 100;
if(dist > targetPosThreshold)
if((dist < 0) || (dist > targetPosThreshold))
{
//construct new path only if target has moved away more than on <targetPosThreshold>
ESM::Position pos = actor.getRefData().getPosition();
@ -334,8 +343,11 @@ namespace MWMechanics
//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.
//if(pathFinder2.getPathSize() < mPathFinder.getPathSize())
newPathFinder.syncStart(mPathFinder.getPath());
mPathFinder = newPathFinder;
if(!mPathFinder.getPath().empty())
{
newPathFinder.syncStart(mPathFinder.getPath());
mPathFinder = newPathFinder;
}
}
}
}

@ -27,6 +27,11 @@ namespace
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):
mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat)
, mCellX(std::numeric_limits<int>::max())
@ -36,6 +41,11 @@ namespace MWMechanics
, mX(0)
, mY(0)
, mZ(0)
, mPrevX(0)
, mPrevY(0)
, mWalkState(State_Norm)
, mStuckCount(0)
, mEvadeCount(0)
, mSaidGreeting(false)
{
for(unsigned short counter = 0; counter < mIdle.size(); counter++)
@ -298,9 +308,91 @@ namespace MWMechanics
}
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;
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;
}
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
// 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 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 mChooseAction;
bool mIdleNow;

@ -313,6 +313,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
mAnimation->disable(mCurrentMovement);
mCurrentMovement = movement;
mMovementAnimVelocity = 0.0f;
if(!mCurrentMovement.empty())
{
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);
if(mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(mCurrentMovement)) > 1.0f)
{
mMovementAnimVelocity = vel;
speedmult = mMovementSpeed / vel;
}
else if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight)
speedmult = 1.f; // TODO: should get a speed mult depending on the current turning speed
else if (mMovementSpeed > 0.0f)
@ -330,10 +334,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
speedmult = mMovementSpeed / (isrunning ? 222.857f : 154.064f);
mAnimation->play(mCurrentMovement, Priority_Movement, movegroup, false,
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
: (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)
movestate = CharState_TurnRight;

@ -4,9 +4,12 @@
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/soundmanager.hpp"
#include "../mwmechanics/npcstats.hpp"
#include "../mwmechanics/movement.hpp"
#include "../mwmechanics/spellcasting.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/inventorystore.hpp"
@ -17,14 +20,30 @@
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(
n.dotProduct( v1.crossProduct(v2) ),
normal.dotProduct( v1.crossProduct(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
@ -135,4 +154,94 @@ namespace MWMechanics
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
#include "../mwworld/ptr.hpp"
#include <OgreVector3.h>
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);
/// @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

@ -6,6 +6,8 @@
#include <vector>
#include <algorithm>
#include <iomanip>
#include <boost/format.hpp>
#include <components/esm/loadskil.hpp>
@ -509,4 +511,4 @@ void MWMechanics::NpcStats::readState (const ESM::NpcStats& state)
mTimeToStartDrowning = state.mTimeToStartDrowning;
mLastDrowningHit = state.mLastDrowningHit;
mLevelHealthBonus = state.mLevelHealthBonus;
}
}

@ -393,6 +393,8 @@ namespace MWMechanics
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>::iterator iter = ++mPath.begin();

@ -587,7 +587,7 @@ namespace MWMechanics
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;
}
@ -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;
}

@ -10,6 +10,8 @@
#include <OgreSceneManager.h>
#include <OgreControllerManager.h>
#include <OgreStaticGeometry.h>
#include <OgreSceneNode.h>
#include <OgreTechnique.h>
#include <components/esm/loadligh.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]);
grpctrls[grp].push_back(ctrls[i]);
}

@ -70,7 +70,7 @@ namespace MWRender
if (!mVanity.enabled && !mPreviewMode) {
mCamera->getParentNode()->setOrientation(xr);
} 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);
}
}

@ -1,10 +1,13 @@
#include "characterpreview.hpp"
#include <OgreSceneManager.h>
#include <OgreRoot.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreCamera.h>
#include <OgreSceneNode.h>
#include <OgreTextureManager.h>
#include <OgreViewport.h>
#include <OgreRenderTexture.h>
#include <libs/openengine/ogre/selectionbuffer.hpp>

@ -3,6 +3,7 @@
#include <OgreRenderTarget.h>
#include <OgreMaterialManager.h>
#include <OgreVector3.h>
#include <components/esm/loadnpc.hpp>

@ -55,6 +55,8 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr)
updateParts();
}
mWeaponAnimationTime = Ogre::SharedPtr<WeaponAnimationTime>(new WeaponAnimationTime(this));
}
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,
!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)
{
Ogre::SkeletonInstance *skel = scene->mSkelBase->getSkeleton();
@ -133,15 +149,42 @@ void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slo
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());
for(;ctrl != scene->mControllers.end();ctrl++)
{
if(ctrl->getSource().isNull())
ctrl->setSource(Ogre::SharedPtr<NullAnimationTime>(new NullAnimationTime()));
{
if (slot == MWWorld::InventoryStore::Slot_CarriedRight)
ctrl->setSource(mWeaponAnimationTime);
else
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
#include "animation.hpp"
#include "weaponanimation.hpp"
#include "../mwworld/inventorystore.hpp"
namespace MWWorld
@ -21,7 +22,7 @@ namespace MWRender
// For creatures with weapons and shields
// Animation is already virtual anyway, so might as well make a separate class.
// Most creatures don't need weapons/shields, so this will save some memory.
class CreatureWeaponAnimation : public Animation, public MWWorld::InventoryStoreListener
class CreatureWeaponAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener
{
public:
CreatureWeaponAnimation(const MWWorld::Ptr& ptr);
@ -36,11 +37,29 @@ namespace MWRender
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:
NifOgre::ObjectScenePtr mWeapon;
NifOgre::ObjectScenePtr mShield;
bool mShowWeapons;
bool mShowCarriedLeft;
Ogre::SharedPtr<WeaponAnimationTime> mWeaponAnimationTime;
};
}

@ -7,6 +7,8 @@
#include <OgreMaterial.h>
#include <OgreMaterialManager.h>
#include <OgreManualObject.h>
#include <OgreTechnique.h>
#include <OgreSceneNode.h>
#include <openengine/bullet/physic.hpp>

@ -2,6 +2,8 @@
#include <OgreSceneManager.h>
#include <OgreParticleSystem.h>
#include <OgreSceneNode.h>
#include <OgreTechnique.h>
#include "animation.hpp"
#include "renderconst.hpp"

@ -75,10 +75,9 @@ namespace MWRender
if (land)
{
if (!land->isDataLoaded(ESM::Land::DATA_VHGT))
{
land->loadData(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(mask);
}
for (int cellY=0; cellY<cellSize; ++cellY)

@ -6,6 +6,8 @@
#include <OgreSceneNode.h>
#include <OgreCamera.h>
#include <OgreTextureManager.h>
#include <OgreRenderTexture.h>
#include <OgreViewport.h>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"

@ -4,6 +4,11 @@
#include <OgreEntity.h>
#include <OgreParticleSystem.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>
@ -71,27 +76,6 @@ float HeadAnimationTime::getValue() const
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()
{
NpcAnimation::PartBoneMap result;
@ -142,8 +126,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int v
mShowCarriedLeft(true),
mFirstPersonOffset(0.f, 0.f, 0.f),
mAlpha(1.f),
mNpcType(Type_Normal),
mPitchFactor(0)
mNpcType(Type_Normal)
{
mNpc = mPtr.get<ESM::NPC>()->mBase;
@ -527,20 +510,16 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
{
float pitch = mPtr.getRefData().getPosition().rot[0];
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;
// updateSkeletonInstance, below, touches the hands.
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
float pitch = mPtr.getRefData().getPosition().rot[0] * mPitchFactor;
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);
pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst);
}
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::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);
std::string mesh = MWWorld::Class::get(*weapon).getModel(*weapon);
addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1,
mesh, !weapon->getClass().getEnchantment(*weapon).empty(), &glowColor);
// Crossbows start out with a bolt attached
if (weapon->getTypeName() == typeid(ESM::Weapon).name() &&
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
{
@ -738,50 +718,24 @@ void NpcAnimation::showCarriedLeft(bool show)
removeIndividualPart(ESM::PRT_Shield);
}
void NpcAnimation::attachArrow()
void NpcAnimation::configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot)
{
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(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);
Ogre::Vector3 glowColor = getEnchantmentColor(ptr);
setRenderProperties(object, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha, 0,
!ptr.getClass().getEnchantment(ptr).empty(), &glowColor);
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(object->mEntities.begin(), object->mEntities.end(), SetObjectGroup(slot));
std::for_each(object->mParticles.begin(), object->mParticles.end(), SetObjectGroup(slot));
}
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::attachArrow()
{
WeaponAnimation::attachArrow(mPtr);
}
void NpcAnimation::releaseArrow()
{
// Thrown weapons get detached now
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();
}
WeaponAnimation::releaseArrow(mPtr);
}
void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew, bool playSound)

@ -5,6 +5,8 @@
#include "../mwworld/inventorystore.hpp"
#include "weaponanimation.hpp"
namespace ESM
{
struct NPC;
@ -25,24 +27,7 @@ public:
{ }
};
class WeaponAnimationTime : public Ogre::ControllerValue<Ogre::Real>
{
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
class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener
{
public:
virtual void equipmentChanged() { updateParts(); }
@ -91,7 +76,6 @@ private:
Ogre::SharedPtr<WeaponAnimationTime> mWeaponAnimationTime;
float mAlpha;
float mPitchFactor;
void updateNpcBase();
@ -138,7 +122,10 @@ public:
virtual void attachArrow();
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);

@ -109,6 +109,7 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh)
{
uniqueID = uniqueID+1;
sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID));
sg->setOrigin(ptr.getRefData().getBaseNode()->getPosition());
mStaticGeometrySmall[ptr.getCell()] = sg;
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;
sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID));
sg->setOrigin(ptr.getRefData().getBaseNode()->getPosition());
mStaticGeometry[ptr.getCell()] = sg;
}
else

@ -9,6 +9,8 @@
#include <OgreMeshManager.h>
#include <OgreMaterialManager.h>
#include <OgreCamera.h>
#include <OgreSceneNode.h>
#include <OgreMesh.h>
#include "renderconst.hpp"

@ -7,6 +7,8 @@
#include <OgreRenderTarget.h>
#include <OgreViewport.h>
#include <OgreRoot.h>
#include <OgreRenderTexture.h>
#include <OgreSceneNode.h>
#include <extern/shiny/Main/Factory.hpp>

@ -5,12 +5,14 @@
#include <OgreRoot.h>
#include <OgreRenderWindow.h>
#include <OgreSceneManager.h>
#include <OgreSceneNode.h>
#include <OgreViewport.h>
#include <OgreCamera.h>
#include <OgreTextureManager.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreControllerManager.h>
#include <OgreMeshManager.h>
#include <OgreRenderTexture.h>
#include <SDL_video.h>
@ -278,13 +280,12 @@ void RenderingManager::rotateObject(const MWWorld::Ptr &ptr)
if(ptr.getRefData().getHandle() == mCamera->getHandle() &&
!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())
newo = Ogre::Quaternion(Ogre::Radian(-rot.x), Ogre::Vector3::UNIT_X) *
Ogre::Quaternion(Ogre::Radian(-rot.y), Ogre::Vector3::UNIT_Y) * newo;
newo = Ogre::Quaternion(Ogre::Radian(rot.x), Ogre::Vector3::NEGATIVE_UNIT_X) *
Ogre::Quaternion(Ogre::Radian(rot.y), Ogre::Vector3::NEGATIVE_UNIT_Y) * newo;
ptr.getRefData().getBaseNode()->setOrientation(newo);
}
@ -649,6 +650,18 @@ void RenderingManager::setGlare(bool glare)
mSkyManager->setGlare(glare);
}
void RenderingManager::updateTerrain()
{
if (mTerrain)
{
// Avoid updating with dims.getCenter for each cell. Player position should be good enough
mTerrain->update(mRendering.getCamera()->getRealPosition());
mTerrain->syncLoad();
// need to update again so the chunks that were just loaded can be made visible
mTerrain->update(mRendering.getCamera()->getRealPosition());
}
}
void RenderingManager::requestMap(MWWorld::CellStore* cell)
{
if (cell->getCell()->isExterior())
@ -659,9 +672,6 @@ void RenderingManager::requestMap(MWWorld::CellStore* cell)
Ogre::Vector2 center (cell->getCell()->getGridX() + 0.5, cell->getCell()->getGridY() + 0.5);
dims.merge(mTerrain->getWorldBoundingBox(center));
if (dims.isFinite())
mTerrain->update(dims.getCenter());
mLocalMap->requestMap(cell, dims.getMinimum().z, dims.getMaximum().z);
}
else
@ -981,13 +991,11 @@ void RenderingManager::screenshot(Image &image, int w, int h)
Ogre::PixelFormat pf = rt->suggestPixelFormat();
std::vector<Ogre::uchar> data;
data.resize(w * h * Ogre::PixelUtil::getNumElemBytes(pf));
Ogre::PixelBox pb(w, h, 1, pf, &data[0]);
rt->copyContentsToMemory(pb);
image.loadDynamicImage(&data[0], w, h, pf);
image.loadDynamicImage(
OGRE_ALLOC_T(Ogre::uchar, w * h * Ogre::PixelUtil::getNumElemBytes(pf), Ogre::MEMCATEGORY_GENERAL),
w, h, 1, pf, true // autoDelete=true, frees memory we allocate
);
rt->copyContentsToMemory(image.getPixelBox()); // getPixelBox returns a box sharing the same memory as the image
Ogre::TextureManager::getSingleton().remove(tempName);
mRendering.getCamera()->setAspectRatio(oldAspect);
@ -1045,20 +1053,16 @@ void RenderingManager::enableTerrain(bool enable)
{
if (!mTerrain)
{
Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
Loading::ScopedLoad load(listener);
mTerrain = new Terrain::World(listener, mRendering.getScene(), new MWRender::TerrainStorage(), RV_Terrain,
mTerrain = new Terrain::World(mRendering.getScene(), new MWRender::TerrainStorage(), RV_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"),
Settings::Manager::getBool("split", "Shadows"));
mTerrain->update(mRendering.getCamera()->getRealPosition());
mTerrain->setLoadingListener(NULL);
}
mTerrain->setVisible(true);
}
else
if (mTerrain)
else if (mTerrain)
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)
{
mEffectManager->addEffect(model, "", worldPosition, scale);
mEffectManager->addEffect(model, texture, worldPosition, scale);
}
} // namespace

@ -180,6 +180,10 @@ public:
void removeWaterRippleEmitter (const MWWorld::Ptr& ptr);
void updateWaterRippleEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr);
void updateTerrain ();
///< update the terrain according to the player position. Usually done automatically, but should be done manually
/// before calling requestMap
void requestMap (MWWorld::CellStore* cell);
///< request the local map for a cell

@ -4,6 +4,10 @@
#include <OgreStringConverter.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreRoot.h>
#include <OgreRectangle2D.h>
#include <OgreSceneNode.h>
#include <OgreRenderTexture.h>
#include <OgreViewport.h>
#include <extern/shiny/Main/Factory.hpp>

@ -9,6 +9,8 @@
#include <OgreShadowCameraSetupPSSM.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreCamera.h>
#include <OgreRenderTexture.h>
#include <OgreViewport.h>
#include <extern/shiny/Main/Factory.hpp>

@ -11,6 +11,7 @@
#include <OgreBillboardSet.h>
#include <OgreEntity.h>
#include <OgreSubEntity.h>
#include <OgreTechnique.h>
#include <OgreMeshManager.h>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save