mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 22:23:51 +00:00
Merge remote-tracking branch 'scrawl/master'
This commit is contained in:
commit
60a8a9e684
74 changed files with 815 additions and 689 deletions
|
@ -219,7 +219,7 @@ bool Launcher::MainDialog::showFirstRunDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the file if it doesn't already exist, else the importer will fail
|
// Create the file if it doesn't already exist, else the importer will fail
|
||||||
QString path = QString::fromStdString(mCfgMgr.getUserPath().string()) + QString("openmw.cfg");
|
QString path = QString::fromStdString(mCfgMgr.getUserConfigPath().string()) + QString("openmw.cfg");
|
||||||
QFile file(path);
|
QFile file(path);
|
||||||
|
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
|
@ -334,7 +334,7 @@ bool Launcher::MainDialog::setupLauncherSettings()
|
||||||
{
|
{
|
||||||
mLauncherSettings.setMultiValueEnabled(true);
|
mLauncherSettings.setMultiValueEnabled(true);
|
||||||
|
|
||||||
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
|
QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string());
|
||||||
|
|
||||||
QStringList paths;
|
QStringList paths;
|
||||||
paths.append(QString("launcher.cfg"));
|
paths.append(QString("launcher.cfg"));
|
||||||
|
@ -440,7 +440,7 @@ bool Launcher::expansions(Launcher::UnshieldThread& cd)
|
||||||
|
|
||||||
bool Launcher::MainDialog::setupGameSettings()
|
bool Launcher::MainDialog::setupGameSettings()
|
||||||
{
|
{
|
||||||
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
|
QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string());
|
||||||
QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string());
|
QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string());
|
||||||
|
|
||||||
// Load the user config file first, separately
|
// Load the user config file first, separately
|
||||||
|
@ -591,7 +591,7 @@ bool Launcher::MainDialog::setupGraphicsSettings()
|
||||||
{
|
{
|
||||||
mGraphicsSettings.setMultiValueEnabled(false);
|
mGraphicsSettings.setMultiValueEnabled(false);
|
||||||
|
|
||||||
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
|
QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string());
|
||||||
QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string());
|
QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string());
|
||||||
|
|
||||||
QFile localDefault(QString("settings-default.cfg"));
|
QFile localDefault(QString("settings-default.cfg"));
|
||||||
|
@ -678,7 +678,7 @@ bool Launcher::MainDialog::writeSettings()
|
||||||
mGraphicsPage->saveSettings();
|
mGraphicsPage->saveSettings();
|
||||||
mDataFilesPage->saveSettings();
|
mDataFilesPage->saveSettings();
|
||||||
|
|
||||||
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
|
QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string());
|
||||||
QDir dir(userPath);
|
QDir dir(userPath);
|
||||||
|
|
||||||
if (!dir.exists()) {
|
if (!dir.exists()) {
|
||||||
|
|
|
@ -16,7 +16,7 @@ MwIniImporter::MwIniImporter()
|
||||||
const char *map[][2] =
|
const char *map[][2] =
|
||||||
{
|
{
|
||||||
{ "fps", "General:Show FPS" },
|
{ "fps", "General:Show FPS" },
|
||||||
{ "nosound", "General:Disable Audio" },
|
{ "no-sound", "General:Disable Audio" },
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
const char *fallback[] = {
|
const char *fallback[] = {
|
||||||
|
|
|
@ -86,10 +86,6 @@ void CS::Editor::setupDataFiles()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the charset for reading the esm/esp files
|
|
||||||
// QString encoding = QString::fromStdString(variables["encoding"].as<std::string>());
|
|
||||||
//mFileDialog.setEncoding(encoding);
|
|
||||||
|
|
||||||
dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end());
|
dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end());
|
||||||
|
|
||||||
mDocumentManager.setResourceDir (variables["resources"].as<std::string>());
|
mDocumentManager.setResourceDir (variables["resources"].as<std::string>());
|
||||||
|
|
|
@ -42,10 +42,10 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
// TODO: Ogre startup shouldn't be here, but it currently has to:
|
// 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 :(
|
// SceneWidget destructor will delete the created render window, which would be called _after_ Root has shut down :(
|
||||||
OgreInit::OgreInit ogreInit;
|
|
||||||
ogreInit.init("./opencsOgre.log"); // TODO log path?
|
|
||||||
|
|
||||||
Application mApplication (argc, argv);
|
Application mApplication (argc, argv);
|
||||||
|
OgreInit::OgreInit ogreInit;
|
||||||
|
ogreInit.init("./opencsOgre.log"); // TODO log path?
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
QDir dir(QCoreApplication::applicationDirPath());
|
QDir dir(QCoreApplication::applicationDirPath());
|
||||||
|
|
|
@ -2221,7 +2221,7 @@ void CSMDoc::Document::createBase()
|
||||||
|
|
||||||
CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, bool new_)
|
CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, bool new_)
|
||||||
: mSavePath (savePath), mContentFiles (files), mTools (mData), mResDir(resDir),
|
: mSavePath (savePath), mContentFiles (files), mTools (mData), mResDir(resDir),
|
||||||
mProjectPath ((configuration.getUserPath() / "projects") /
|
mProjectPath ((configuration.getUserDataPath() / "projects") /
|
||||||
(savePath.filename().string() + ".project")),
|
(savePath.filename().string() + ".project")),
|
||||||
mSaving (*this, mProjectPath)
|
mSaving (*this, mProjectPath)
|
||||||
{
|
{
|
||||||
|
@ -2254,7 +2254,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, co
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
boost::filesystem::path locCustomFiltersPath (configuration.getUserPath());
|
boost::filesystem::path locCustomFiltersPath (configuration.getUserDataPath());
|
||||||
locCustomFiltersPath /= "defaultfilters";
|
locCustomFiltersPath /= "defaultfilters";
|
||||||
|
|
||||||
if (boost::filesystem::exists(locCustomFiltersPath))
|
if (boost::filesystem::exists(locCustomFiltersPath))
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration)
|
CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration)
|
||||||
: mConfiguration (configuration)
|
: mConfiguration (configuration)
|
||||||
{
|
{
|
||||||
boost::filesystem::path projectPath = configuration.getUserPath() / "projects";
|
boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects";
|
||||||
|
|
||||||
if (!boost::filesystem::is_directory (projectPath))
|
if (!boost::filesystem::is_directory (projectPath))
|
||||||
boost::filesystem::create_directories (projectPath);
|
boost::filesystem::create_directories (projectPath);
|
||||||
|
|
|
@ -251,7 +251,7 @@ void CSMSettings::UserSettings::loadSettings (const QString &fileName)
|
||||||
bool localOk = loadFromFile(localFilePath);
|
bool localOk = loadFromFile(localFilePath);
|
||||||
|
|
||||||
//user
|
//user
|
||||||
mUserFilePath = QString::fromStdString(mCfgMgr.getUserPath().string()) + fileName;
|
mUserFilePath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()) + fileName;
|
||||||
loadFromFile(mUserFilePath);
|
loadFromFile(mUserFilePath);
|
||||||
|
|
||||||
if (!(localOk || globalOk))
|
if (!(localOk || globalOk))
|
||||||
|
|
|
@ -20,7 +20,7 @@ add_openmw_dir (mwrender
|
||||||
renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation
|
renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation
|
||||||
actors objects renderinginterface localmap occlusionquery water shadows
|
actors objects renderinginterface localmap occlusionquery water shadows
|
||||||
characterpreview externalrendering globalmap videoplayer ripplesimulation refraction
|
characterpreview externalrendering globalmap videoplayer ripplesimulation refraction
|
||||||
terrainstorage
|
terrainstorage renderconst
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwinput
|
add_openmw_dir (mwinput
|
||||||
|
|
|
@ -65,10 +65,6 @@ void OMW::Engine::executeLocalScripts()
|
||||||
localScripts.setIgnore (MWWorld::Ptr());
|
localScripts.setIgnore (MWWorld::Ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
void OMW::Engine::setAnimationVerbose(bool animverbose)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OMW::Engine::frameStarted (const Ogre::FrameEvent& evt)
|
bool OMW::Engine::frameStarted (const Ogre::FrameEvent& evt)
|
||||||
{
|
{
|
||||||
bool paused = MWBase::Environment::get().getWindowManager()->isGuiMode();
|
bool paused = MWBase::Environment::get().getWindowManager()->isGuiMode();
|
||||||
|
@ -301,7 +297,7 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings)
|
||||||
throw std::runtime_error ("No default settings file found! Make sure the file \"settings-default.cfg\" was properly installed.");
|
throw std::runtime_error ("No default settings file found! Make sure the file \"settings-default.cfg\" was properly installed.");
|
||||||
|
|
||||||
// load user settings if they exist, otherwise just load the default settings as user settings
|
// load user settings if they exist, otherwise just load the default settings as user settings
|
||||||
const std::string settingspath = mCfgMgr.getUserPath().string() + "/settings.cfg";
|
const std::string settingspath = mCfgMgr.getUserConfigPath().string() + "/settings.cfg";
|
||||||
if (boost::filesystem::exists(settingspath))
|
if (boost::filesystem::exists(settingspath))
|
||||||
settings.loadUser(settingspath);
|
settings.loadUser(settingspath);
|
||||||
else if (boost::filesystem::exists(localdefault))
|
else if (boost::filesystem::exists(localdefault))
|
||||||
|
@ -373,7 +369,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
// Create input and UI first to set up a bootstrapping environment for
|
// Create input and UI first to set up a bootstrapping environment for
|
||||||
// showing a loading screen and keeping the window responsive while doing so
|
// showing a loading screen and keeping the window responsive while doing so
|
||||||
|
|
||||||
std::string keybinderUser = (mCfgMgr.getUserPath() / "input.xml").string();
|
std::string keybinderUser = (mCfgMgr.getUserConfigPath() / "input.xml").string();
|
||||||
bool keybinderUserExists = boost::filesystem::exists(keybinderUser);
|
bool keybinderUserExists = boost::filesystem::exists(keybinderUser);
|
||||||
MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, mGrab);
|
MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, mGrab);
|
||||||
mEnvironment.setInputManager (input);
|
mEnvironment.setInputManager (input);
|
||||||
|
@ -536,7 +532,7 @@ void OMW::Engine::screenshot()
|
||||||
// Count screenshots.
|
// Count screenshots.
|
||||||
int shotCount = 0;
|
int shotCount = 0;
|
||||||
|
|
||||||
const std::string screenshotPath = mCfgMgr.getUserPath().string();
|
const std::string& screenshotPath = mCfgMgr.getUserDataPath().string();
|
||||||
|
|
||||||
// Find the first unused filename with a do-while
|
// Find the first unused filename with a do-while
|
||||||
std::ostringstream stream;
|
std::ostringstream stream;
|
||||||
|
|
|
@ -171,8 +171,6 @@ namespace OMW
|
||||||
/// Font encoding
|
/// Font encoding
|
||||||
void setEncoding(const ToUTF8::FromType& encoding);
|
void setEncoding(const ToUTF8::FromType& encoding);
|
||||||
|
|
||||||
void setAnimationVerbose(bool animverbose);
|
|
||||||
|
|
||||||
void setFallbackValues(std::map<std::string,std::string> map);
|
void setFallbackValues(std::map<std::string,std::string> map);
|
||||||
|
|
||||||
/// Enable console-only script functionality
|
/// Enable console-only script functionality
|
||||||
|
|
|
@ -121,10 +121,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
||||||
("content", bpo::value<StringsVector>()->default_value(StringsVector(), "")
|
("content", bpo::value<StringsVector>()->default_value(StringsVector(), "")
|
||||||
->multitoken(), "content file(s): esm/esp, or omwgame/omwaddon")
|
->multitoken(), "content file(s): esm/esp, or omwgame/omwaddon")
|
||||||
|
|
||||||
("anim-verbose", bpo::value<bool>()->implicit_value(true)
|
("no-sound", bpo::value<bool>()->implicit_value(true)
|
||||||
->default_value(false), "output animation indices files")
|
|
||||||
|
|
||||||
("nosound", bpo::value<bool>()->implicit_value(true)
|
|
||||||
->default_value(false), "disable all sounds")
|
->default_value(false), "disable all sounds")
|
||||||
|
|
||||||
("script-verbose", bpo::value<bool>()->implicit_value(true)
|
("script-verbose", bpo::value<bool>()->implicit_value(true)
|
||||||
|
@ -168,8 +165,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
||||||
bpo::store(valid_opts, variables);
|
bpo::store(valid_opts, variables);
|
||||||
bpo::notify(variables);
|
bpo::notify(variables);
|
||||||
|
|
||||||
cfgMgr.readConfiguration(variables, desc);
|
|
||||||
|
|
||||||
bool run = true;
|
bool run = true;
|
||||||
|
|
||||||
if (variables.count ("help"))
|
if (variables.count ("help"))
|
||||||
|
@ -187,6 +182,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
||||||
if (!run)
|
if (!run)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
cfgMgr.readConfiguration(variables, desc);
|
||||||
|
|
||||||
engine.setGrabMouse(!variables.count("no-grab"));
|
engine.setGrabMouse(!variables.count("no-grab"));
|
||||||
|
|
||||||
// Font encoding settings
|
// Font encoding settings
|
||||||
|
@ -237,10 +234,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
||||||
engine.setNewGame(variables["new-game"].as<bool>());
|
engine.setNewGame(variables["new-game"].as<bool>());
|
||||||
|
|
||||||
// other settings
|
// other settings
|
||||||
engine.setSoundUsage(!variables["nosound"].as<bool>());
|
engine.setSoundUsage(!variables["no-sound"].as<bool>());
|
||||||
engine.setScriptsVerbosity(variables["script-verbose"].as<bool>());
|
engine.setScriptsVerbosity(variables["script-verbose"].as<bool>());
|
||||||
engine.setCompileAll(variables["script-all"].as<bool>());
|
engine.setCompileAll(variables["script-all"].as<bool>());
|
||||||
engine.setAnimationVerbose(variables["anim-verbose"].as<bool>());
|
|
||||||
engine.setFallbackValues(variables["fallback"].as<FallbackMap>().mMap);
|
engine.setFallbackValues(variables["fallback"].as<FallbackMap>().mMap);
|
||||||
engine.setScriptConsoleMode (variables["script-console"].as<bool>());
|
engine.setScriptConsoleMode (variables["script-console"].as<bool>());
|
||||||
engine.setStartupScript (variables["script-run"].as<std::string>());
|
engine.setStartupScript (variables["script-run"].as<std::string>());
|
||||||
|
|
|
@ -141,15 +141,15 @@ void MWBase::Environment::cleanup()
|
||||||
delete mScriptManager;
|
delete mScriptManager;
|
||||||
mScriptManager = 0;
|
mScriptManager = 0;
|
||||||
|
|
||||||
|
delete mWindowManager;
|
||||||
|
mWindowManager = 0;
|
||||||
|
|
||||||
delete mWorld;
|
delete mWorld;
|
||||||
mWorld = 0;
|
mWorld = 0;
|
||||||
|
|
||||||
delete mSoundManager;
|
delete mSoundManager;
|
||||||
mSoundManager = 0;
|
mSoundManager = 0;
|
||||||
|
|
||||||
delete mWindowManager;
|
|
||||||
mWindowManager = 0;
|
|
||||||
|
|
||||||
delete mInputManager;
|
delete mInputManager;
|
||||||
mInputManager = 0;
|
mInputManager = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,6 +204,7 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void activateQuickKey (int index) = 0;
|
virtual void activateQuickKey (int index) = 0;
|
||||||
|
|
||||||
|
virtual std::string getSelectedSpell() = 0;
|
||||||
virtual void setSelectedSpell(const std::string& spellId, int successChancePercent) = 0;
|
virtual void setSelectedSpell(const std::string& spellId, int successChancePercent) = 0;
|
||||||
virtual void setSelectedEnchantItem(const MWWorld::Ptr& item) = 0;
|
virtual void setSelectedEnchantItem(const MWWorld::Ptr& item) = 0;
|
||||||
virtual void setSelectedWeapon(const MWWorld::Ptr& item) = 0;
|
virtual void setSelectedWeapon(const MWWorld::Ptr& item) = 0;
|
||||||
|
|
|
@ -414,6 +414,13 @@ namespace MWBase
|
||||||
|
|
||||||
virtual bool toggleGodMode() = 0;
|
virtual bool toggleGodMode() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief startSpellCast attempt to start casting a spell. Might fail immediately if conditions are not met.
|
||||||
|
* @param actor
|
||||||
|
* @return true if the spell can be casted (i.e. the animation should start)
|
||||||
|
*/
|
||||||
|
virtual bool startSpellCast (const MWWorld::Ptr& actor) = 0;
|
||||||
|
|
||||||
virtual void castSpell (const MWWorld::Ptr& actor) = 0;
|
virtual void castSpell (const MWWorld::Ptr& actor) = 0;
|
||||||
|
|
||||||
virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
|
virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
|
||||||
|
|
|
@ -466,7 +466,7 @@ namespace MWGui
|
||||||
|
|
||||||
std::string CreateClassDialog::getName() const
|
std::string CreateClassDialog::getName() const
|
||||||
{
|
{
|
||||||
return mEditName->getOnlyText();
|
return mEditName->getCaption();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CreateClassDialog::getDescription() const
|
std::string CreateClassDialog::getDescription() const
|
||||||
|
|
|
@ -228,8 +228,8 @@ namespace MWGui
|
||||||
DescriptionDialog();
|
DescriptionDialog();
|
||||||
~DescriptionDialog();
|
~DescriptionDialog();
|
||||||
|
|
||||||
std::string getTextInput() const { return mTextEdit ? mTextEdit->getOnlyText() : ""; }
|
std::string getTextInput() const { return mTextEdit->getCaption(); }
|
||||||
void setTextInput(const std::string &text) { if (mTextEdit) mTextEdit->setOnlyText(text); }
|
void setTextInput(const std::string &text) { mTextEdit->setCaption(text); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void onOkClicked(MyGUI::Widget* _sender);
|
void onOkClicked(MyGUI::Widget* _sender);
|
||||||
|
|
|
@ -406,13 +406,14 @@ namespace MWGui
|
||||||
setTitle("#{sConsoleTitle} (" + object.getCellRef().mRefID + ")");
|
setTitle("#{sConsoleTitle} (" + object.getCellRef().mRefID + ")");
|
||||||
mPtr = object;
|
mPtr = object;
|
||||||
}
|
}
|
||||||
|
// User clicked on an object. Restore focus to the console command line.
|
||||||
|
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
setTitle("#{sConsoleTitle}");
|
setTitle("#{sConsoleTitle}");
|
||||||
mPtr = MWWorld::Ptr();
|
mPtr = MWWorld::Ptr();
|
||||||
}
|
}
|
||||||
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::onReferenceUnavailable()
|
void Console::onReferenceUnavailable()
|
||||||
|
|
|
@ -61,7 +61,8 @@ namespace MWGui
|
||||||
mDraggedWidget = baseWidget;
|
mDraggedWidget = baseWidget;
|
||||||
MyGUI::ImageBox* image = baseWidget->createWidget<MyGUI::ImageBox>("ImageBox",
|
MyGUI::ImageBox* image = baseWidget->createWidget<MyGUI::ImageBox>("ImageBox",
|
||||||
MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default);
|
MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default);
|
||||||
int pos = path.rfind(".");
|
size_t pos = path.rfind(".");
|
||||||
|
if (pos != std::string::npos)
|
||||||
path.erase(pos);
|
path.erase(pos);
|
||||||
path.append(".dds");
|
path.append(".dds");
|
||||||
image->setImageTexture(path);
|
image->setImageTexture(path);
|
||||||
|
|
|
@ -120,10 +120,13 @@ namespace MWGui
|
||||||
Settings::Manager::getFloat(setting + " y", "Windows") * viewSize.height);
|
Settings::Manager::getFloat(setting + " y", "Windows") * viewSize.height);
|
||||||
MyGUI::IntSize size (Settings::Manager::getFloat(setting + " w", "Windows") * viewSize.width,
|
MyGUI::IntSize size (Settings::Manager::getFloat(setting + " w", "Windows") * viewSize.width,
|
||||||
Settings::Manager::getFloat(setting + " h", "Windows") * viewSize.height);
|
Settings::Manager::getFloat(setting + " h", "Windows") * viewSize.height);
|
||||||
|
|
||||||
|
if (size.width != mMainWidget->getWidth() || size.height != mMainWidget->getHeight())
|
||||||
|
mPreviewDirty = true;
|
||||||
|
|
||||||
mMainWidget->setPosition(pos);
|
mMainWidget->setPosition(pos);
|
||||||
mMainWidget->setSize(size);
|
mMainWidget->setSize(size);
|
||||||
adjustPanes();
|
adjustPanes();
|
||||||
mPreviewDirty = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TradeItemModel* InventoryWindow::getTradeModel()
|
TradeItemModel* InventoryWindow::getTradeModel()
|
||||||
|
|
|
@ -269,13 +269,39 @@ namespace MWGui
|
||||||
|
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||||
MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player);
|
MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player);
|
||||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
|
|
||||||
MWMechanics::Spells& spells = stats.getSpells();
|
if (type == Type_Item || type == Type_MagicItem)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr item = *button->getChildAt (0)->getUserData<MWWorld::Ptr>();
|
||||||
|
// make sure the item is available
|
||||||
|
if (item.getRefData ().getCount() < 1)
|
||||||
|
{
|
||||||
|
// Try searching for a compatible replacement
|
||||||
|
std::string id = item.getCellRef().mRefID;
|
||||||
|
|
||||||
|
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
|
||||||
|
{
|
||||||
|
if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, id))
|
||||||
|
{
|
||||||
|
item = *it;
|
||||||
|
button->getChildAt(0)->setUserData(item);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.getRefData().getCount() < 1)
|
||||||
|
{
|
||||||
|
// No replacement was found
|
||||||
|
MWBase::Environment::get().getWindowManager ()->messageBox (
|
||||||
|
"#{sQuickMenu5} " + MWWorld::Class::get(item).getName(item));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (type == Type_Magic)
|
if (type == Type_Magic)
|
||||||
{
|
{
|
||||||
std::string spellId = button->getChildAt(0)->getUserString("Spell");
|
std::string spellId = button->getChildAt(0)->getUserString("Spell");
|
||||||
spells.setSelectedSpell(spellId);
|
|
||||||
store.setSelectedEnchantItem(store.end());
|
store.setSelectedEnchantItem(store.end());
|
||||||
MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player)));
|
MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player)));
|
||||||
}
|
}
|
||||||
|
@ -283,15 +309,6 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
MWWorld::Ptr item = *button->getChildAt (0)->getUserData<MWWorld::Ptr>();
|
MWWorld::Ptr item = *button->getChildAt (0)->getUserData<MWWorld::Ptr>();
|
||||||
|
|
||||||
// make sure the item is available
|
|
||||||
if (item.getRefData ().getCount() < 1)
|
|
||||||
{
|
|
||||||
// TODO: Try to find a replacement with the same ID?
|
|
||||||
MWBase::Environment::get().getWindowManager ()->messageBox (
|
|
||||||
"#{sQuickMenu5} " + MWWorld::Class::get(item).getName(item));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::shared_ptr<MWWorld::Action> action = MWWorld::Class::get(item).use(item);
|
boost::shared_ptr<MWWorld::Action> action = MWWorld::Class::get(item).use(item);
|
||||||
|
|
||||||
action->execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
|
action->execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
|
||||||
|
@ -310,14 +327,6 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
MWWorld::Ptr item = *button->getChildAt (0)->getUserData<MWWorld::Ptr>();
|
MWWorld::Ptr item = *button->getChildAt (0)->getUserData<MWWorld::Ptr>();
|
||||||
|
|
||||||
// make sure the item is available
|
|
||||||
if (item.getRefData ().getCount() == 0)
|
|
||||||
{
|
|
||||||
MWBase::Environment::get().getWindowManager ()->messageBox (
|
|
||||||
"#{sQuickMenu5} " + MWWorld::Class::get(item).getName(item));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// retrieve ContainerStoreIterator to the item
|
// retrieve ContainerStoreIterator to the item
|
||||||
MWWorld::ContainerStoreIterator it = store.begin();
|
MWWorld::ContainerStoreIterator it = store.begin();
|
||||||
for (; it != store.end(); ++it)
|
for (; it != store.end(); ++it)
|
||||||
|
@ -336,13 +345,9 @@ namespace MWGui
|
||||||
|
|
||||||
MWWorld::ActionEquip action(item);
|
MWWorld::ActionEquip action(item);
|
||||||
action.execute (MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ());
|
action.execute (MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ());
|
||||||
|
|
||||||
// since we changed equipping status, update the inventory window
|
|
||||||
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
store.setSelectedEnchantItem(it);
|
store.setSelectedEnchantItem(it);
|
||||||
spells.setSelectedSpell("");
|
|
||||||
MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item);
|
MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,61 +86,8 @@ namespace MWGui
|
||||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
|
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
|
||||||
MWMechanics::Spells& spells = stats.getSpells();
|
MWMechanics::Spells& spells = stats.getSpells();
|
||||||
|
|
||||||
// the following code switches between selected enchanted item and selected spell (only one of these
|
|
||||||
// can be active at a time)
|
|
||||||
std::string selectedSpell = spells.getSelectedSpell();
|
|
||||||
MWWorld::Ptr selectedItem;
|
|
||||||
if (store.getSelectedEnchantItem() != store.end())
|
|
||||||
{
|
|
||||||
selectedSpell = "";
|
|
||||||
selectedItem = *store.getSelectedEnchantItem();
|
|
||||||
|
|
||||||
bool allowSelectedItem = true;
|
|
||||||
|
|
||||||
// make sure that the item is still in the player inventory, otherwise it can't be selected
|
|
||||||
bool found = false;
|
|
||||||
for (MWWorld::ContainerStoreIterator it(store.begin()); it != store.end(); ++it)
|
|
||||||
{
|
|
||||||
if (*it == selectedItem)
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
allowSelectedItem = false;
|
|
||||||
|
|
||||||
// if the selected item can be equipped, make sure that it actually is equipped
|
|
||||||
std::pair<std::vector<int>, bool> slots_;
|
|
||||||
slots_ = MWWorld::Class::get(selectedItem).getEquipmentSlots(selectedItem);
|
|
||||||
if (!slots_.first.empty())
|
|
||||||
{
|
|
||||||
bool equipped = false;
|
|
||||||
for (int i=0; i < MWWorld::InventoryStore::Slots; ++i)
|
|
||||||
{
|
|
||||||
if (store.getSlot(i) != store.end() && *store.getSlot(i) == selectedItem)
|
|
||||||
{
|
|
||||||
equipped = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!equipped)
|
|
||||||
allowSelectedItem = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!allowSelectedItem)
|
|
||||||
{
|
|
||||||
store.setSelectedEnchantItem(store.end());
|
|
||||||
spells.setSelectedSpell("");
|
|
||||||
MWBase::Environment::get().getWindowManager()->unsetSelectedSpell();
|
|
||||||
selectedItem = MWWorld::Ptr();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
|
for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
|
||||||
{
|
|
||||||
spellList.push_back (it->first);
|
spellList.push_back (it->first);
|
||||||
}
|
|
||||||
|
|
||||||
const MWWorld::ESMStore &esmStore =
|
const MWWorld::ESMStore &esmStore =
|
||||||
MWBase::Environment::get().getWorld()->getStore();
|
MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
@ -210,7 +157,7 @@ namespace MWGui
|
||||||
t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel);
|
t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel);
|
||||||
t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected);
|
t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected);
|
||||||
|
|
||||||
if (*it == selectedSpell)
|
if (*it == MWBase::Environment::get().getWindowManager()->getSelectedSpell())
|
||||||
t->setStateSelected(true);
|
t->setStateSelected(true);
|
||||||
|
|
||||||
mHeight += spellHeight;
|
mHeight += spellHeight;
|
||||||
|
@ -229,7 +176,7 @@ namespace MWGui
|
||||||
t->setUserString("Spell", *it);
|
t->setUserString("Spell", *it);
|
||||||
t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel);
|
t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel);
|
||||||
t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected);
|
t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected);
|
||||||
t->setStateSelected(*it == selectedSpell);
|
t->setStateSelected(*it == MWBase::Environment::get().getWindowManager()->getSelectedSpell());
|
||||||
|
|
||||||
// cost / success chance
|
// cost / success chance
|
||||||
MyGUI::Button* costChance = mSpellView->createWidget<MyGUI::Button>("SpellText",
|
MyGUI::Button* costChance = mSpellView->createWidget<MyGUI::Button>("SpellText",
|
||||||
|
@ -239,7 +186,7 @@ namespace MWGui
|
||||||
costChance->setCaption(cost + "/" + chance);
|
costChance->setCaption(cost + "/" + chance);
|
||||||
costChance->setTextAlign(MyGUI::Align::Right);
|
costChance->setTextAlign(MyGUI::Align::Right);
|
||||||
costChance->setNeedMouseFocus(false);
|
costChance->setNeedMouseFocus(false);
|
||||||
costChance->setStateSelected(*it == selectedSpell);
|
costChance->setStateSelected(*it == MWBase::Environment::get().getWindowManager()->getSelectedSpell());
|
||||||
|
|
||||||
|
|
||||||
mHeight += spellHeight;
|
mHeight += spellHeight;
|
||||||
|
@ -276,7 +223,9 @@ namespace MWGui
|
||||||
t->setUserString("Equipped", equipped ? "true" : "false");
|
t->setUserString("Equipped", equipped ? "true" : "false");
|
||||||
t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onEnchantedItemSelected);
|
t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onEnchantedItemSelected);
|
||||||
t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel);
|
t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel);
|
||||||
t->setStateSelected(item == selectedItem);
|
if (store.getSelectedEnchantItem() != store.end())
|
||||||
|
t->setStateSelected(item == *store.getSelectedEnchantItem());
|
||||||
|
|
||||||
|
|
||||||
// cost / charge
|
// cost / charge
|
||||||
MyGUI::Button* costCharge = mSpellView->createWidget<MyGUI::Button>(equipped ? "SpellText" : "SpellTextUnequipped",
|
MyGUI::Button* costCharge = mSpellView->createWidget<MyGUI::Button>(equipped ? "SpellText" : "SpellTextUnequipped",
|
||||||
|
@ -302,7 +251,8 @@ namespace MWGui
|
||||||
costCharge->setCaption(cost + "/" + charge);
|
costCharge->setCaption(cost + "/" + charge);
|
||||||
costCharge->setTextAlign(MyGUI::Align::Right);
|
costCharge->setTextAlign(MyGUI::Align::Right);
|
||||||
costCharge->setNeedMouseFocus(false);
|
costCharge->setNeedMouseFocus(false);
|
||||||
costCharge->setStateSelected(item == selectedItem);
|
if (store.getSelectedEnchantItem() != store.end())
|
||||||
|
costCharge->setStateSelected(item == *store.getSelectedEnchantItem());
|
||||||
|
|
||||||
mHeight += spellHeight;
|
mHeight += spellHeight;
|
||||||
}
|
}
|
||||||
|
@ -349,9 +299,7 @@ namespace MWGui
|
||||||
void SpellWindow::onEnchantedItemSelected(MyGUI::Widget* _sender)
|
void SpellWindow::onEnchantedItemSelected(MyGUI::Widget* _sender)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
|
|
||||||
MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player);
|
MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player);
|
||||||
MWMechanics::Spells& spells = stats.getSpells();
|
|
||||||
MWWorld::Ptr item = *_sender->getUserData<MWWorld::Ptr>();
|
MWWorld::Ptr item = *_sender->getUserData<MWWorld::Ptr>();
|
||||||
|
|
||||||
// retrieve ContainerStoreIterator to the item
|
// retrieve ContainerStoreIterator to the item
|
||||||
|
@ -379,7 +327,6 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
|
|
||||||
store.setSelectedEnchantItem(it);
|
store.setSelectedEnchantItem(it);
|
||||||
spells.setSelectedSpell("");
|
|
||||||
MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item);
|
MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item);
|
||||||
|
|
||||||
updateSpells();
|
updateSpells();
|
||||||
|
@ -389,9 +336,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
std::string spellId = _sender->getUserString("Spell");
|
std::string spellId = _sender->getUserString("Spell");
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
|
|
||||||
MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player);
|
MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player);
|
||||||
MWMechanics::Spells& spells = stats.getSpells();
|
|
||||||
|
|
||||||
if (MyGUI::InputManager::getInstance().isShiftPressed())
|
if (MyGUI::InputManager::getInstance().isShiftPressed())
|
||||||
{
|
{
|
||||||
|
@ -419,7 +364,6 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
spells.setSelectedSpell(spellId);
|
|
||||||
store.setSelectedEnchantItem(store.end());
|
store.setSelectedEnchantItem(store.end());
|
||||||
MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player)));
|
MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player)));
|
||||||
}
|
}
|
||||||
|
@ -450,10 +394,7 @@ namespace MWGui
|
||||||
MWMechanics::Spells& spells = stats.getSpells();
|
MWMechanics::Spells& spells = stats.getSpells();
|
||||||
|
|
||||||
if (spells.getSelectedSpell() == mSpellToDelete)
|
if (spells.getSelectedSpell() == mSpellToDelete)
|
||||||
{
|
|
||||||
spells.setSelectedSpell("");
|
|
||||||
MWBase::Environment::get().getWindowManager()->unsetSelectedSpell();
|
MWBase::Environment::get().getWindowManager()->unsetSelectedSpell();
|
||||||
}
|
|
||||||
|
|
||||||
spells.remove(mSpellToDelete);
|
spells.remove(mSpellToDelete);
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@ namespace MWGui
|
||||||
public:
|
public:
|
||||||
TextInputDialog();
|
TextInputDialog();
|
||||||
|
|
||||||
std::string getTextInput() const { return mTextEdit ? mTextEdit->getOnlyText() : ""; }
|
std::string getTextInput() const { return mTextEdit->getCaption(); }
|
||||||
void setTextInput(const std::string &text) { if (mTextEdit) mTextEdit->setOnlyText(text); }
|
void setTextInput(const std::string &text) { mTextEdit->setCaption(text); }
|
||||||
|
|
||||||
void setNextButtonShow(bool shown);
|
void setNextButtonShow(bool shown);
|
||||||
void setTextLabel(const std::string &label);
|
void setTextLabel(const std::string &label);
|
||||||
|
|
|
@ -1010,6 +1010,7 @@ namespace MWGui
|
||||||
|
|
||||||
void WindowManager::setSelectedSpell(const std::string& spellId, int successChancePercent)
|
void WindowManager::setSelectedSpell(const std::string& spellId, int successChancePercent)
|
||||||
{
|
{
|
||||||
|
mSelectedSpell = spellId;
|
||||||
mHud->setSelectedSpell(spellId, successChancePercent);
|
mHud->setSelectedSpell(spellId, successChancePercent);
|
||||||
|
|
||||||
const ESM::Spell* spell =
|
const ESM::Spell* spell =
|
||||||
|
@ -1020,6 +1021,7 @@ namespace MWGui
|
||||||
|
|
||||||
void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item)
|
void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item)
|
||||||
{
|
{
|
||||||
|
mSelectedSpell = "";
|
||||||
const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>()
|
const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>()
|
||||||
.find(MWWorld::Class::get(item).getEnchantment(item));
|
.find(MWWorld::Class::get(item).getEnchantment(item));
|
||||||
|
|
||||||
|
@ -1039,6 +1041,7 @@ namespace MWGui
|
||||||
|
|
||||||
void WindowManager::unsetSelectedSpell()
|
void WindowManager::unsetSelectedSpell()
|
||||||
{
|
{
|
||||||
|
mSelectedSpell = "";
|
||||||
mHud->unsetSelectedSpell();
|
mHud->unsetSelectedSpell();
|
||||||
mSpellWindow->setTitle("#{sNone}");
|
mSpellWindow->setTitle("#{sNone}");
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,6 +200,7 @@ namespace MWGui
|
||||||
|
|
||||||
virtual void activateQuickKey (int index);
|
virtual void activateQuickKey (int index);
|
||||||
|
|
||||||
|
virtual std::string getSelectedSpell() { return mSelectedSpell; }
|
||||||
virtual void setSelectedSpell(const std::string& spellId, int successChancePercent);
|
virtual void setSelectedSpell(const std::string& spellId, int successChancePercent);
|
||||||
virtual void setSelectedEnchantItem(const MWWorld::Ptr& item);
|
virtual void setSelectedEnchantItem(const MWWorld::Ptr& item);
|
||||||
virtual void setSelectedWeapon(const MWWorld::Ptr& item);
|
virtual void setSelectedWeapon(const MWWorld::Ptr& item);
|
||||||
|
@ -288,6 +289,8 @@ namespace MWGui
|
||||||
void trackWindow(OEngine::GUI::Layout* layout, const std::string& name);
|
void trackWindow(OEngine::GUI::Layout* layout, const std::string& name);
|
||||||
void onWindowChangeCoord(MyGUI::Window* _sender);
|
void onWindowChangeCoord(MyGUI::Window* _sender);
|
||||||
|
|
||||||
|
std::string mSelectedSpell;
|
||||||
|
|
||||||
OEngine::GUI::MyGUIManager *mGuiManager;
|
OEngine::GUI::MyGUIManager *mGuiManager;
|
||||||
OEngine::Render::OgreRenderer *mRendering;
|
OEngine::Render::OgreRenderer *mRendering;
|
||||||
HUD *mHud;
|
HUD *mHud;
|
||||||
|
|
|
@ -378,10 +378,9 @@ namespace MWInput
|
||||||
MWBase::Environment::get().getWorld()->togglePreviewMode(true);
|
MWBase::Environment::get().getWorld()->togglePreviewMode(true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (mPreviewPOVDelay > 0.5) {
|
|
||||||
//disable preview mode
|
//disable preview mode
|
||||||
MWBase::Environment::get().getWorld()->togglePreviewMode(false);
|
MWBase::Environment::get().getWorld()->togglePreviewMode(false);
|
||||||
} else if (mPreviewPOVDelay > 0.f) {
|
if (mPreviewPOVDelay > 0.f && mPreviewPOVDelay <= 0.5) {
|
||||||
MWBase::Environment::get().getWorld()->togglePOV();
|
MWBase::Environment::get().getWorld()->togglePOV();
|
||||||
}
|
}
|
||||||
mPreviewPOVDelay = 0.f;
|
mPreviewPOVDelay = 0.f;
|
||||||
|
|
|
@ -350,7 +350,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
||||||
, mSkipAnim(false)
|
, mSkipAnim(false)
|
||||||
, mSecondsOfRunning(0)
|
, mSecondsOfRunning(0)
|
||||||
, mSecondsOfSwimming(0)
|
, mSecondsOfSwimming(0)
|
||||||
, mFallHeight(0)
|
|
||||||
{
|
{
|
||||||
if(!mAnimation)
|
if(!mAnimation)
|
||||||
return;
|
return;
|
||||||
|
@ -426,10 +425,10 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
|
||||||
{
|
{
|
||||||
forcestateupdate = true;
|
forcestateupdate = true;
|
||||||
|
|
||||||
// Shields shouldn't be visible during spellcasting
|
// Shields/torches shouldn't be visible during spellcasting or hand-to-hand
|
||||||
// There seems to be no text keys for this purpose, except maybe for "[un]equip start/stop",
|
// There seems to be no text keys for this purpose, except maybe for "[un]equip start/stop",
|
||||||
// but they are also present in weapon drawing animation.
|
// but they are also present in weapon drawing animation.
|
||||||
mAnimation->showShield(weaptype != WeapType_Spell);
|
mAnimation->showCarriedLeft(weaptype != WeapType_Spell && weaptype != WeapType_HandToHand);
|
||||||
|
|
||||||
std::string weapgroup;
|
std::string weapgroup;
|
||||||
if(weaptype == WeapType_None)
|
if(weaptype == WeapType_None)
|
||||||
|
@ -505,10 +504,21 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
|
||||||
mAttackType.clear();
|
mAttackType.clear();
|
||||||
if(mWeaponType == WeapType_Spell)
|
if(mWeaponType == WeapType_Spell)
|
||||||
{
|
{
|
||||||
|
// Unset casting flag, otherwise pressing the mouse button down would
|
||||||
|
// continue casting every frame if there is no animation
|
||||||
|
mPtr.getClass().getCreatureStats(mPtr).setAttackingOrSpell(false);
|
||||||
|
|
||||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
|
||||||
const std::string spellid = stats.getSpells().getSelectedSpell();
|
// For the player, set the spell we want to cast
|
||||||
if(!spellid.empty())
|
// This has to be done at the start of the casting animation,
|
||||||
|
// *not* when selecting a spell in the GUI (otherwise you could change the spell mid-animation)
|
||||||
|
if (mPtr.getRefData().getHandle() == "player")
|
||||||
|
stats.getSpells().setSelectedSpell(MWBase::Environment::get().getWindowManager()->getSelectedSpell());
|
||||||
|
|
||||||
|
std::string spellid = stats.getSpells().getSelectedSpell();
|
||||||
|
|
||||||
|
if(!spellid.empty() && MWBase::Environment::get().getWorld()->startSpellCast(mPtr))
|
||||||
{
|
{
|
||||||
static const std::string schools[] = {
|
static const std::string schools[] = {
|
||||||
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
|
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
|
||||||
|
@ -709,7 +719,8 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
|
||||||
|
|
||||||
|
|
||||||
MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
|
MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
|
||||||
if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name())
|
if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name()
|
||||||
|
&& mWeaponType != WeapType_Spell && mWeaponType != WeapType_HandToHand)
|
||||||
{
|
{
|
||||||
if(!mAnimation->isPlaying("torch"))
|
if(!mAnimation->isPlaying("torch"))
|
||||||
mAnimation->play("torch", Priority_Torch,
|
mAnimation->play("torch", Priority_Torch,
|
||||||
|
@ -789,10 +800,7 @@ void CharacterController::update(float duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sneak || inwater || flying)
|
if(sneak || inwater || flying)
|
||||||
{
|
|
||||||
vec.z = 0.0f;
|
vec.z = 0.0f;
|
||||||
mFallHeight = mPtr.getRefData().getPosition().pos[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!onground && !flying && !inwater)
|
if(!onground && !flying && !inwater)
|
||||||
{
|
{
|
||||||
|
@ -801,11 +809,7 @@ void CharacterController::update(float duration)
|
||||||
if (world->isSlowFalling(mPtr))
|
if (world->isSlowFalling(mPtr))
|
||||||
{
|
{
|
||||||
// SlowFalling spell effect is active, do not keep previous fall height
|
// SlowFalling spell effect is active, do not keep previous fall height
|
||||||
mFallHeight = mPtr.getRefData().getPosition().pos[2];
|
cls.getCreatureStats(mPtr).land();
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mFallHeight = std::max(mFallHeight, mPtr.getRefData().getPosition().pos[2]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
|
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
|
||||||
|
@ -861,7 +865,8 @@ void CharacterController::update(float duration)
|
||||||
mJumpState = JumpState_Landing;
|
mJumpState = JumpState_Landing;
|
||||||
vec.z = 0.0f;
|
vec.z = 0.0f;
|
||||||
|
|
||||||
float healthLost = cls.getFallDamage(mPtr, mFallHeight - mPtr.getRefData().getPosition().pos[2]);
|
float height = cls.getCreatureStats(mPtr).land();
|
||||||
|
float healthLost = cls.getFallDamage(mPtr, height);
|
||||||
if (healthLost > 0.0f)
|
if (healthLost > 0.0f)
|
||||||
{
|
{
|
||||||
const float fatigueTerm = cls.getCreatureStats(mPtr).getFatigueTerm();
|
const float fatigueTerm = cls.getCreatureStats(mPtr).getFatigueTerm();
|
||||||
|
@ -882,8 +887,6 @@ void CharacterController::update(float duration)
|
||||||
//TODO: actor falls over
|
//TODO: actor falls over
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mFallHeight = mPtr.getRefData().getPosition().pos[2];
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -922,6 +925,9 @@ void CharacterController::update(float duration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (onground || inwater || flying)
|
||||||
|
cls.getCreatureStats(mPtr).land();
|
||||||
|
|
||||||
if(movestate != CharState_None)
|
if(movestate != CharState_None)
|
||||||
clearAnimQueue();
|
clearAnimQueue();
|
||||||
|
|
||||||
|
|
|
@ -156,9 +156,6 @@ class CharacterController
|
||||||
float mSecondsOfSwimming;
|
float mSecondsOfSwimming;
|
||||||
float mSecondsOfRunning;
|
float mSecondsOfRunning;
|
||||||
|
|
||||||
// used for acrobatics progress and fall damages
|
|
||||||
float mFallHeight;
|
|
||||||
|
|
||||||
std::string mAttackType; // slash, chop or thrust
|
std::string mAttackType; // slash, chop or thrust
|
||||||
|
|
||||||
void refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force=false);
|
void refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force=false);
|
||||||
|
|
|
@ -14,7 +14,8 @@ namespace MWMechanics
|
||||||
mTalkedTo (false), mAlarmed (false),
|
mTalkedTo (false), mAlarmed (false),
|
||||||
mAttacked (false), mHostile (false),
|
mAttacked (false), mHostile (false),
|
||||||
mAttackingOrSpell(false), mAttackType(AT_Chop),
|
mAttackingOrSpell(false), mAttackType(AT_Chop),
|
||||||
mIsWerewolf(false)
|
mIsWerewolf(false),
|
||||||
|
mFallHeight(0)
|
||||||
{
|
{
|
||||||
for (int i=0; i<4; ++i)
|
for (int i=0; i<4; ++i)
|
||||||
mAiSettings[i] = 0;
|
mAiSettings[i] = 0;
|
||||||
|
@ -356,4 +357,16 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
mUsedPowers[power] = MWBase::Environment::get().getWorld()->getTimeStamp();
|
mUsedPowers[power] = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CreatureStats::addToFallHeight(float height)
|
||||||
|
{
|
||||||
|
mFallHeight += height;
|
||||||
|
}
|
||||||
|
|
||||||
|
float CreatureStats::land()
|
||||||
|
{
|
||||||
|
float height = mFallHeight;
|
||||||
|
mFallHeight = 0;
|
||||||
|
return height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,8 @@ namespace MWMechanics
|
||||||
bool mHostile;
|
bool mHostile;
|
||||||
bool mAttackingOrSpell;//for the player, this is true if the left mouse button is pressed, false if not.
|
bool mAttackingOrSpell;//for the player, this is true if the left mouse button is pressed, false if not.
|
||||||
|
|
||||||
|
float mFallHeight;
|
||||||
|
|
||||||
int mAttackType;
|
int mAttackType;
|
||||||
|
|
||||||
std::string mLastHitObject; // The last object to hit this actor
|
std::string mLastHitObject; // The last object to hit this actor
|
||||||
|
@ -49,6 +51,12 @@ namespace MWMechanics
|
||||||
public:
|
public:
|
||||||
CreatureStats();
|
CreatureStats();
|
||||||
|
|
||||||
|
void addToFallHeight(float height);
|
||||||
|
|
||||||
|
/// Reset the fall height
|
||||||
|
/// @return total fall height
|
||||||
|
float land();
|
||||||
|
|
||||||
bool canUsePower (const std::string& power) const;
|
bool canUsePower (const std::string& power) const;
|
||||||
void usePower (const std::string& power);
|
void usePower (const std::string& power);
|
||||||
|
|
||||||
|
|
|
@ -300,9 +300,10 @@ namespace MWMechanics
|
||||||
if (item.getCellRef().mEnchantmentCharge == -1)
|
if (item.getCellRef().mEnchantmentCharge == -1)
|
||||||
item.getCellRef().mEnchantmentCharge = enchantment->mData.mCharge;
|
item.getCellRef().mEnchantmentCharge = enchantment->mData.mCharge;
|
||||||
|
|
||||||
if (mCaster.getRefData().getHandle() == "player" && item.getCellRef().mEnchantmentCharge < castCost)
|
if (item.getCellRef().mEnchantmentCharge < castCost)
|
||||||
{
|
{
|
||||||
// TODO: Should there be a sound here?
|
// TODO: Should there be a sound here?
|
||||||
|
if (mCaster.getRefData().getHandle() == "player")
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientCharge}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientCharge}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -370,33 +371,7 @@ namespace MWMechanics
|
||||||
fatigue.setCurrent(std::max(0.f, fatigue.getCurrent() - fatigueLoss));
|
fatigue.setCurrent(std::max(0.f, fatigue.getCurrent() - fatigueLoss));
|
||||||
stats.setFatigue(fatigue);
|
stats.setFatigue(fatigue);
|
||||||
|
|
||||||
// Check mana
|
|
||||||
bool fail = false;
|
bool fail = false;
|
||||||
DynamicStat<float> magicka = stats.getMagicka();
|
|
||||||
if (magicka.getCurrent() < spell->mData.mCost)
|
|
||||||
{
|
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientSP}");
|
|
||||||
fail = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reduce mana
|
|
||||||
if (!fail)
|
|
||||||
{
|
|
||||||
magicka.setCurrent(magicka.getCurrent() - spell->mData.mCost);
|
|
||||||
stats.setMagicka(magicka);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is a power, check if it was already used in last 24h
|
|
||||||
if (!fail && spell->mData.mType & ESM::Spell::ST_Power)
|
|
||||||
{
|
|
||||||
if (stats.canUsePower(spell->mId))
|
|
||||||
stats.usePower(spell->mId);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sPowerAlreadyUsed}");
|
|
||||||
fail = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check success
|
// Check success
|
||||||
int successChance = getSpellSuccessChance(spell, mCaster);
|
int successChance = getSpellSuccessChance(spell, mCaster);
|
||||||
|
|
|
@ -125,7 +125,7 @@ namespace MWMechanics
|
||||||
const ESM::Spell *spell =
|
const ESM::Spell *spell =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (iter->first);
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (iter->first);
|
||||||
|
|
||||||
if (spell->mData.mType & ESM::Spell::ST_Disease)
|
if (spell->mData.mType == ESM::Spell::ST_Disease)
|
||||||
mSpells.erase(iter++);
|
mSpells.erase(iter++);
|
||||||
else
|
else
|
||||||
iter++;
|
iter++;
|
||||||
|
@ -139,7 +139,7 @@ namespace MWMechanics
|
||||||
const ESM::Spell *spell =
|
const ESM::Spell *spell =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (iter->first);
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (iter->first);
|
||||||
|
|
||||||
if (spell->mData.mType & ESM::Spell::ST_Blight)
|
if (spell->mData.mType == ESM::Spell::ST_Blight)
|
||||||
mSpells.erase(iter++);
|
mSpells.erase(iter++);
|
||||||
else
|
else
|
||||||
iter++;
|
iter++;
|
||||||
|
|
|
@ -150,9 +150,12 @@ void Actors::removeCell(MWWorld::Ptr::CellStore* store)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actors::update (float duration)
|
void Actors::update (Ogre::Camera* camera)
|
||||||
{
|
{
|
||||||
// Nothing to do
|
for(PtrAnimationMap::iterator iter = mAllActors.begin();iter != mAllActors.end(); ++iter)
|
||||||
|
{
|
||||||
|
iter->second->preRender(camera);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Animation* Actors::getAnimation(const MWWorld::Ptr &ptr)
|
Animation* Actors::getAnimation(const MWWorld::Ptr &ptr)
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace MWRender
|
||||||
|
|
||||||
void removeCell(MWWorld::CellStore* store);
|
void removeCell(MWWorld::CellStore* store);
|
||||||
|
|
||||||
void update (float duration);
|
void update (Ogre::Camera* camera);
|
||||||
|
|
||||||
/// Updates containing cell for object rendering data
|
/// Updates containing cell for object rendering data
|
||||||
void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur);
|
void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur);
|
||||||
|
|
|
@ -146,30 +146,22 @@ void Animation::setObjectRoot(const std::string &model, bool baseonly)
|
||||||
struct AddGlow
|
struct AddGlow
|
||||||
{
|
{
|
||||||
Ogre::Vector3* mColor;
|
Ogre::Vector3* mColor;
|
||||||
AddGlow(Ogre::Vector3* col) : mColor(col) {}
|
NifOgre::MaterialControllerManager* mMaterialControllerMgr;
|
||||||
|
AddGlow(Ogre::Vector3* col, NifOgre::MaterialControllerManager* materialControllerMgr)
|
||||||
|
: mColor(col)
|
||||||
|
, mMaterialControllerMgr(materialControllerMgr)
|
||||||
|
{}
|
||||||
|
|
||||||
// TODO: integrate this with material controllers?
|
|
||||||
void operator()(Ogre::Entity* entity) const
|
void operator()(Ogre::Entity* entity) const
|
||||||
{
|
{
|
||||||
unsigned int numsubs = entity->getNumSubEntities();
|
if (!entity->getNumSubEntities())
|
||||||
for(unsigned int i = 0;i < numsubs;++i)
|
return;
|
||||||
{
|
Ogre::MaterialPtr writableMaterial = mMaterialControllerMgr->getWritableMaterial(entity);
|
||||||
unsigned int numsubs = entity->getNumSubEntities();
|
sh::MaterialInstance* instance = sh::Factory::getInstance().getMaterialInstance(writableMaterial->getName());
|
||||||
for(unsigned int i = 0;i < numsubs;++i)
|
|
||||||
{
|
|
||||||
Ogre::SubEntity* subEnt = entity->getSubEntity(i);
|
|
||||||
std::string newName = subEnt->getMaterialName() + "@fx";
|
|
||||||
if (sh::Factory::getInstance().searchInstance(newName) == NULL)
|
|
||||||
{
|
|
||||||
sh::MaterialInstance* instance =
|
|
||||||
sh::Factory::getInstance().createMaterialInstance(newName, subEnt->getMaterialName());
|
|
||||||
instance->setProperty("env_map", sh::makeProperty(new sh::BooleanValue(true)));
|
instance->setProperty("env_map", sh::makeProperty(new sh::BooleanValue(true)));
|
||||||
instance->setProperty("env_map_color", sh::makeProperty(new sh::Vector3(mColor->x, mColor->y, mColor->z)));
|
instance->setProperty("env_map_color", sh::makeProperty(new sh::Vector3(mColor->x, mColor->y, mColor->z)));
|
||||||
}
|
}
|
||||||
subEnt->setMaterialName(newName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class VisQueueSet
|
class VisQueueSet
|
||||||
|
@ -216,7 +208,7 @@ void Animation::setRenderProperties(NifOgre::ObjectScenePtr objlist, Ogre::uint3
|
||||||
|
|
||||||
if (enchantedGlow)
|
if (enchantedGlow)
|
||||||
std::for_each(objlist->mEntities.begin(), objlist->mEntities.end(),
|
std::for_each(objlist->mEntities.begin(), objlist->mEntities.end(),
|
||||||
AddGlow(glowColor));
|
AddGlow(glowColor, &objlist->mMaterialControllerMgr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1004,6 +996,16 @@ void Animation::detachObjectFromBone(Ogre::MovableObject *obj)
|
||||||
mSkelBase->detachObjectFromBone(obj);
|
mSkelBase->detachObjectFromBone(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Animation::isPlaying(Group group) const
|
||||||
|
{
|
||||||
|
for (AnimStateMap::const_iterator stateiter = mStates.begin(); stateiter != mStates.end(); ++stateiter)
|
||||||
|
{
|
||||||
|
if(stateiter->second.mGroups == group)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Animation::addEffect(const std::string &model, int effectId, bool loop, const std::string &bonename, std::string texture)
|
void Animation::addEffect(const std::string &model, int effectId, bool loop, const std::string &bonename, std::string texture)
|
||||||
{
|
{
|
||||||
// Early out if we already have this effect
|
// Early out if we already have this effect
|
||||||
|
@ -1025,6 +1027,10 @@ void Animation::addEffect(const std::string &model, int effectId, bool loop, con
|
||||||
params.mObjects = NifOgre::Loader::createObjects(mInsert, model);
|
params.mObjects = NifOgre::Loader::createObjects(mInsert, model);
|
||||||
else
|
else
|
||||||
params.mObjects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model);
|
params.mObjects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model);
|
||||||
|
|
||||||
|
setRenderProperties(params.mObjects, RV_Misc,
|
||||||
|
RQG_Main, RQG_Alpha, 0.f, false, NULL);
|
||||||
|
|
||||||
params.mLoop = loop;
|
params.mLoop = loop;
|
||||||
params.mEffectId = effectId;
|
params.mEffectId = effectId;
|
||||||
params.mBoneName = bonename;
|
params.mBoneName = bonename;
|
||||||
|
@ -1040,17 +1046,12 @@ void Animation::addEffect(const std::string &model, int effectId, bool loop, con
|
||||||
for(size_t i = 0;i < params.mObjects->mParticles.size(); ++i)
|
for(size_t i = 0;i < params.mObjects->mParticles.size(); ++i)
|
||||||
{
|
{
|
||||||
Ogre::ParticleSystem* partSys = params.mObjects->mParticles[i];
|
Ogre::ParticleSystem* partSys = params.mObjects->mParticles[i];
|
||||||
sh::Factory::getInstance()._ensureMaterial(partSys->getMaterialName(), "Default");
|
|
||||||
Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().getByName(partSys->getMaterialName());
|
|
||||||
static int count = 0;
|
|
||||||
Ogre::String materialName = "openmw/" + Ogre::StringConverter::toString(count++);
|
|
||||||
// TODO: destroy when effect is removed
|
|
||||||
Ogre::MaterialPtr newMat = mat->clone(materialName);
|
|
||||||
partSys->setMaterialName(materialName);
|
|
||||||
|
|
||||||
for (int t=0; t<newMat->getNumTechniques(); ++t)
|
Ogre::MaterialPtr mat = params.mObjects->mMaterialControllerMgr.getWritableMaterial(partSys);
|
||||||
|
|
||||||
|
for (int t=0; t<mat->getNumTechniques(); ++t)
|
||||||
{
|
{
|
||||||
Ogre::Technique* tech = newMat->getTechnique(t);
|
Ogre::Technique* tech = mat->getTechnique(t);
|
||||||
for (int p=0; p<tech->getNumPasses(); ++p)
|
for (int p=0; p<tech->getNumPasses(); ++p)
|
||||||
{
|
{
|
||||||
Ogre::Pass* pass = tech->getPass(p);
|
Ogre::Pass* pass = tech->getPass(p);
|
||||||
|
@ -1125,6 +1126,16 @@ void Animation::updateEffects(float duration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Animation::preRender(Ogre::Camera *camera)
|
||||||
|
{
|
||||||
|
for (std::vector<EffectParams>::iterator it = mEffects.begin(); it != mEffects.end(); ++it)
|
||||||
|
{
|
||||||
|
NifOgre::ObjectScenePtr objects = it->mObjects;
|
||||||
|
objects->rotateBillboardNodes(camera);
|
||||||
|
}
|
||||||
|
mObjectRoot->rotateBillboardNodes(camera);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Should not be here
|
// TODO: Should not be here
|
||||||
Ogre::Vector3 Animation::getEnchantmentColor(MWWorld::Ptr item)
|
Ogre::Vector3 Animation::getEnchantmentColor(MWWorld::Ptr item)
|
||||||
{
|
{
|
||||||
|
@ -1188,6 +1199,8 @@ bool ObjectAnimation::canBatch() const
|
||||||
{
|
{
|
||||||
if(!mObjectRoot->mParticles.empty() || !mObjectRoot->mLights.empty() || !mObjectRoot->mControllers.empty())
|
if(!mObjectRoot->mParticles.empty() || !mObjectRoot->mLights.empty() || !mObjectRoot->mControllers.empty())
|
||||||
return false;
|
return false;
|
||||||
|
if (!mObjectRoot->mBillboardNodes.empty())
|
||||||
|
return false;
|
||||||
return std::find_if(mObjectRoot->mEntities.begin(), mObjectRoot->mEntities.end(),
|
return std::find_if(mObjectRoot->mEntities.begin(), mObjectRoot->mEntities.end(),
|
||||||
FindEntityTransparency()) == mObjectRoot->mEntities.end();
|
FindEntityTransparency()) == mObjectRoot->mEntities.end();
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,6 +216,9 @@ public:
|
||||||
void removeEffect (int effectId);
|
void removeEffect (int effectId);
|
||||||
void getLoopingEffects (std::vector<int>& out);
|
void getLoopingEffects (std::vector<int>& out);
|
||||||
|
|
||||||
|
/// Prepare this animation for being rendered with \a camera (rotates billboard nodes)
|
||||||
|
virtual void preRender (Ogre::Camera* camera);
|
||||||
|
|
||||||
virtual void setAlpha(float alpha) {}
|
virtual void setAlpha(float alpha) {}
|
||||||
private:
|
private:
|
||||||
void updateEffects(float duration);
|
void updateEffects(float duration);
|
||||||
|
@ -255,6 +258,8 @@ public:
|
||||||
/** Returns true if the named animation group is playing. */
|
/** Returns true if the named animation group is playing. */
|
||||||
bool isPlaying(const std::string &groupname) const;
|
bool isPlaying(const std::string &groupname) const;
|
||||||
|
|
||||||
|
bool isPlaying(Group group) const;
|
||||||
|
|
||||||
/** Gets info about the given animation group.
|
/** Gets info about the given animation group.
|
||||||
* \param groupname Animation group to check.
|
* \param groupname Animation group to check.
|
||||||
* \param complete Stores completion amount (0 = at start key, 0.5 = half way between start and stop keys), etc.
|
* \param complete Stores completion amount (0 = at start key, 0.5 = half way between start and stop keys), etc.
|
||||||
|
@ -274,7 +279,7 @@ public:
|
||||||
virtual Ogre::Vector3 runAnimation(float duration);
|
virtual Ogre::Vector3 runAnimation(float duration);
|
||||||
|
|
||||||
virtual void showWeapons(bool showWeapon);
|
virtual void showWeapons(bool showWeapon);
|
||||||
virtual void showShield(bool show) {}
|
virtual void showCarriedLeft(bool show) {}
|
||||||
|
|
||||||
void enableLights(bool enable);
|
void enableLights(bool enable);
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,9 @@ namespace MWRender
|
||||||
mNearest(30.f),
|
mNearest(30.f),
|
||||||
mFurthest(800.f),
|
mFurthest(800.f),
|
||||||
mIsNearest(false),
|
mIsNearest(false),
|
||||||
mIsFurthest(false)
|
mIsFurthest(false),
|
||||||
|
mVanityToggleQueued(false),
|
||||||
|
mViewModeToggleQueued(false)
|
||||||
{
|
{
|
||||||
mVanity.enabled = false;
|
mVanity.enabled = false;
|
||||||
mVanity.allowed = true;
|
mVanity.allowed = true;
|
||||||
|
@ -103,6 +105,23 @@ namespace MWRender
|
||||||
|
|
||||||
void Camera::update(float duration, bool paused)
|
void Camera::update(float duration, bool paused)
|
||||||
{
|
{
|
||||||
|
if (!mAnimation->isPlaying(MWRender::Animation::Group_UpperBody))
|
||||||
|
{
|
||||||
|
// Now process the view changes we queued earlier
|
||||||
|
if (mVanityToggleQueued)
|
||||||
|
{
|
||||||
|
toggleVanityMode(!mVanity.enabled);
|
||||||
|
mVanityToggleQueued = false;
|
||||||
|
}
|
||||||
|
if (mViewModeToggleQueued)
|
||||||
|
{
|
||||||
|
|
||||||
|
togglePreviewMode(false);
|
||||||
|
toggleViewMode();
|
||||||
|
mViewModeToggleQueued = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateListener();
|
updateListener();
|
||||||
if (paused)
|
if (paused)
|
||||||
return;
|
return;
|
||||||
|
@ -121,6 +140,14 @@ namespace MWRender
|
||||||
|
|
||||||
void Camera::toggleViewMode()
|
void Camera::toggleViewMode()
|
||||||
{
|
{
|
||||||
|
// Changing the view will stop all playing animations, so if we are playing
|
||||||
|
// anything important, queue the view change for later
|
||||||
|
if (mAnimation->isPlaying(MWRender::Animation::Group_UpperBody))
|
||||||
|
{
|
||||||
|
mViewModeToggleQueued = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mFirstPersonView = !mFirstPersonView;
|
mFirstPersonView = !mFirstPersonView;
|
||||||
processViewChange();
|
processViewChange();
|
||||||
|
|
||||||
|
@ -140,6 +167,14 @@ namespace MWRender
|
||||||
|
|
||||||
bool Camera::toggleVanityMode(bool enable)
|
bool Camera::toggleVanityMode(bool enable)
|
||||||
{
|
{
|
||||||
|
// Changing the view will stop all playing animations, so if we are playing
|
||||||
|
// anything important, queue the view change for later
|
||||||
|
if (mAnimation->isPlaying(MWRender::Animation::Group_UpperBody))
|
||||||
|
{
|
||||||
|
mVanityToggleQueued = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(!mVanity.allowed && enable)
|
if(!mVanity.allowed && enable)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -168,6 +203,9 @@ namespace MWRender
|
||||||
|
|
||||||
void Camera::togglePreviewMode(bool enable)
|
void Camera::togglePreviewMode(bool enable)
|
||||||
{
|
{
|
||||||
|
if (mAnimation->isPlaying(MWRender::Animation::Group_UpperBody))
|
||||||
|
return;
|
||||||
|
|
||||||
if(mPreviewMode == enable)
|
if(mPreviewMode == enable)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -184,7 +222,6 @@ namespace MWRender
|
||||||
}
|
}
|
||||||
|
|
||||||
mCamera->setPosition(0.f, 0.f, offset);
|
mCamera->setPosition(0.f, 0.f, offset);
|
||||||
rotateCamera(Ogre::Vector3(getPitch(), 0.f, getYaw()), false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera::setSneakOffset()
|
void Camera::setSneakOffset()
|
||||||
|
@ -319,6 +356,7 @@ namespace MWRender
|
||||||
mAnimation->setViewMode(NpcAnimation::VM_Normal);
|
mAnimation->setViewMode(NpcAnimation::VM_Normal);
|
||||||
mCameraNode->attachObject(mCamera);
|
mCameraNode->attachObject(mCamera);
|
||||||
}
|
}
|
||||||
|
rotateCamera(Ogre::Vector3(getPitch(), 0.f, getYaw()), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera::getPosition(Ogre::Vector3 &focal, Ogre::Vector3 &camera)
|
void Camera::getPosition(Ogre::Vector3 &focal, Ogre::Vector3 &camera)
|
||||||
|
|
|
@ -47,6 +47,9 @@ namespace MWRender
|
||||||
|
|
||||||
bool mDistanceAdjusted;
|
bool mDistanceAdjusted;
|
||||||
|
|
||||||
|
bool mVanityToggleQueued;
|
||||||
|
bool mViewModeToggleQueued;
|
||||||
|
|
||||||
/// Updates sound manager listener data
|
/// Updates sound manager listener data
|
||||||
void updateListener();
|
void updateListener();
|
||||||
|
|
||||||
|
@ -77,6 +80,7 @@ namespace MWRender
|
||||||
bool toggleVanityMode(bool enable);
|
bool toggleVanityMode(bool enable);
|
||||||
void allowVanityMode(bool allow);
|
void allowVanityMode(bool allow);
|
||||||
|
|
||||||
|
/// @note this may be ignored if an important animation is currently playing
|
||||||
void togglePreviewMode(bool enable);
|
void togglePreviewMode(bool enable);
|
||||||
|
|
||||||
/// \brief Lowers the camera for sneak.
|
/// \brief Lowers the camera for sneak.
|
||||||
|
|
|
@ -117,7 +117,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int v
|
||||||
mListenerDisabled(disableListener),
|
mListenerDisabled(disableListener),
|
||||||
mViewMode(viewMode),
|
mViewMode(viewMode),
|
||||||
mShowWeapons(false),
|
mShowWeapons(false),
|
||||||
mShowShield(true),
|
mShowCarriedLeft(true),
|
||||||
mFirstPersonOffset(0.f, 0.f, 0.f),
|
mFirstPersonOffset(0.f, 0.f, 0.f),
|
||||||
mAlpha(1.f)
|
mAlpha(1.f)
|
||||||
{
|
{
|
||||||
|
@ -319,7 +319,7 @@ void NpcAnimation::updateParts()
|
||||||
}
|
}
|
||||||
|
|
||||||
showWeapons(mShowWeapons);
|
showWeapons(mShowWeapons);
|
||||||
showShield(mShowShield);
|
showCarriedLeft(mShowCarriedLeft);
|
||||||
|
|
||||||
// Remember body parts so we only have to search through the store once for each race/gender/viewmode combination
|
// Remember body parts so we only have to search through the store once for each race/gender/viewmode combination
|
||||||
static std::map< std::pair<std::string,int>,std::vector<const ESM::BodyPart*> > sRaceMapping;
|
static std::map< std::pair<std::string,int>,std::vector<const ESM::BodyPart*> > sRaceMapping;
|
||||||
|
@ -654,33 +654,25 @@ void NpcAnimation::showWeapons(bool showWeapon)
|
||||||
mAlpha = 1.f;
|
mAlpha = 1.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NpcAnimation::showShield(bool show)
|
void NpcAnimation::showCarriedLeft(bool show)
|
||||||
{
|
{
|
||||||
mShowShield = show;
|
mShowCarriedLeft = show;
|
||||||
MWWorld::InventoryStore &inv = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
|
MWWorld::InventoryStore &inv = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
|
||||||
MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
|
MWWorld::ContainerStoreIterator iter = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
|
||||||
|
|
||||||
if (shield != inv.end() && shield->getTypeName() == typeid(ESM::Light).name())
|
if(show && iter != inv.end())
|
||||||
{
|
{
|
||||||
// ... Except for lights, which are still shown during spellcasting since they
|
Ogre::Vector3 glowColor = getEnchantmentColor(*iter);
|
||||||
// have their own (one-handed) casting animations
|
std::string mesh = MWWorld::Class::get(*iter).getModel(*iter);
|
||||||
show = true;
|
|
||||||
}
|
|
||||||
if(show && shield != inv.end())
|
|
||||||
{
|
|
||||||
Ogre::Vector3 glowColor = getEnchantmentColor(*shield);
|
|
||||||
std::string mesh = MWWorld::Class::get(*shield).getModel(*shield);
|
|
||||||
addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1,
|
addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1,
|
||||||
mesh, !shield->getClass().getEnchantment(*shield).empty(), &glowColor);
|
mesh, !iter->getClass().getEnchantment(*iter).empty(), &glowColor);
|
||||||
|
|
||||||
if (shield->getTypeName() == typeid(ESM::Light).name())
|
if (iter->getTypeName() == typeid(ESM::Light).name())
|
||||||
addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], shield->get<ESM::Light>()->mBase);
|
addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], iter->get<ESM::Light>()->mBase);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
removeIndividualPart(ESM::PRT_Shield);
|
removeIndividualPart(ESM::PRT_Shield);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew, bool playSound)
|
void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew, bool playSound)
|
||||||
{
|
{
|
||||||
|
@ -730,6 +722,17 @@ void NpcAnimation::setAlpha(float alpha)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NpcAnimation::preRender(Ogre::Camera *camera)
|
||||||
|
{
|
||||||
|
Animation::preRender(camera);
|
||||||
|
for (int i=0; i<ESM::PRT_Count; ++i)
|
||||||
|
{
|
||||||
|
if (mObjectParts[i].isNull())
|
||||||
|
continue;
|
||||||
|
mObjectParts[i]->rotateBillboardNodes(camera);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void NpcAnimation::applyAlpha(float alpha, Ogre::Entity *ent, NifOgre::ObjectScenePtr scene)
|
void NpcAnimation::applyAlpha(float alpha, Ogre::Entity *ent, NifOgre::ObjectScenePtr scene)
|
||||||
{
|
{
|
||||||
ent->getSubEntity(0)->setRenderQueueGroup(alpha != 1.f || ent->getSubEntity(0)->getMaterial()->isTransparent()
|
ent->getSubEntity(0)->setRenderQueueGroup(alpha != 1.f || ent->getSubEntity(0)->getMaterial()->isTransparent()
|
||||||
|
|
|
@ -53,7 +53,7 @@ private:
|
||||||
std::string mHairModel;
|
std::string mHairModel;
|
||||||
ViewMode mViewMode;
|
ViewMode mViewMode;
|
||||||
bool mShowWeapons;
|
bool mShowWeapons;
|
||||||
bool mShowShield;
|
bool mShowCarriedLeft;
|
||||||
|
|
||||||
int mVisibilityFlags;
|
int mVisibilityFlags;
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ public:
|
||||||
virtual Ogre::Vector3 runAnimation(float timepassed);
|
virtual Ogre::Vector3 runAnimation(float timepassed);
|
||||||
|
|
||||||
virtual void showWeapons(bool showWeapon);
|
virtual void showWeapons(bool showWeapon);
|
||||||
virtual void showShield(bool showShield);
|
virtual void showCarriedLeft(bool showa);
|
||||||
|
|
||||||
void setViewMode(ViewMode viewMode);
|
void setViewMode(ViewMode viewMode);
|
||||||
|
|
||||||
|
@ -116,6 +116,9 @@ public:
|
||||||
|
|
||||||
/// Make the NPC only partially visible
|
/// Make the NPC only partially visible
|
||||||
virtual void setAlpha(float alpha);
|
virtual void setAlpha(float alpha);
|
||||||
|
|
||||||
|
/// Prepare this animation for being rendered with \a camera (rotates billboard nodes)
|
||||||
|
virtual void preRender (Ogre::Camera* camera);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -245,11 +245,16 @@ void Objects::disableLights()
|
||||||
it->second->enableLights(false);
|
it->second->enableLights(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Objects::update(const float dt)
|
void Objects::update(float dt, Ogre::Camera* camera)
|
||||||
{
|
{
|
||||||
PtrAnimationMap::const_iterator it = mObjects.begin();
|
PtrAnimationMap::const_iterator it = mObjects.begin();
|
||||||
for(;it != mObjects.end();it++)
|
for(;it != mObjects.end();it++)
|
||||||
it->second->runAnimation(dt);
|
it->second->runAnimation(dt);
|
||||||
|
|
||||||
|
it = mObjects.begin();
|
||||||
|
for(;it != mObjects.end();it++)
|
||||||
|
it->second->preRender(camera);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Objects::rebuildStaticGeometry()
|
void Objects::rebuildStaticGeometry()
|
||||||
|
|
|
@ -48,7 +48,7 @@ public:
|
||||||
void enableLights();
|
void enableLights();
|
||||||
void disableLights();
|
void disableLights();
|
||||||
|
|
||||||
void update (const float dt);
|
void update (float dt, Ogre::Camera* camera);
|
||||||
///< per-frame update
|
///< per-frame update
|
||||||
|
|
||||||
Ogre::AxisAlignedBox getDimensions(MWWorld::CellStore*);
|
Ogre::AxisAlignedBox getDimensions(MWWorld::CellStore*);
|
||||||
|
|
|
@ -372,9 +372,9 @@ void RenderingManager::update (float duration, bool paused)
|
||||||
if(paused)
|
if(paused)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mActors->update (duration);
|
mActors->update (mRendering.getCamera());
|
||||||
mObjects->update (duration);
|
mPlayerAnimation->preRender(mRendering.getCamera());
|
||||||
|
mObjects->update (duration, mRendering.getCamera());
|
||||||
|
|
||||||
mSkyManager->update(duration);
|
mSkyManager->update(duration);
|
||||||
|
|
||||||
|
|
|
@ -989,8 +989,11 @@ void VideoState::deinit()
|
||||||
this->audioq.cond.notify_one();
|
this->audioq.cond.notify_one();
|
||||||
this->videoq.cond.notify_one();
|
this->videoq.cond.notify_one();
|
||||||
|
|
||||||
|
if (this->parse_thread.joinable())
|
||||||
this->parse_thread.join();
|
this->parse_thread.join();
|
||||||
|
if (this->video_thread.joinable())
|
||||||
this->video_thread.join();
|
this->video_thread.join();
|
||||||
|
if (this->refresh_thread.joinable())
|
||||||
this->refresh_thread.join();
|
this->refresh_thread.join();
|
||||||
|
|
||||||
if(this->audio_st)
|
if(this->audio_st)
|
||||||
|
|
|
@ -131,6 +131,15 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr
|
||||||
MWWorld::ContainerStoreIterator it = addImp(itemPtr);
|
MWWorld::ContainerStoreIterator it = addImp(itemPtr);
|
||||||
MWWorld::Ptr item = *it;
|
MWWorld::Ptr item = *it;
|
||||||
|
|
||||||
|
// we may have copied an item from the world, so reset a few things first
|
||||||
|
item.getRefData().setBaseNode(NULL);
|
||||||
|
item.getCellRef().mPos.rot[0] = 0;
|
||||||
|
item.getCellRef().mPos.rot[1] = 0;
|
||||||
|
item.getCellRef().mPos.rot[2] = 0;
|
||||||
|
item.getCellRef().mPos.pos[0] = 0;
|
||||||
|
item.getCellRef().mPos.pos[1] = 0;
|
||||||
|
item.getCellRef().mPos.pos[2] = 0;
|
||||||
|
|
||||||
std::string script = MWWorld::Class::get(item).getScript(item);
|
std::string script = MWWorld::Class::get(item).getScript(item);
|
||||||
if(script != "")
|
if(script != "")
|
||||||
{
|
{
|
||||||
|
|
|
@ -94,6 +94,8 @@ namespace MWWorld
|
||||||
ContainerStoreIterator addNewStack (const Ptr& ptr);
|
ContainerStoreIterator addNewStack (const Ptr& ptr);
|
||||||
///< Add the item to this container (do not try to stack it onto existing items)
|
///< Add the item to this container (do not try to stack it onto existing items)
|
||||||
|
|
||||||
|
virtual void flagAsModified();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2);
|
virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2);
|
||||||
|
@ -105,10 +107,6 @@ namespace MWWorld
|
||||||
void clear();
|
void clear();
|
||||||
///< Empty container.
|
///< Empty container.
|
||||||
|
|
||||||
virtual void flagAsModified();
|
|
||||||
///< \attention This function is internal to the world model and should not be called from
|
|
||||||
/// outside.
|
|
||||||
|
|
||||||
float getWeight() const;
|
float getWeight() const;
|
||||||
///< Return total weight of the items contained in *this.
|
///< Return total weight of the items contained in *this.
|
||||||
|
|
||||||
|
|
|
@ -180,6 +180,29 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
|
||||||
std::pair<std::vector<int>, bool> itemsSlots =
|
std::pair<std::vector<int>, bool> itemsSlots =
|
||||||
MWWorld::Class::get (*iter).getEquipmentSlots (*iter);
|
MWWorld::Class::get (*iter).getEquipmentSlots (*iter);
|
||||||
|
|
||||||
|
// Skip items that have *only* harmful permanent effects
|
||||||
|
if (!test.getClass().getEnchantment(test).empty())
|
||||||
|
{
|
||||||
|
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
const ESM::Enchantment* enchantment = store.get<ESM::Enchantment>().find(test.getClass().getEnchantment(test));
|
||||||
|
bool harmfulEffect = false;
|
||||||
|
bool usefulEffect = false;
|
||||||
|
if (enchantment->mData.mType == ESM::Enchantment::ConstantEffect)
|
||||||
|
{
|
||||||
|
for (std::vector<ESM::ENAMstruct>::const_iterator it = enchantment->mEffects.mList.begin();
|
||||||
|
it != enchantment->mEffects.mList.end(); ++it)
|
||||||
|
{
|
||||||
|
const ESM::MagicEffect* effect = store.get<ESM::MagicEffect>().find(it->mEffectID);
|
||||||
|
if (effect->mData.mFlags & ESM::MagicEffect::Harmful)
|
||||||
|
harmfulEffect = true;
|
||||||
|
else
|
||||||
|
usefulEffect = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (harmfulEffect && !usefulEffect)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (std::vector<int>::const_iterator iter2 (itemsSlots.first.begin());
|
for (std::vector<int>::const_iterator iter2 (itemsSlots.first.begin());
|
||||||
iter2!=itemsSlots.first.end(); ++iter2)
|
iter2!=itemsSlots.first.end(); ++iter2)
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#include "../mwbase/world.hpp" // FIXME
|
#include "../mwbase/world.hpp" // FIXME
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
|
||||||
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
|
|
||||||
#include <components/esm/loadgmst.hpp>
|
#include <components/esm/loadgmst.hpp>
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
|
@ -573,9 +575,17 @@ namespace MWWorld
|
||||||
if(cell->hasWater())
|
if(cell->hasWater())
|
||||||
waterlevel = cell->mWater;
|
waterlevel = cell->mWater;
|
||||||
|
|
||||||
|
float oldHeight = iter->first.getRefData().getPosition().pos[2];
|
||||||
|
|
||||||
Ogre::Vector3 newpos = MovementSolver::move(iter->first, iter->second, mTimeAccum,
|
Ogre::Vector3 newpos = MovementSolver::move(iter->first, iter->second, mTimeAccum,
|
||||||
world->isFlying(iter->first),
|
world->isFlying(iter->first),
|
||||||
waterlevel, mEngine);
|
waterlevel, mEngine);
|
||||||
|
|
||||||
|
float heightDiff = newpos.z - oldHeight;
|
||||||
|
|
||||||
|
if (heightDiff < 0)
|
||||||
|
iter->first.getClass().getCreatureStats(iter->first).addToFallHeight(-heightDiff);
|
||||||
|
|
||||||
mMovementResults.push_back(std::make_pair(iter->first, newpos));
|
mMovementResults.push_back(std::make_pair(iter->first, newpos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,6 @@ ESM::CellRef& MWWorld::Ptr::getCellRef() const
|
||||||
{
|
{
|
||||||
assert(mRef);
|
assert(mRef);
|
||||||
|
|
||||||
if (mContainerStore)
|
|
||||||
mContainerStore->flagAsModified();
|
|
||||||
|
|
||||||
return mRef->mRef;
|
return mRef->mRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,9 +32,6 @@ MWWorld::RefData& MWWorld::Ptr::getRefData() const
|
||||||
{
|
{
|
||||||
assert(mRef);
|
assert(mRef);
|
||||||
|
|
||||||
if (mContainerStore)
|
|
||||||
mContainerStore->flagAsModified();
|
|
||||||
|
|
||||||
return mRef->mData;
|
return mRef->mData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2049,15 +2049,56 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool World::startSpellCast(const Ptr &actor)
|
||||||
|
{
|
||||||
|
MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
||||||
|
|
||||||
|
std::string message;
|
||||||
|
bool fail = false;
|
||||||
|
bool isPlayer = (actor == getPlayer().getPlayer());
|
||||||
|
|
||||||
|
std::string selectedSpell = stats.getSpells().getSelectedSpell();
|
||||||
|
|
||||||
|
if (!selectedSpell.empty())
|
||||||
|
{
|
||||||
|
const ESM::Spell* spell = getStore().get<ESM::Spell>().search(selectedSpell);
|
||||||
|
|
||||||
|
// Check mana
|
||||||
|
MWMechanics::DynamicStat<float> magicka = stats.getMagicka();
|
||||||
|
if (magicka.getCurrent() < spell->mData.mCost)
|
||||||
|
{
|
||||||
|
message = "#{sMagicInsufficientSP}";
|
||||||
|
fail = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is a power, check if it was already used in the last 24h
|
||||||
|
if (!fail && spell->mData.mType == ESM::Spell::ST_Power)
|
||||||
|
{
|
||||||
|
if (stats.canUsePower(spell->mId))
|
||||||
|
stats.usePower(spell->mId);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message = "#{sPowerAlreadyUsed}";
|
||||||
|
fail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce mana
|
||||||
|
magicka.setCurrent(magicka.getCurrent() - spell->mData.mCost);
|
||||||
|
stats.setMagicka(magicka);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPlayer && fail)
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox(message);
|
||||||
|
|
||||||
|
return !fail;
|
||||||
|
}
|
||||||
|
|
||||||
void World::castSpell(const Ptr &actor)
|
void World::castSpell(const Ptr &actor)
|
||||||
{
|
{
|
||||||
MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
||||||
InventoryStore& inv = actor.getClass().getInventoryStore(actor);
|
InventoryStore& inv = actor.getClass().getInventoryStore(actor);
|
||||||
|
|
||||||
// Unset casting flag, otherwise pressing the mouse button down would continue casting every frame if using an enchantment
|
|
||||||
// (which casts instantly without an animation)
|
|
||||||
stats.setAttackingOrSpell(false);
|
|
||||||
|
|
||||||
MWWorld::Ptr target = getFacedObject();
|
MWWorld::Ptr target = getFacedObject();
|
||||||
|
|
||||||
std::string selectedSpell = stats.getSpells().getSelectedSpell();
|
std::string selectedSpell = stats.getSpells().getSelectedSpell();
|
||||||
|
|
|
@ -499,6 +499,17 @@ namespace MWWorld
|
||||||
|
|
||||||
virtual bool toggleGodMode();
|
virtual bool toggleGodMode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief startSpellCast attempt to start casting a spell. Might fail immediately if conditions are not met.
|
||||||
|
* @param actor
|
||||||
|
* @return true if the spell can be casted (i.e. the animation should start)
|
||||||
|
*/
|
||||||
|
virtual bool startSpellCast (const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Cast the actual spell, should be called mid-animation
|
||||||
|
* @param actor
|
||||||
|
*/
|
||||||
virtual void castSpell (const MWWorld::Ptr& actor);
|
virtual void castSpell (const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
|
virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
|
||||||
|
|
|
@ -26,9 +26,10 @@ ConfigurationManager::ConfigurationManager()
|
||||||
{
|
{
|
||||||
setupTokensMapping();
|
setupTokensMapping();
|
||||||
|
|
||||||
boost::filesystem::create_directories(mFixedPath.getUserPath());
|
boost::filesystem::create_directories(mFixedPath.getUserConfigPath());
|
||||||
|
boost::filesystem::create_directories(mFixedPath.getUserDataPath());
|
||||||
|
|
||||||
mLogPath = mFixedPath.getUserPath();
|
mLogPath = mFixedPath.getUserConfigPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigurationManager::~ConfigurationManager()
|
ConfigurationManager::~ConfigurationManager()
|
||||||
|
@ -39,19 +40,19 @@ void ConfigurationManager::setupTokensMapping()
|
||||||
{
|
{
|
||||||
mTokensMapping.insert(std::make_pair(mwToken, &FixedPath<>::getInstallPath));
|
mTokensMapping.insert(std::make_pair(mwToken, &FixedPath<>::getInstallPath));
|
||||||
mTokensMapping.insert(std::make_pair(localToken, &FixedPath<>::getLocalPath));
|
mTokensMapping.insert(std::make_pair(localToken, &FixedPath<>::getLocalPath));
|
||||||
mTokensMapping.insert(std::make_pair(userToken, &FixedPath<>::getUserPath));
|
mTokensMapping.insert(std::make_pair(userToken, &FixedPath<>::getUserConfigPath));
|
||||||
mTokensMapping.insert(std::make_pair(globalToken, &FixedPath<>::getGlobalDataPath));
|
mTokensMapping.insert(std::make_pair(globalToken, &FixedPath<>::getGlobalDataPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigurationManager::readConfiguration(boost::program_options::variables_map& variables,
|
void ConfigurationManager::readConfiguration(boost::program_options::variables_map& variables,
|
||||||
boost::program_options::options_description& description)
|
boost::program_options::options_description& description)
|
||||||
{
|
{
|
||||||
loadConfig(mFixedPath.getUserPath(), variables, description);
|
loadConfig(mFixedPath.getUserConfigPath(), variables, description);
|
||||||
boost::program_options::notify(variables);
|
boost::program_options::notify(variables);
|
||||||
|
|
||||||
loadConfig(mFixedPath.getLocalPath(), variables, description);
|
loadConfig(mFixedPath.getLocalPath(), variables, description);
|
||||||
boost::program_options::notify(variables);
|
boost::program_options::notify(variables);
|
||||||
loadConfig(mFixedPath.getGlobalPath(), variables, description);
|
loadConfig(mFixedPath.getGlobalConfigPath(), variables, description);
|
||||||
boost::program_options::notify(variables);
|
boost::program_options::notify(variables);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -141,12 +142,17 @@ void ConfigurationManager::loadConfig(const boost::filesystem::path& path,
|
||||||
|
|
||||||
const boost::filesystem::path& ConfigurationManager::getGlobalPath() const
|
const boost::filesystem::path& ConfigurationManager::getGlobalPath() const
|
||||||
{
|
{
|
||||||
return mFixedPath.getGlobalPath();
|
return mFixedPath.getGlobalConfigPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
const boost::filesystem::path& ConfigurationManager::getUserPath() const
|
const boost::filesystem::path& ConfigurationManager::getUserConfigPath() const
|
||||||
{
|
{
|
||||||
return mFixedPath.getUserPath();
|
return mFixedPath.getUserConfigPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
const boost::filesystem::path& ConfigurationManager::getUserDataPath() const
|
||||||
|
{
|
||||||
|
return mFixedPath.getUserDataPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
const boost::filesystem::path& ConfigurationManager::getLocalPath() const
|
const boost::filesystem::path& ConfigurationManager::getLocalPath() const
|
||||||
|
|
|
@ -36,7 +36,7 @@ struct ConfigurationManager
|
||||||
|
|
||||||
/**< Fixed paths */
|
/**< Fixed paths */
|
||||||
const boost::filesystem::path& getGlobalPath() const;
|
const boost::filesystem::path& getGlobalPath() const;
|
||||||
const boost::filesystem::path& getUserPath() const;
|
const boost::filesystem::path& getUserConfigPath() const;
|
||||||
const boost::filesystem::path& getLocalPath() const;
|
const boost::filesystem::path& getLocalPath() const;
|
||||||
|
|
||||||
const boost::filesystem::path& getGlobalDataPath() const;
|
const boost::filesystem::path& getGlobalDataPath() const;
|
||||||
|
|
|
@ -48,8 +48,9 @@ struct FixedPath
|
||||||
*/
|
*/
|
||||||
FixedPath(const std::string& application_name)
|
FixedPath(const std::string& application_name)
|
||||||
: mPath(application_name + "/")
|
: mPath(application_name + "/")
|
||||||
, mUserPath(mPath.getUserPath())
|
, mUserConfigPath(mPath.getUserConfigPath())
|
||||||
, mGlobalPath(mPath.getGlobalPath())
|
, mUserDataPath(mPath.getUserDataPath())
|
||||||
|
, mGlobalConfigPath(mPath.getGlobalConfigPath())
|
||||||
, mLocalPath(mPath.getLocalPath())
|
, mLocalPath(mPath.getLocalPath())
|
||||||
, mGlobalDataPath(mPath.getGlobalDataPath())
|
, mGlobalDataPath(mPath.getGlobalDataPath())
|
||||||
, mInstallPath(mPath.getInstallPath())
|
, mInstallPath(mPath.getInstallPath())
|
||||||
|
@ -59,28 +60,27 @@ struct FixedPath
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Return path pointing to the user local configuration directory.
|
* \brief Return path pointing to the user local configuration directory.
|
||||||
*
|
|
||||||
* \return boost::filesystem::path
|
|
||||||
*/
|
*/
|
||||||
const boost::filesystem::path& getUserPath() const
|
const boost::filesystem::path& getUserConfigPath() const
|
||||||
{
|
{
|
||||||
return mUserPath;
|
return mUserConfigPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const boost::filesystem::path& getUserDataPath() const
|
||||||
|
{
|
||||||
|
return mUserDataPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Return path pointing to the global (system) configuration directory.
|
* \brief Return path pointing to the global (system) configuration directory.
|
||||||
*
|
|
||||||
* \return boost::filesystem::path
|
|
||||||
*/
|
*/
|
||||||
const boost::filesystem::path& getGlobalPath() const
|
const boost::filesystem::path& getGlobalConfigPath() const
|
||||||
{
|
{
|
||||||
return mGlobalPath;
|
return mGlobalConfigPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Return path pointing to the directory where application was started.
|
* \brief Return path pointing to the directory where application was started.
|
||||||
*
|
|
||||||
* \return boost::filesystem::path
|
|
||||||
*/
|
*/
|
||||||
const boost::filesystem::path& getLocalPath() const
|
const boost::filesystem::path& getLocalPath() const
|
||||||
{
|
{
|
||||||
|
@ -105,8 +105,9 @@ struct FixedPath
|
||||||
private:
|
private:
|
||||||
PathType mPath;
|
PathType mPath;
|
||||||
|
|
||||||
boost::filesystem::path mUserPath; /**< User path */
|
boost::filesystem::path mUserConfigPath; /**< User path */
|
||||||
boost::filesystem::path mGlobalPath; /**< Global path */
|
boost::filesystem::path mUserDataPath;
|
||||||
|
boost::filesystem::path mGlobalConfigPath; /**< Global path */
|
||||||
boost::filesystem::path mLocalPath; /**< It is the same directory where application was run */
|
boost::filesystem::path mLocalPath; /**< It is the same directory where application was run */
|
||||||
|
|
||||||
boost::filesystem::path mGlobalDataPath; /**< Global application data path */
|
boost::filesystem::path mGlobalDataPath; /**< Global application data path */
|
||||||
|
|
|
@ -8,6 +8,39 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <boost/filesystem/fstream.hpp>
|
#include <boost/filesystem/fstream.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
boost::filesystem::path getUserHome()
|
||||||
|
{
|
||||||
|
const char* dir = getenv("HOME");
|
||||||
|
if (dir == NULL)
|
||||||
|
{
|
||||||
|
struct passwd* pwd = getpwuid(getuid());
|
||||||
|
if (pwd != NULL)
|
||||||
|
{
|
||||||
|
dir = pwd->pw_dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dir == NULL)
|
||||||
|
return boost::filesystem::path();
|
||||||
|
else
|
||||||
|
return boost::filesystem::path(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::filesystem::path getEnv(const std::string& envVariable, const boost::filesystem::path& fallback)
|
||||||
|
{
|
||||||
|
const char* result = getenv(envVariable.c_str());
|
||||||
|
if (!result)
|
||||||
|
return fallback;
|
||||||
|
boost::filesystem::path dir(result);
|
||||||
|
if (dir.empty())
|
||||||
|
return fallback;
|
||||||
|
else
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \namespace Files
|
* \namespace Files
|
||||||
*/
|
*/
|
||||||
|
@ -19,51 +52,22 @@ LinuxPath::LinuxPath(const std::string& application_name)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::filesystem::path LinuxPath::getUserPath() const
|
boost::filesystem::path LinuxPath::getUserConfigPath() const
|
||||||
{
|
{
|
||||||
boost::filesystem::path userPath(".");
|
return getEnv("XDG_CONFIG_HOME", getUserHome() / ".config") / mName;
|
||||||
|
|
||||||
const char* theDir = getenv("HOME");
|
|
||||||
if (theDir == NULL)
|
|
||||||
{
|
|
||||||
struct passwd* pwd = getpwuid(getuid());
|
|
||||||
if (pwd != NULL)
|
|
||||||
{
|
|
||||||
theDir = pwd->pw_dir;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theDir != NULL)
|
boost::filesystem::path LinuxPath::getUserDataPath() const
|
||||||
{
|
{
|
||||||
userPath = boost::filesystem::path(theDir);
|
return getEnv("XDG_DATA_HOME", getUserHome() / ".local/share") / mName;
|
||||||
}
|
|
||||||
|
|
||||||
return userPath / ".config" / mName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::filesystem::path LinuxPath::getCachePath() const
|
boost::filesystem::path LinuxPath::getCachePath() const
|
||||||
{
|
{
|
||||||
boost::filesystem::path userPath(".");
|
return getEnv("XDG_CACHE_HOME", getUserHome() / ".cache") / mName;
|
||||||
|
|
||||||
const char* theDir = getenv("HOME");
|
|
||||||
if (theDir == NULL)
|
|
||||||
{
|
|
||||||
struct passwd* pwd = getpwuid(getuid());
|
|
||||||
if (pwd != NULL)
|
|
||||||
{
|
|
||||||
theDir = pwd->pw_dir;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theDir != NULL)
|
boost::filesystem::path LinuxPath::getGlobalConfigPath() const
|
||||||
{
|
|
||||||
userPath = boost::filesystem::path(theDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
return userPath / ".cache" / mName;
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::filesystem::path LinuxPath::getGlobalPath() const
|
|
||||||
{
|
{
|
||||||
boost::filesystem::path globalPath("/etc/");
|
boost::filesystem::path globalPath("/etc/");
|
||||||
return globalPath / mName;
|
return globalPath / mName;
|
||||||
|
@ -84,17 +88,9 @@ boost::filesystem::path LinuxPath::getInstallPath() const
|
||||||
{
|
{
|
||||||
boost::filesystem::path installPath;
|
boost::filesystem::path installPath;
|
||||||
|
|
||||||
char *homePath = getenv("HOME");
|
boost::filesystem::path homePath = getUserHome();
|
||||||
if (homePath == NULL)
|
|
||||||
{
|
|
||||||
struct passwd* pwd = getpwuid(getuid());
|
|
||||||
if (pwd != NULL)
|
|
||||||
{
|
|
||||||
homePath = pwd->pw_dir;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (homePath != NULL)
|
if (!homePath.empty())
|
||||||
{
|
{
|
||||||
boost::filesystem::path wineDefaultRegistry(homePath);
|
boost::filesystem::path wineDefaultRegistry(homePath);
|
||||||
wineDefaultRegistry /= ".wine/system.reg";
|
wineDefaultRegistry /= ".wine/system.reg";
|
||||||
|
|
|
@ -20,44 +20,34 @@ struct LinuxPath
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Return path to the user directory.
|
* \brief Return path to the user directory.
|
||||||
*
|
|
||||||
* \return boost::filesystem::path
|
|
||||||
*/
|
*/
|
||||||
boost::filesystem::path getUserPath() const;
|
boost::filesystem::path getUserConfigPath() const;
|
||||||
|
|
||||||
|
boost::filesystem::path getUserDataPath() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Return path to the global (system) directory where game files could be placed.
|
* \brief Return path to the global (system) directory where config files can be placed.
|
||||||
*
|
|
||||||
* \return boost::filesystem::path
|
|
||||||
*/
|
*/
|
||||||
boost::filesystem::path getGlobalPath() const;
|
boost::filesystem::path getGlobalConfigPath() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Return path to the runtime configuration directory which is the
|
* \brief Return path to the runtime configuration directory which is the
|
||||||
* place where an application was started.
|
* place where an application was started.
|
||||||
*
|
|
||||||
* \return boost::filesystem::path
|
|
||||||
*/
|
*/
|
||||||
boost::filesystem::path getLocalPath() const;
|
boost::filesystem::path getLocalPath() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief
|
* \brief Return path to the global (system) directory where game files can be placed.
|
||||||
*
|
|
||||||
* \return boost::filesystem::path
|
|
||||||
*/
|
*/
|
||||||
boost::filesystem::path getGlobalDataPath() const;
|
boost::filesystem::path getGlobalDataPath() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief
|
* \brief
|
||||||
*
|
|
||||||
* \return boost::filesystem::path
|
|
||||||
*/
|
*/
|
||||||
boost::filesystem::path getCachePath() const;
|
boost::filesystem::path getCachePath() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Gets the path of the installed Morrowind version if there is one.
|
* \brief Gets the path of the installed Morrowind version if there is one.
|
||||||
*
|
|
||||||
* \return boost::filesystem::path
|
|
||||||
*/
|
*/
|
||||||
boost::filesystem::path getInstallPath() const;
|
boost::filesystem::path getInstallPath() const;
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,26 @@
|
||||||
* FIXME: Someone with MacOS system should check this and correct if necessary
|
* FIXME: Someone with MacOS system should check this and correct if necessary
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
namespace
|
||||||
* \namespace Files
|
{
|
||||||
*/
|
boost::filesystem::path getUserHome()
|
||||||
|
{
|
||||||
|
const char* dir = getenv("HOME");
|
||||||
|
if (dir == NULL)
|
||||||
|
{
|
||||||
|
struct passwd* pwd = getpwuid(getuid());
|
||||||
|
if (pwd != NULL)
|
||||||
|
{
|
||||||
|
dir = pwd->pw_dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dir == NULL)
|
||||||
|
return boost::filesystem::path();
|
||||||
|
else
|
||||||
|
return boost::filesystem::path(dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace Files
|
namespace Files
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -22,28 +39,24 @@ MacOsPath::MacOsPath(const std::string& application_name)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::filesystem::path MacOsPath::getUserPath() const
|
boost::filesystem::path MacOsPath::getUserConfigPath() const
|
||||||
{
|
{
|
||||||
boost::filesystem::path userPath(".");
|
boost::filesystem::path userPath (getUserHome());
|
||||||
|
userPath /= "Library/Preferences/";
|
||||||
const char* theDir = getenv("HOME");
|
|
||||||
if (theDir == NULL)
|
|
||||||
{
|
|
||||||
struct passwd* pwd = getpwuid(getuid());
|
|
||||||
if (pwd != NULL)
|
|
||||||
{
|
|
||||||
theDir = pwd->pw_dir;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (theDir != NULL)
|
|
||||||
{
|
|
||||||
userPath = boost::filesystem::path(theDir) / "Library/Preferences/";
|
|
||||||
}
|
|
||||||
|
|
||||||
return userPath / mName;
|
return userPath / mName;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::filesystem::path MacOsPath::getGlobalPath() const
|
boost::filesystem::path MacOsPath::getUserDataPath() const
|
||||||
|
{
|
||||||
|
// TODO: probably wrong?
|
||||||
|
boost::filesystem::path userPath (getUserHome());
|
||||||
|
userPath /= "Library/Preferences/";
|
||||||
|
|
||||||
|
return userPath / mName;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::filesystem::path MacOsPath::getGlobalConfigPath() const
|
||||||
{
|
{
|
||||||
boost::filesystem::path globalPath("/Library/Preferences/");
|
boost::filesystem::path globalPath("/Library/Preferences/");
|
||||||
return globalPath / mName;
|
return globalPath / mName;
|
||||||
|
@ -51,23 +64,9 @@ boost::filesystem::path MacOsPath::getGlobalPath() const
|
||||||
|
|
||||||
boost::filesystem::path MacOsPath::getCachePath() const
|
boost::filesystem::path MacOsPath::getCachePath() const
|
||||||
{
|
{
|
||||||
boost::filesystem::path userPath(".");
|
boost::filesystem::path userPath (getUserHome());
|
||||||
|
userPath /= "Library/Caches";
|
||||||
const char* theDir = getenv("HOME");
|
return userPath / mName;
|
||||||
if (theDir == NULL)
|
|
||||||
{
|
|
||||||
struct passwd* pwd = getpwuid(getuid());
|
|
||||||
if (pwd != NULL)
|
|
||||||
{
|
|
||||||
theDir = pwd->pw_dir;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (theDir != NULL)
|
|
||||||
{
|
|
||||||
userPath = boost::filesystem::path(theDir) / "Library/Caches" / mName;
|
|
||||||
}
|
|
||||||
|
|
||||||
return userPath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::filesystem::path MacOsPath::getLocalPath() const
|
boost::filesystem::path MacOsPath::getLocalPath() const
|
||||||
|
@ -85,17 +84,9 @@ boost::filesystem::path MacOsPath::getInstallPath() const
|
||||||
{
|
{
|
||||||
boost::filesystem::path installPath;
|
boost::filesystem::path installPath;
|
||||||
|
|
||||||
char *homePath = getenv("HOME");
|
boost::filesystem::path homePath = getUserHome();
|
||||||
if (homePath == NULL)
|
|
||||||
{
|
|
||||||
struct passwd* pwd = getpwuid(getuid());
|
|
||||||
if (pwd != NULL)
|
|
||||||
{
|
|
||||||
homePath = pwd->pw_dir;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (homePath != NULL)
|
if (!homePath.empty())
|
||||||
{
|
{
|
||||||
boost::filesystem::path wineDefaultRegistry(homePath);
|
boost::filesystem::path wineDefaultRegistry(homePath);
|
||||||
wineDefaultRegistry /= ".wine/system.reg";
|
wineDefaultRegistry /= ".wine/system.reg";
|
||||||
|
|
|
@ -23,14 +23,16 @@ struct MacOsPath
|
||||||
*
|
*
|
||||||
* \return boost::filesystem::path
|
* \return boost::filesystem::path
|
||||||
*/
|
*/
|
||||||
boost::filesystem::path getUserPath() const;
|
boost::filesystem::path getUserConfigPath() const;
|
||||||
|
|
||||||
|
boost::filesystem::path getUserDataPath() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Return path to the global (system) directory.
|
* \brief Return path to the global (system) directory.
|
||||||
*
|
*
|
||||||
* \return boost::filesystem::path
|
* \return boost::filesystem::path
|
||||||
*/
|
*/
|
||||||
boost::filesystem::path getGlobalPath() const;
|
boost::filesystem::path getGlobalConfigPath() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Return path to the runtime directory which is the
|
* \brief Return path to the runtime directory which is the
|
||||||
|
|
|
@ -25,7 +25,7 @@ WindowsPath::WindowsPath(const std::string& application_name)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::filesystem::path WindowsPath::getUserPath() const
|
boost::filesystem::path WindowsPath::getUserConfigPath() const
|
||||||
{
|
{
|
||||||
boost::filesystem::path userPath(".");
|
boost::filesystem::path userPath(".");
|
||||||
|
|
||||||
|
@ -41,7 +41,13 @@ boost::filesystem::path WindowsPath::getUserPath() const
|
||||||
return userPath / mName;
|
return userPath / mName;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::filesystem::path WindowsPath::getGlobalPath() const
|
boost::filesystem::path WindowsPath::getUserDataPath() const
|
||||||
|
{
|
||||||
|
// Have some chaos, windows people!
|
||||||
|
return getUserConfigPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::filesystem::path WindowsPath::getGlobalConfigPath() const
|
||||||
{
|
{
|
||||||
boost::filesystem::path globalPath(".");
|
boost::filesystem::path globalPath(".");
|
||||||
|
|
||||||
|
|
|
@ -29,14 +29,16 @@ struct WindowsPath
|
||||||
*
|
*
|
||||||
* \return boost::filesystem::path
|
* \return boost::filesystem::path
|
||||||
*/
|
*/
|
||||||
boost::filesystem::path getUserPath() const;
|
boost::filesystem::path getUserConfigPath() const;
|
||||||
|
|
||||||
|
boost::filesystem::path getUserDataPath() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Returns "X:\Program Files\"
|
* \brief Returns "X:\Program Files\"
|
||||||
*
|
*
|
||||||
* \return boost::filesystem::path
|
* \return boost::filesystem::path
|
||||||
*/
|
*/
|
||||||
boost::filesystem::path getGlobalPath() const;
|
boost::filesystem::path getGlobalConfigPath() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Return local path which is a location where
|
* \brief Return local path which is a location where
|
||||||
|
|
|
@ -210,7 +210,7 @@ static const RecordFactoryEntry recordFactories [] = {
|
||||||
{ "AvoidNode", &construct <NiNode >, RC_AvoidNode },
|
{ "AvoidNode", &construct <NiNode >, RC_AvoidNode },
|
||||||
{ "NiBSParticleNode", &construct <NiNode >, RC_NiBSParticleNode },
|
{ "NiBSParticleNode", &construct <NiNode >, RC_NiBSParticleNode },
|
||||||
{ "NiBSAnimationNode", &construct <NiNode >, RC_NiBSAnimationNode },
|
{ "NiBSAnimationNode", &construct <NiNode >, RC_NiBSAnimationNode },
|
||||||
{ "NiBillboardNode", &construct <NiNode >, RC_NiNode },
|
{ "NiBillboardNode", &construct <NiNode >, RC_NiBillboardNode },
|
||||||
{ "NiTriShape", &construct <NiTriShape >, RC_NiTriShape },
|
{ "NiTriShape", &construct <NiTriShape >, RC_NiTriShape },
|
||||||
{ "NiRotatingParticles", &construct <NiRotatingParticles >, RC_NiRotatingParticles },
|
{ "NiRotatingParticles", &construct <NiRotatingParticles >, RC_NiRotatingParticles },
|
||||||
{ "NiAutoNormalParticles", &construct <NiAutoNormalParticles >, RC_NiAutoNormalParticles },
|
{ "NiAutoNormalParticles", &construct <NiAutoNormalParticles >, RC_NiAutoNormalParticles },
|
||||||
|
|
|
@ -36,6 +36,7 @@ enum RecordType
|
||||||
{
|
{
|
||||||
RC_MISSING = 0,
|
RC_MISSING = 0,
|
||||||
RC_NiNode,
|
RC_NiNode,
|
||||||
|
RC_NiBillboardNode,
|
||||||
RC_AvoidNode,
|
RC_AvoidNode,
|
||||||
RC_NiTriShape,
|
RC_NiTriShape,
|
||||||
RC_NiRotatingParticles,
|
RC_NiRotatingParticles,
|
||||||
|
|
|
@ -324,6 +324,12 @@ Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata,
|
||||||
instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture]));
|
instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture]));
|
||||||
instance->setProperty("detailMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DetailTexture]));
|
instance->setProperty("detailMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DetailTexture]));
|
||||||
instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture]));
|
instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture]));
|
||||||
|
instance->setProperty("darkMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DarkTexture]));
|
||||||
|
if (!texName[Nif::NiTexturingProperty::BaseTexture].empty())
|
||||||
|
{
|
||||||
|
instance->setProperty("use_diffuse_map", sh::makeProperty(new sh::BooleanValue(true)));
|
||||||
|
instance->setProperty("diffuseMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::BaseTexture].uvSet)));
|
||||||
|
}
|
||||||
if (!texName[Nif::NiTexturingProperty::GlowTexture].empty())
|
if (!texName[Nif::NiTexturingProperty::GlowTexture].empty())
|
||||||
{
|
{
|
||||||
instance->setProperty("use_emissive_map", sh::makeProperty(new sh::BooleanValue(true)));
|
instance->setProperty("use_emissive_map", sh::makeProperty(new sh::BooleanValue(true)));
|
||||||
|
@ -334,6 +340,11 @@ Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata,
|
||||||
instance->setProperty("use_detail_map", sh::makeProperty(new sh::BooleanValue(true)));
|
instance->setProperty("use_detail_map", sh::makeProperty(new sh::BooleanValue(true)));
|
||||||
instance->setProperty("detailMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::DetailTexture].uvSet)));
|
instance->setProperty("detailMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::DetailTexture].uvSet)));
|
||||||
}
|
}
|
||||||
|
if (!texName[Nif::NiTexturingProperty::DarkTexture].empty())
|
||||||
|
{
|
||||||
|
instance->setProperty("use_dark_map", sh::makeProperty(new sh::BooleanValue(true)));
|
||||||
|
instance->setProperty("darkMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::DarkTexture].uvSet)));
|
||||||
|
}
|
||||||
|
|
||||||
bool useParallax = !texName[Nif::NiTexturingProperty::BumpTexture].empty()
|
bool useParallax = !texName[Nif::NiTexturingProperty::BumpTexture].empty()
|
||||||
&& texName[Nif::NiTexturingProperty::BumpTexture].find("_nh.") != std::string::npos;
|
&& texName[Nif::NiTexturingProperty::BumpTexture].find("_nh.") != std::string::npos;
|
||||||
|
@ -343,17 +354,20 @@ Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata,
|
||||||
{
|
{
|
||||||
if(i == Nif::NiTexturingProperty::BaseTexture ||
|
if(i == Nif::NiTexturingProperty::BaseTexture ||
|
||||||
i == Nif::NiTexturingProperty::DetailTexture ||
|
i == Nif::NiTexturingProperty::DetailTexture ||
|
||||||
|
i == Nif::NiTexturingProperty::DarkTexture ||
|
||||||
i == Nif::NiTexturingProperty::BumpTexture ||
|
i == Nif::NiTexturingProperty::BumpTexture ||
|
||||||
i == Nif::NiTexturingProperty::GlowTexture)
|
i == Nif::NiTexturingProperty::GlowTexture)
|
||||||
continue;
|
continue;
|
||||||
if(!texName[i].empty())
|
if(!texName[i].empty())
|
||||||
warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i));
|
warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i) + " in " + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vertexColour)
|
if (vertexColour)
|
||||||
instance->setProperty("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true)));
|
instance->setProperty("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true)));
|
||||||
|
|
||||||
// Add transparency if NiAlphaProperty was present
|
// Override alpha flags based on our override list (transparency-overrides.cfg)
|
||||||
|
if (!texName[0].empty())
|
||||||
|
{
|
||||||
NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName[0]);
|
NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName[0]);
|
||||||
if (result.first)
|
if (result.first)
|
||||||
{
|
{
|
||||||
|
@ -361,7 +375,9 @@ Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata,
|
||||||
alphaTest = result.second;
|
alphaTest = result.second;
|
||||||
depthFlags = (1<<0) | (1<<1); // depth_write on, depth_check on
|
depthFlags = (1<<0) | (1<<1); // depth_write on, depth_check on
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add transparency if NiAlphaProperty was present
|
||||||
if((alphaFlags&1))
|
if((alphaFlags&1))
|
||||||
{
|
{
|
||||||
std::string blend_mode;
|
std::string blend_mode;
|
||||||
|
@ -390,7 +406,6 @@ Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata,
|
||||||
instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue(((depthFlags>>1)&1) ? "on" : "off")));
|
instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue(((depthFlags>>1)&1) ? "on" : "off")));
|
||||||
// depth_func???
|
// depth_func???
|
||||||
|
|
||||||
sh::Factory::getInstance()._ensureMaterial(name, "Default");
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,21 +116,6 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape
|
||||||
Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC;
|
Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC;
|
||||||
bool vertShadowBuffer = false;
|
bool vertShadowBuffer = false;
|
||||||
|
|
||||||
bool geomMorpherController = false;
|
|
||||||
if(!shape->controller.empty())
|
|
||||||
{
|
|
||||||
Nif::ControllerPtr ctrl = shape->controller;
|
|
||||||
do {
|
|
||||||
if(ctrl->recType == Nif::RC_NiGeomMorpherController)
|
|
||||||
{
|
|
||||||
vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY;
|
|
||||||
vertShadowBuffer = true;
|
|
||||||
geomMorpherController = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while(!(ctrl=ctrl->next).empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(skin != NULL)
|
if(skin != NULL)
|
||||||
{
|
{
|
||||||
vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY;
|
vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY;
|
||||||
|
@ -350,10 +335,39 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape
|
||||||
mesh->buildTangentVectors(Ogre::VES_TANGENT, src,dest);
|
mesh->buildTangentVectors(Ogre::VES_TANGENT, src,dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a dummy vertex animation track if there's a geom morpher controller
|
|
||||||
// This is required to make Ogre create the buffers we will use for software vertex animation
|
if(!shape->controller.empty())
|
||||||
if (srcVerts.size() && geomMorpherController)
|
{
|
||||||
mesh->createAnimation("dummy", 0)->createVertexTrack(1, sub->vertexData, Ogre::VAT_MORPH);
|
Nif::ControllerPtr ctrl = shape->controller;
|
||||||
|
do {
|
||||||
|
// Load GeomMorpherController into an Ogre::Pose and Animation
|
||||||
|
if(ctrl->recType == Nif::RC_NiGeomMorpherController)
|
||||||
|
{
|
||||||
|
const Nif::NiGeomMorpherController *geom =
|
||||||
|
static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr());
|
||||||
|
|
||||||
|
const std::vector<Nif::NiMorphData::MorphData>& morphs = geom->data.getPtr()->mMorphs;
|
||||||
|
// Note we are not interested in morph 0, which just contains the original vertices
|
||||||
|
for (unsigned int i = 1; i < morphs.size(); ++i)
|
||||||
|
{
|
||||||
|
Ogre::Pose* pose = mesh->createPose(i);
|
||||||
|
const Nif::NiMorphData::MorphData& data = morphs[i];
|
||||||
|
for (unsigned int v = 0; v < data.mVertices.size(); ++v)
|
||||||
|
pose->addVertex(v, data.mVertices[v]);
|
||||||
|
|
||||||
|
Ogre::String animationID = Ogre::StringConverter::toString(ctrl->recIndex)
|
||||||
|
+ "_" + Ogre::StringConverter::toString(i);
|
||||||
|
Ogre::VertexAnimationTrack* track =
|
||||||
|
mesh->createAnimation(animationID, 0)
|
||||||
|
->createVertexTrack(1, Ogre::VAT_POSE);
|
||||||
|
Ogre::VertexPoseKeyFrame* keyframe = track->createVertexPoseKeyFrame(0);
|
||||||
|
keyframe->addPoseReference(i-1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(!(ctrl=ctrl->next).empty());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,17 @@ ObjectScene::~ObjectScene()
|
||||||
mSkelBase = NULL;
|
mSkelBase = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ObjectScene::rotateBillboardNodes(Ogre::Camera *camera)
|
||||||
|
{
|
||||||
|
for (std::vector<Ogre::Node*>::iterator it = mBillboardNodes.begin(); it != mBillboardNodes.end(); ++it)
|
||||||
|
{
|
||||||
|
assert(mSkelBase);
|
||||||
|
Ogre::Node* node = *it;
|
||||||
|
node->_setDerivedOrientation(mSkelBase->getParentNode()->_getDerivedOrientation().Inverse() *
|
||||||
|
camera->getRealOrientation());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Animates a texture
|
// Animates a texture
|
||||||
class FlipController
|
class FlipController
|
||||||
{
|
{
|
||||||
|
@ -167,6 +178,7 @@ public:
|
||||||
if ((texture->getName() == "diffuseMap" && mTexSlot == Nif::NiTexturingProperty::BaseTexture)
|
if ((texture->getName() == "diffuseMap" && mTexSlot == Nif::NiTexturingProperty::BaseTexture)
|
||||||
|| (texture->getName() == "normalMap" && mTexSlot == Nif::NiTexturingProperty::BumpTexture)
|
|| (texture->getName() == "normalMap" && mTexSlot == Nif::NiTexturingProperty::BumpTexture)
|
||||||
|| (texture->getName() == "detailMap" && mTexSlot == Nif::NiTexturingProperty::DetailTexture)
|
|| (texture->getName() == "detailMap" && mTexSlot == Nif::NiTexturingProperty::DetailTexture)
|
||||||
|
|| (texture->getName() == "darkMap" && mTexSlot == Nif::NiTexturingProperty::DarkTexture)
|
||||||
|| (texture->getName() == "emissiveMap" && mTexSlot == Nif::NiTexturingProperty::GlowTexture))
|
|| (texture->getName() == "emissiveMap" && mTexSlot == Nif::NiTexturingProperty::GlowTexture))
|
||||||
texture->setTextureName(mTextures[curTexture]);
|
texture->setTextureName(mTextures[curTexture]);
|
||||||
}
|
}
|
||||||
|
@ -295,9 +307,6 @@ public:
|
||||||
return mData.back().isSet;
|
return mData.back().isSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: We are not getting all objects here. Skinned meshes get
|
|
||||||
// attached to the object's root node, and won't be connected via a
|
|
||||||
// TagPoint.
|
|
||||||
static void setVisible(Ogre::Node *node, int vis)
|
static void setVisible(Ogre::Node *node, int vis)
|
||||||
{
|
{
|
||||||
Ogre::Node::ChildNodeIterator iter = node->getChildIterator();
|
Ogre::Node::ChildNodeIterator iter = node->getChildIterator();
|
||||||
|
@ -306,6 +315,12 @@ public:
|
||||||
node = iter.getNext();
|
node = iter.getNext();
|
||||||
setVisible(node, vis);
|
setVisible(node, vis);
|
||||||
|
|
||||||
|
// Skinned meshes and particle systems are attached to the scene node, not the bone.
|
||||||
|
// We use the Node's user data to connect it with the mesh / particle system.
|
||||||
|
Ogre::Any customData = node->getUserObjectBindings().getUserAny();
|
||||||
|
if (!customData.isEmpty())
|
||||||
|
Ogre::any_cast<Ogre::MovableObject*>(customData)->setVisible(vis);
|
||||||
|
|
||||||
Ogre::TagPoint *tag = dynamic_cast<Ogre::TagPoint*>(node);
|
Ogre::TagPoint *tag = dynamic_cast<Ogre::TagPoint*>(node);
|
||||||
if(tag != NULL)
|
if(tag != NULL)
|
||||||
{
|
{
|
||||||
|
@ -519,18 +534,18 @@ public:
|
||||||
class Value : public Ogre::ControllerValue<Ogre::Real>, public ValueInterpolator
|
class Value : public Ogre::ControllerValue<Ogre::Real>, public ValueInterpolator
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Ogre::SubEntity *mSubEntity;
|
Ogre::Entity *mEntity;
|
||||||
std::vector<Nif::NiMorphData::MorphData> mMorphs;
|
std::vector<Nif::NiMorphData::MorphData> mMorphs;
|
||||||
std::vector<float> mValues;
|
size_t mControllerIndex;
|
||||||
|
|
||||||
std::vector<Ogre::Vector3> mVertices;
|
std::vector<Ogre::Vector3> mVertices;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Value(Ogre::SubEntity *subent, const Nif::NiMorphData *data)
|
Value(Ogre::Entity *ent, const Nif::NiMorphData *data, size_t controllerIndex)
|
||||||
: mSubEntity(subent)
|
: mEntity(ent)
|
||||||
, mMorphs(data->mMorphs)
|
, mMorphs(data->mMorphs)
|
||||||
|
, mControllerIndex(controllerIndex)
|
||||||
{
|
{
|
||||||
mValues.resize(mMorphs.size()-1, 0.f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Ogre::Real getValue() const
|
virtual Ogre::Real getValue() const
|
||||||
|
@ -543,21 +558,7 @@ public:
|
||||||
{
|
{
|
||||||
if (mMorphs.size() <= 1)
|
if (mMorphs.size() <= 1)
|
||||||
return;
|
return;
|
||||||
|
int i = 1;
|
||||||
#if OGRE_DOUBLE_PRECISION
|
|
||||||
#error "This code needs to be rewritten for double precision mode"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Ogre::VertexData* data = mSubEntity->_getSoftwareVertexAnimVertexData();
|
|
||||||
|
|
||||||
const Ogre::VertexElement* posElem =
|
|
||||||
data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
|
|
||||||
|
|
||||||
Ogre::HardwareVertexBufferSharedPtr vbuf =
|
|
||||||
data->vertexBufferBinding->getBuffer(posElem->getSource());
|
|
||||||
|
|
||||||
bool needToUpdate = false;
|
|
||||||
int i=0;
|
|
||||||
for (std::vector<Nif::NiMorphData::MorphData>::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i)
|
for (std::vector<Nif::NiMorphData::MorphData>::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i)
|
||||||
{
|
{
|
||||||
float val = 0;
|
float val = 0;
|
||||||
|
@ -565,37 +566,13 @@ public:
|
||||||
val = interpKey(it->mData.mKeys, time);
|
val = interpKey(it->mData.mKeys, time);
|
||||||
val = std::max(0.f, std::min(1.f, val));
|
val = std::max(0.f, std::min(1.f, val));
|
||||||
|
|
||||||
if (val != mValues[i])
|
Ogre::String animationID = Ogre::StringConverter::toString(mControllerIndex)
|
||||||
needToUpdate = true;
|
+ "_" + Ogre::StringConverter::toString(i);
|
||||||
mValues[i] = val;
|
|
||||||
|
Ogre::AnimationState* state = mEntity->getAnimationState(animationID);
|
||||||
|
state->setEnabled(val > 0);
|
||||||
|
state->setWeight(val);
|
||||||
}
|
}
|
||||||
if (!needToUpdate)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// The first morph key always contains the original positions
|
|
||||||
mVertices = mMorphs[0].mVertices;
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
for (std::vector<Nif::NiMorphData::MorphData>::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i)
|
|
||||||
{
|
|
||||||
float val = mValues[i];
|
|
||||||
|
|
||||||
if (it->mVertices.size() != mMorphs[0].mVertices.size())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (val != 0)
|
|
||||||
{
|
|
||||||
for (unsigned int v=0; v<mVertices.size(); ++v)
|
|
||||||
mVertices[v] += it->mVertices[v] * val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mVertices.size() * sizeof(float)*3 != vbuf->getSizeInBytes())
|
|
||||||
return;
|
|
||||||
|
|
||||||
vbuf->writeData(0, vbuf->getSizeInBytes(), &mVertices[0]);
|
|
||||||
|
|
||||||
mSubEntity->_markBuffersUsedForAnimation();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -614,13 +591,6 @@ class NIFObjectLoader
|
||||||
std::cerr << "NIFObjectLoader: Warn: " << msg << std::endl;
|
std::cerr << "NIFObjectLoader: Warn: " << msg << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fail(const std::string &msg)
|
|
||||||
{
|
|
||||||
std::cerr << "NIFObjectLoader: Fail: "<< msg << std::endl;
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void createEntity(const std::string &name, const std::string &group,
|
static void createEntity(const std::string &name, const std::string &group,
|
||||||
Ogre::SceneManager *sceneMgr, ObjectScenePtr scene,
|
Ogre::SceneManager *sceneMgr, ObjectScenePtr scene,
|
||||||
const Nif::Node *node, int flags, int animflags)
|
const Nif::Node *node, int flags, int animflags)
|
||||||
|
@ -648,6 +618,7 @@ class NIFObjectLoader
|
||||||
{
|
{
|
||||||
int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, shape->recIndex);
|
int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, shape->recIndex);
|
||||||
Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid);
|
Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid);
|
||||||
|
trgtbone->getUserObjectBindings().setUserAny(Ogre::Any(static_cast<Ogre::MovableObject*>(entity)));
|
||||||
scene->mSkelBase->attachObjectToBone(trgtbone->getName(), entity);
|
scene->mSkelBase->attachObjectToBone(trgtbone->getName(), entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -677,7 +648,8 @@ class NIFObjectLoader
|
||||||
Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ?
|
Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ?
|
||||||
Ogre::ControllerManager::getSingleton().getFrameTimeSource() :
|
Ogre::ControllerManager::getSingleton().getFrameTimeSource() :
|
||||||
Ogre::ControllerValueRealPtr());
|
Ogre::ControllerValueRealPtr());
|
||||||
Ogre::ControllerValueRealPtr dstval(OGRE_NEW GeomMorpherController::Value(entity->getSubEntity(0), geom->data.getPtr()));
|
Ogre::ControllerValueRealPtr dstval(OGRE_NEW GeomMorpherController::Value(
|
||||||
|
entity, geom->data.getPtr(), geom->recIndex));
|
||||||
|
|
||||||
GeomMorpherController::Function* function = OGRE_NEW GeomMorpherController::Function(geom, (animflags&Nif::NiNode::AnimFlag_AutoPlay));
|
GeomMorpherController::Function* function = OGRE_NEW GeomMorpherController::Function(geom, (animflags&Nif::NiNode::AnimFlag_AutoPlay));
|
||||||
scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength);
|
scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength);
|
||||||
|
@ -773,8 +745,6 @@ class NIFObjectLoader
|
||||||
emitter->setParameter("vertical_angle", Ogre::StringConverter::toString(Ogre::Radian(partctrl->verticalAngle).valueDegrees()));
|
emitter->setParameter("vertical_angle", Ogre::StringConverter::toString(Ogre::Radian(partctrl->verticalAngle).valueDegrees()));
|
||||||
emitter->setParameter("horizontal_direction", Ogre::StringConverter::toString(Ogre::Radian(partctrl->horizontalDir).valueDegrees()));
|
emitter->setParameter("horizontal_direction", Ogre::StringConverter::toString(Ogre::Radian(partctrl->horizontalDir).valueDegrees()));
|
||||||
emitter->setParameter("horizontal_angle", Ogre::StringConverter::toString(Ogre::Radian(partctrl->horizontalAngle).valueDegrees()));
|
emitter->setParameter("horizontal_angle", Ogre::StringConverter::toString(Ogre::Radian(partctrl->horizontalAngle).valueDegrees()));
|
||||||
emitter->setParameter("skelbase", skelBaseName);
|
|
||||||
emitter->setParameter("bone", bone->getName());
|
|
||||||
|
|
||||||
Nif::ExtraPtr e = partctrl->extra;
|
Nif::ExtraPtr e = partctrl->extra;
|
||||||
while(!e.empty())
|
while(!e.empty())
|
||||||
|
@ -867,7 +837,9 @@ class NIFObjectLoader
|
||||||
partsys->setParticleQuota(particledata->numParticles);
|
partsys->setParticleQuota(particledata->numParticles);
|
||||||
partsys->setKeepParticlesInLocalSpace(partflags & (Nif::NiNode::ParticleFlag_LocalSpace));
|
partsys->setKeepParticlesInLocalSpace(partflags & (Nif::NiNode::ParticleFlag_LocalSpace));
|
||||||
|
|
||||||
sceneNode->attachObject(partsys);
|
int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partnode->recIndex);
|
||||||
|
Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid);
|
||||||
|
scene->mSkelBase->attachObjectToBone(trgtbone->getName(), partsys);
|
||||||
|
|
||||||
Nif::ControllerPtr ctrl = partnode->controller;
|
Nif::ControllerPtr ctrl = partnode->controller;
|
||||||
while(!ctrl.empty())
|
while(!ctrl.empty())
|
||||||
|
@ -880,6 +852,9 @@ class NIFObjectLoader
|
||||||
{
|
{
|
||||||
int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex);
|
int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex);
|
||||||
Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid);
|
Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid);
|
||||||
|
// Set the emitter bone as user data on the particle system
|
||||||
|
// so the emitters/affectors can access it easily.
|
||||||
|
partsys->getUserObjectBindings().setUserAny(Ogre::Any(trgtbone));
|
||||||
createParticleEmitterAffectors(partsys, partctrl, trgtbone, scene->mSkelBase->getName());
|
createParticleEmitterAffectors(partsys, partctrl, trgtbone, scene->mSkelBase->getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1007,6 +982,17 @@ class NIFObjectLoader
|
||||||
else
|
else
|
||||||
flags |= node->flags;
|
flags |= node->flags;
|
||||||
|
|
||||||
|
if (node->recType == Nif::RC_NiBillboardNode)
|
||||||
|
{
|
||||||
|
// TODO: figure out what the flags mean.
|
||||||
|
// NifSkope has names for them, but doesn't implement them.
|
||||||
|
// Change mBillboardNodes to map <Bone, billboard type>
|
||||||
|
int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex);
|
||||||
|
Ogre::Bone* bone = scene->mSkelBase->getSkeleton()->getBone(trgtid);
|
||||||
|
bone->setManuallyControlled(true);
|
||||||
|
scene->mBillboardNodes.push_back(bone);
|
||||||
|
}
|
||||||
|
|
||||||
Nif::ExtraPtr e = node->extra;
|
Nif::ExtraPtr e = node->extra;
|
||||||
while(!e.empty())
|
while(!e.empty())
|
||||||
{
|
{
|
||||||
|
@ -1243,17 +1229,6 @@ ObjectScenePtr Loader::createObjects(Ogre::Entity *parent, const std::string &bo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(size_t i = 0;i < scene->mParticles.size();i++)
|
|
||||||
{
|
|
||||||
Ogre::ParticleSystem *partsys = scene->mParticles[i];
|
|
||||||
if(partsys->isAttached())
|
|
||||||
partsys->detachFromParent();
|
|
||||||
|
|
||||||
Ogre::TagPoint *tag = scene->mSkelBase->attachObjectToBone(
|
|
||||||
scene->mSkelBase->getSkeleton()->getRootBone()->getName(), partsys);
|
|
||||||
tag->setScale(scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
return scene;
|
return scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,8 @@ class MaterialControllerManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
~MaterialControllerManager();
|
~MaterialControllerManager();
|
||||||
|
|
||||||
|
/// @attention if \a movable is an Entity, it needs to have *one* SubEntity
|
||||||
Ogre::MaterialPtr getWritableMaterial (Ogre::MovableObject* movable);
|
Ogre::MaterialPtr getWritableMaterial (Ogre::MovableObject* movable);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -59,6 +61,9 @@ struct ObjectScene {
|
||||||
std::vector<Ogre::ParticleSystem*> mParticles;
|
std::vector<Ogre::ParticleSystem*> mParticles;
|
||||||
std::vector<Ogre::Light*> mLights;
|
std::vector<Ogre::Light*> mLights;
|
||||||
|
|
||||||
|
// Nodes that should always face the camera when rendering
|
||||||
|
std::vector<Ogre::Node*> mBillboardNodes;
|
||||||
|
|
||||||
Ogre::SceneManager* mSceneMgr;
|
Ogre::SceneManager* mSceneMgr;
|
||||||
|
|
||||||
// The maximum length on any of the controllers. For animations with controllers, but no text keys, consider this the animation length.
|
// The maximum length on any of the controllers. For animations with controllers, but no text keys, consider this the animation length.
|
||||||
|
@ -74,6 +79,9 @@ struct ObjectScene {
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
~ObjectScene();
|
~ObjectScene();
|
||||||
|
|
||||||
|
// Rotate nodes in mBillboardNodes so they face the given camera
|
||||||
|
void rotateBillboardNodes(Ogre::Camera* camera);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Ogre::SharedPtr<ObjectScene> ObjectScenePtr;
|
typedef Ogre::SharedPtr<ObjectScene> ObjectScenePtr;
|
||||||
|
|
|
@ -16,46 +16,11 @@
|
||||||
class NifEmitter : public Ogre::ParticleEmitter
|
class NifEmitter : public Ogre::ParticleEmitter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::string mSkelBaseName;
|
Ogre::Bone* mEmitterBone;
|
||||||
Ogre::Bone* mBone;
|
Ogre::Bone* mParticleBone;
|
||||||
|
|
||||||
Ogre::ParticleSystem* getPartSys() { return mParent; }
|
Ogre::ParticleSystem* getPartSys() { return mParent; }
|
||||||
|
|
||||||
class CmdSkelBase : public Ogre::ParamCommand
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Ogre::String doGet(const void *target) const
|
|
||||||
{
|
|
||||||
assert(false && "Unimplemented");
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
void doSet(void *target, const Ogre::String &val)
|
|
||||||
{
|
|
||||||
NifEmitter* emitter = static_cast<NifEmitter*>(target);
|
|
||||||
emitter->mSkelBaseName = val;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class CmdBone : public Ogre::ParamCommand
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Ogre::String doGet(const void *target) const
|
|
||||||
{
|
|
||||||
assert(false && "Unimplemented");
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
void doSet(void *target, const Ogre::String &val)
|
|
||||||
{
|
|
||||||
NifEmitter* emitter = static_cast<NifEmitter*>(target);
|
|
||||||
assert(!emitter->mSkelBaseName.empty() && "Base entity needs to be set first");
|
|
||||||
Ogre::ParticleSystem* partsys = emitter->getPartSys();
|
|
||||||
Ogre::Entity* ent = partsys->getParentSceneNode()->getCreator()->getEntity(emitter->mSkelBaseName);
|
|
||||||
Ogre::Bone* bone = ent->getSkeleton()->getBone(val);
|
|
||||||
assert(bone);
|
|
||||||
emitter->mBone = bone;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Command object for the emitter width (see Ogre::ParamCommand).*/
|
/** Command object for the emitter width (see Ogre::ParamCommand).*/
|
||||||
class CmdWidth : public Ogre::ParamCommand
|
class CmdWidth : public Ogre::ParamCommand
|
||||||
{
|
{
|
||||||
|
@ -165,8 +130,10 @@ public:
|
||||||
|
|
||||||
NifEmitter(Ogre::ParticleSystem *psys)
|
NifEmitter(Ogre::ParticleSystem *psys)
|
||||||
: Ogre::ParticleEmitter(psys)
|
: Ogre::ParticleEmitter(psys)
|
||||||
, mBone(NULL)
|
|
||||||
{
|
{
|
||||||
|
mEmitterBone = Ogre::any_cast<Ogre::Bone*>(psys->getUserObjectBindings().getUserAny());
|
||||||
|
Ogre::TagPoint* tag = static_cast<Ogre::TagPoint*>(mParent->getParentNode());
|
||||||
|
mParticleBone = static_cast<Ogre::Bone*>(tag->getParent());
|
||||||
initDefaults("Nif");
|
initDefaults("Nif");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +147,6 @@ public:
|
||||||
/** See Ogre::ParticleEmitter. */
|
/** See Ogre::ParticleEmitter. */
|
||||||
void _initParticle(Ogre::Particle *particle)
|
void _initParticle(Ogre::Particle *particle)
|
||||||
{
|
{
|
||||||
assert (mBone && "No node set");
|
|
||||||
Ogre::Vector3 xOff, yOff, zOff;
|
Ogre::Vector3 xOff, yOff, zOff;
|
||||||
|
|
||||||
// Call superclass
|
// Call superclass
|
||||||
|
@ -190,22 +156,40 @@ public:
|
||||||
yOff = Ogre::Math::SymmetricRandom() * mYRange;
|
yOff = Ogre::Math::SymmetricRandom() * mYRange;
|
||||||
zOff = Ogre::Math::SymmetricRandom() * mZRange;
|
zOff = Ogre::Math::SymmetricRandom() * mZRange;
|
||||||
|
|
||||||
particle->position = mBone->_getDerivedPosition() + xOff + yOff + zOff;
|
#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0)
|
||||||
|
Ogre::Vector3& position = particle->mPosition;
|
||||||
|
Ogre::Vector3& direction = particle->mDirection;
|
||||||
|
Ogre::ColourValue& colour = particle->mColour;
|
||||||
|
Ogre::Real& totalTimeToLive = particle->mTotalTimeToLive;
|
||||||
|
Ogre::Real& timeToLive = particle->mTimeToLive;
|
||||||
|
#else
|
||||||
|
Ogre::Vector3& position = particle->position;
|
||||||
|
Ogre::Vector3& direction = particle->direction;
|
||||||
|
Ogre::ColourValue& colour = particle->colour;
|
||||||
|
Ogre::Real& totalTimeToLive = particle->totalTimeToLive;
|
||||||
|
Ogre::Real& timeToLive = particle->timeToLive;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
position = xOff + yOff + zOff +
|
||||||
|
mParticleBone->_getDerivedOrientation().Inverse() * (mEmitterBone->_getDerivedPosition()
|
||||||
|
- mParticleBone->_getDerivedPosition());
|
||||||
|
|
||||||
// Generate complex data by reference
|
// Generate complex data by reference
|
||||||
genEmissionColour(particle->colour);
|
genEmissionColour(colour);
|
||||||
|
|
||||||
// NOTE: We do not use mDirection/mAngle for the initial direction.
|
// NOTE: We do not use mDirection/mAngle for the initial direction.
|
||||||
Ogre::Radian hdir = mHorizontalDir + mHorizontalAngle*Ogre::Math::SymmetricRandom();
|
Ogre::Radian hdir = mHorizontalDir + mHorizontalAngle*Ogre::Math::SymmetricRandom();
|
||||||
Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom();
|
Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom();
|
||||||
particle->direction = (mBone->_getDerivedOrientation() * Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z) *
|
direction = (mParticleBone->_getDerivedOrientation().Inverse()
|
||||||
|
* mEmitterBone->_getDerivedOrientation() *
|
||||||
|
Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z) *
|
||||||
Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X)) *
|
Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X)) *
|
||||||
Ogre::Vector3::UNIT_Z;
|
Ogre::Vector3::UNIT_Z;
|
||||||
|
|
||||||
genEmissionVelocity(particle->direction);
|
genEmissionVelocity(direction);
|
||||||
|
|
||||||
// Generate simpler data
|
// Generate simpler data
|
||||||
particle->timeToLive = particle->totalTimeToLive = genEmissionTTL();
|
timeToLive = totalTimeToLive = genEmissionTTL();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Overloaded to update the trans. matrix */
|
/** Overloaded to update the trans. matrix */
|
||||||
|
@ -361,16 +345,6 @@ protected:
|
||||||
Ogre::PT_REAL),
|
Ogre::PT_REAL),
|
||||||
&msHorizontalAngleCmd);
|
&msHorizontalAngleCmd);
|
||||||
|
|
||||||
dict->addParameter(Ogre::ParameterDef("bone",
|
|
||||||
"The bone where the particles should be spawned",
|
|
||||||
Ogre::PT_STRING),
|
|
||||||
&msBoneCmd);
|
|
||||||
|
|
||||||
dict->addParameter(Ogre::ParameterDef("skelbase",
|
|
||||||
"The name of the entity containing the bone (see 'bone' parameter)",
|
|
||||||
Ogre::PT_STRING),
|
|
||||||
&msSkelBaseCmd);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -384,8 +358,6 @@ protected:
|
||||||
static CmdVerticalAngle msVerticalAngleCmd;
|
static CmdVerticalAngle msVerticalAngleCmd;
|
||||||
static CmdHorizontalDir msHorizontalDirCmd;
|
static CmdHorizontalDir msHorizontalDirCmd;
|
||||||
static CmdHorizontalAngle msHorizontalAngleCmd;
|
static CmdHorizontalAngle msHorizontalAngleCmd;
|
||||||
static CmdBone msBoneCmd;
|
|
||||||
static CmdSkelBase msSkelBaseCmd;
|
|
||||||
};
|
};
|
||||||
NifEmitter::CmdWidth NifEmitter::msWidthCmd;
|
NifEmitter::CmdWidth NifEmitter::msWidthCmd;
|
||||||
NifEmitter::CmdHeight NifEmitter::msHeightCmd;
|
NifEmitter::CmdHeight NifEmitter::msHeightCmd;
|
||||||
|
@ -394,8 +366,6 @@ NifEmitter::CmdVerticalDir NifEmitter::msVerticalDirCmd;
|
||||||
NifEmitter::CmdVerticalAngle NifEmitter::msVerticalAngleCmd;
|
NifEmitter::CmdVerticalAngle NifEmitter::msVerticalAngleCmd;
|
||||||
NifEmitter::CmdHorizontalDir NifEmitter::msHorizontalDirCmd;
|
NifEmitter::CmdHorizontalDir NifEmitter::msHorizontalDirCmd;
|
||||||
NifEmitter::CmdHorizontalAngle NifEmitter::msHorizontalAngleCmd;
|
NifEmitter::CmdHorizontalAngle NifEmitter::msHorizontalAngleCmd;
|
||||||
NifEmitter::CmdBone NifEmitter::msBoneCmd;
|
|
||||||
NifEmitter::CmdSkelBase NifEmitter::msSkelBaseCmd;
|
|
||||||
|
|
||||||
Ogre::ParticleEmitter* NifEmitterFactory::createEmitter(Ogre::ParticleSystem *psys)
|
Ogre::ParticleEmitter* NifEmitterFactory::createEmitter(Ogre::ParticleSystem *psys)
|
||||||
{
|
{
|
||||||
|
@ -466,9 +436,13 @@ public:
|
||||||
/** See Ogre::ParticleAffector. */
|
/** See Ogre::ParticleAffector. */
|
||||||
void _initParticle(Ogre::Particle *particle)
|
void _initParticle(Ogre::Particle *particle)
|
||||||
{
|
{
|
||||||
|
#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0)
|
||||||
|
const Ogre::Real life_time = particle->mTotalTimeToLive;
|
||||||
|
Ogre::Real particle_time = particle->mTimeToLive;
|
||||||
|
#else
|
||||||
const Ogre::Real life_time = particle->totalTimeToLive;
|
const Ogre::Real life_time = particle->totalTimeToLive;
|
||||||
Ogre::Real particle_time = particle->timeToLive;
|
Ogre::Real particle_time = particle->timeToLive;
|
||||||
|
#endif
|
||||||
Ogre::Real width = mParent->getDefaultWidth();
|
Ogre::Real width = mParent->getDefaultWidth();
|
||||||
Ogre::Real height = mParent->getDefaultHeight();
|
Ogre::Real height = mParent->getDefaultHeight();
|
||||||
if(life_time-particle_time < mGrowTime)
|
if(life_time-particle_time < mGrowTime)
|
||||||
|
@ -493,9 +467,13 @@ public:
|
||||||
while (!pi.end())
|
while (!pi.end())
|
||||||
{
|
{
|
||||||
Ogre::Particle *p = pi.getNext();
|
Ogre::Particle *p = pi.getNext();
|
||||||
|
#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0)
|
||||||
|
const Ogre::Real life_time = p->mTotalTimeToLive;
|
||||||
|
Ogre::Real particle_time = p->mTimeToLive;
|
||||||
|
#else
|
||||||
const Ogre::Real life_time = p->totalTimeToLive;
|
const Ogre::Real life_time = p->totalTimeToLive;
|
||||||
Ogre::Real particle_time = p->timeToLive;
|
Ogre::Real particle_time = p->timeToLive;
|
||||||
|
#endif
|
||||||
Ogre::Real width = mParent->getDefaultWidth();
|
Ogre::Real width = mParent->getDefaultWidth();
|
||||||
Ogre::Real height = mParent->getDefaultHeight();
|
Ogre::Real height = mParent->getDefaultHeight();
|
||||||
if(life_time-particle_time < mGrowTime)
|
if(life_time-particle_time < mGrowTime)
|
||||||
|
@ -554,47 +532,11 @@ class GravityAffector : public Ogre::ParticleAffector
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::string mSkelBaseName;
|
Ogre::Bone* mEmitterBone;
|
||||||
Ogre::Bone* mBone;
|
Ogre::Bone* mParticleBone;
|
||||||
|
|
||||||
Ogre::ParticleSystem* getPartSys() { return mParent; }
|
Ogre::ParticleSystem* getPartSys() { return mParent; }
|
||||||
|
|
||||||
class CmdSkelBase : public Ogre::ParamCommand
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Ogre::String doGet(const void *target) const
|
|
||||||
{
|
|
||||||
assert(false && "Unimplemented");
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
void doSet(void *target, const Ogre::String &val)
|
|
||||||
{
|
|
||||||
GravityAffector* affector = static_cast<GravityAffector*>(target);
|
|
||||||
affector->mSkelBaseName = val;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class CmdBone : public Ogre::ParamCommand
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Ogre::String doGet(const void *target) const
|
|
||||||
{
|
|
||||||
assert(false && "Unimplemented");
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
void doSet(void *target, const Ogre::String &val)
|
|
||||||
{
|
|
||||||
GravityAffector* affector = static_cast<GravityAffector*>(target);
|
|
||||||
assert(!affector->mSkelBaseName.empty() && "Base entity needs to be set first");
|
|
||||||
Ogre::ParticleSystem* partsys = affector->getPartSys();
|
|
||||||
Ogre::Entity* ent = partsys->getParentSceneNode()->getCreator()->getEntity(affector->mSkelBaseName);
|
|
||||||
Ogre::Bone* bone = ent->getSkeleton()->getBone(val);
|
|
||||||
assert(bone);
|
|
||||||
affector->mBone = bone;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/** Command object for force (see Ogre::ParamCommand).*/
|
/** Command object for force (see Ogre::ParamCommand).*/
|
||||||
class CmdForce : public Ogre::ParamCommand
|
class CmdForce : public Ogre::ParamCommand
|
||||||
{
|
{
|
||||||
|
@ -688,8 +630,11 @@ public:
|
||||||
, mForceType(Type_Wind)
|
, mForceType(Type_Wind)
|
||||||
, mPosition(0.0f)
|
, mPosition(0.0f)
|
||||||
, mDirection(0.0f)
|
, mDirection(0.0f)
|
||||||
, mBone(NULL)
|
|
||||||
{
|
{
|
||||||
|
mEmitterBone = Ogre::any_cast<Ogre::Bone*>(psys->getUserObjectBindings().getUserAny());
|
||||||
|
Ogre::TagPoint* tag = static_cast<Ogre::TagPoint*>(mParent->getParentNode());
|
||||||
|
mParticleBone = static_cast<Ogre::Bone*>(tag->getParent());
|
||||||
|
|
||||||
mType = "Gravity";
|
mType = "Gravity";
|
||||||
|
|
||||||
// Init parameters
|
// Init parameters
|
||||||
|
@ -710,16 +655,6 @@ public:
|
||||||
dict->addParameter(Ogre::ParameterDef(force_type_title, force_type_descr, Ogre::PT_STRING), &msForceTypeCmd);
|
dict->addParameter(Ogre::ParameterDef(force_type_title, force_type_descr, Ogre::PT_STRING), &msForceTypeCmd);
|
||||||
dict->addParameter(Ogre::ParameterDef(direction_title, direction_descr, Ogre::PT_VECTOR3), &msDirectionCmd);
|
dict->addParameter(Ogre::ParameterDef(direction_title, direction_descr, Ogre::PT_VECTOR3), &msDirectionCmd);
|
||||||
dict->addParameter(Ogre::ParameterDef(position_title, position_descr, Ogre::PT_VECTOR3), &msPositionCmd);
|
dict->addParameter(Ogre::ParameterDef(position_title, position_descr, Ogre::PT_VECTOR3), &msPositionCmd);
|
||||||
|
|
||||||
dict->addParameter(Ogre::ParameterDef("bone",
|
|
||||||
"The bone where the particles should be spawned",
|
|
||||||
Ogre::PT_STRING),
|
|
||||||
&msBoneCmd);
|
|
||||||
|
|
||||||
dict->addParameter(Ogre::ParameterDef("skelbase",
|
|
||||||
"The name of the entity containing the bone (see 'bone' parameter)",
|
|
||||||
Ogre::PT_STRING),
|
|
||||||
&msSkelBaseCmd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -761,18 +696,20 @@ public:
|
||||||
static CmdForceType msForceTypeCmd;
|
static CmdForceType msForceTypeCmd;
|
||||||
static CmdDirection msDirectionCmd;
|
static CmdDirection msDirectionCmd;
|
||||||
static CmdPosition msPositionCmd;
|
static CmdPosition msPositionCmd;
|
||||||
static CmdBone msBoneCmd;
|
|
||||||
static CmdSkelBase msSkelBaseCmd;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void applyWindForce(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed)
|
void applyWindForce(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed)
|
||||||
{
|
{
|
||||||
const Ogre::Vector3 vec = mBone->_getDerivedOrientation() * mDirection * mForce * timeElapsed;
|
const Ogre::Vector3 vec = mDirection * mForce * timeElapsed;
|
||||||
Ogre::ParticleIterator pi = psys->_getIterator();
|
Ogre::ParticleIterator pi = psys->_getIterator();
|
||||||
while (!pi.end())
|
while (!pi.end())
|
||||||
{
|
{
|
||||||
Ogre::Particle *p = pi.getNext();
|
Ogre::Particle *p = pi.getNext();
|
||||||
|
#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0)
|
||||||
|
p->mDirection += vec;
|
||||||
|
#else
|
||||||
p->direction += vec;
|
p->direction += vec;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -783,9 +720,18 @@ protected:
|
||||||
while (!pi.end())
|
while (!pi.end())
|
||||||
{
|
{
|
||||||
Ogre::Particle *p = pi.getNext();
|
Ogre::Particle *p = pi.getNext();
|
||||||
const Ogre::Vector3 vec = (
|
#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0)
|
||||||
(mBone->_getDerivedOrientation() * mPosition + mBone->_getDerivedPosition()) - p->position).normalisedCopy() * force;
|
Ogre::Vector3 position = p->mPosition;
|
||||||
|
#else
|
||||||
|
Ogre::Vector3 position = p->position;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Ogre::Vector3 vec = (mPosition - position).normalisedCopy() * force;
|
||||||
|
#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0)
|
||||||
|
p->mDirection += vec;
|
||||||
|
#else
|
||||||
p->direction += vec;
|
p->direction += vec;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -801,8 +747,6 @@ GravityAffector::CmdForce GravityAffector::msForceCmd;
|
||||||
GravityAffector::CmdForceType GravityAffector::msForceTypeCmd;
|
GravityAffector::CmdForceType GravityAffector::msForceTypeCmd;
|
||||||
GravityAffector::CmdDirection GravityAffector::msDirectionCmd;
|
GravityAffector::CmdDirection GravityAffector::msDirectionCmd;
|
||||||
GravityAffector::CmdPosition GravityAffector::msPositionCmd;
|
GravityAffector::CmdPosition GravityAffector::msPositionCmd;
|
||||||
GravityAffector::CmdBone GravityAffector::msBoneCmd;
|
|
||||||
GravityAffector::CmdSkelBase GravityAffector::msSkelBaseCmd;
|
|
||||||
|
|
||||||
Ogre::ParticleAffector *GravityAffectorFactory::createAffector(Ogre::ParticleSystem *psys)
|
Ogre::ParticleAffector *GravityAffectorFactory::createAffector(Ogre::ParticleSystem *psys)
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,6 +30,7 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node,
|
||||||
node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */
|
node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */
|
||||||
node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */
|
node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */
|
||||||
node->recType == Nif::RC_NiBSAnimationNode || /* Handled in the object loader */
|
node->recType == Nif::RC_NiBSAnimationNode || /* Handled in the object loader */
|
||||||
|
node->recType == Nif::RC_NiBillboardNode || /* Handled in the object loader */
|
||||||
node->recType == Nif::RC_NiBSParticleNode ||
|
node->recType == Nif::RC_NiBSParticleNode ||
|
||||||
node->recType == Nif::RC_NiCamera ||
|
node->recType == Nif::RC_NiCamera ||
|
||||||
node->recType == Nif::RC_NiAutoNormalParticles ||
|
node->recType == Nif::RC_NiAutoNormalParticles ||
|
||||||
|
|
3
extern/shiny/Main/Factory.hpp
vendored
3
extern/shiny/Main/Factory.hpp
vendored
|
@ -259,9 +259,8 @@ namespace sh
|
||||||
Platform* mPlatform;
|
Platform* mPlatform;
|
||||||
|
|
||||||
MaterialInstance* findInstance (const std::string& name);
|
MaterialInstance* findInstance (const std::string& name);
|
||||||
public:
|
|
||||||
MaterialInstance* searchInstance (const std::string& name);
|
|
||||||
private:
|
private:
|
||||||
|
MaterialInstance* searchInstance (const std::string& name);
|
||||||
/// @return was anything removed?
|
/// @return was anything removed?
|
||||||
bool removeCache (const std::string& pattern);
|
bool removeCache (const std::string& pattern);
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,15 @@ material openmw_objects_base
|
||||||
diffuseMap black.png
|
diffuseMap black.png
|
||||||
normalMap
|
normalMap
|
||||||
emissiveMap
|
emissiveMap
|
||||||
|
darkMap
|
||||||
use_emissive_map false
|
use_emissive_map false
|
||||||
use_detail_map false
|
use_detail_map false
|
||||||
|
use_diffuse_map false
|
||||||
|
use_dark_map false
|
||||||
emissiveMapUVSet 0
|
emissiveMapUVSet 0
|
||||||
detailMapUVSet 0
|
detailMapUVSet 0
|
||||||
|
diffuseMapUVSet 0
|
||||||
|
darkMapUVSet 0
|
||||||
use_parallax false
|
use_parallax false
|
||||||
|
|
||||||
scene_blend default
|
scene_blend default
|
||||||
|
@ -34,8 +39,12 @@ material openmw_objects_base
|
||||||
normalMap $normalMap
|
normalMap $normalMap
|
||||||
emissiveMapUVSet $emissiveMapUVSet
|
emissiveMapUVSet $emissiveMapUVSet
|
||||||
detailMapUVSet $detailMapUVSet
|
detailMapUVSet $detailMapUVSet
|
||||||
|
diffuseMapUVSet $diffuseMapUVSet
|
||||||
|
darkMapUVSet $darkMapUVSet
|
||||||
emissiveMap $emissiveMap
|
emissiveMap $emissiveMap
|
||||||
detailMap $detailMap
|
detailMap $detailMap
|
||||||
|
diffuseMap $diffuseMap
|
||||||
|
darkMap $darkMap
|
||||||
env_map $env_map
|
env_map $env_map
|
||||||
env_map_color $env_map_color
|
env_map_color $env_map_color
|
||||||
use_parallax $use_parallax
|
use_parallax $use_parallax
|
||||||
|
@ -55,8 +64,8 @@ material openmw_objects_base
|
||||||
texture_unit diffuseMap
|
texture_unit diffuseMap
|
||||||
{
|
{
|
||||||
direct_texture $diffuseMap
|
direct_texture $diffuseMap
|
||||||
create_in_ffp true
|
create_in_ffp $use_diffuse_map
|
||||||
tex_coord_set $emissiveMapUVSet
|
tex_coord_set $diffuseMapUVSet
|
||||||
}
|
}
|
||||||
|
|
||||||
texture_unit normalMap
|
texture_unit normalMap
|
||||||
|
@ -66,12 +75,13 @@ material openmw_objects_base
|
||||||
num_mipmaps 4
|
num_mipmaps 4
|
||||||
}
|
}
|
||||||
|
|
||||||
texture_unit emissiveMap
|
texture_unit darkMap
|
||||||
{
|
{
|
||||||
create_in_ffp $use_emissive_map
|
create_in_ffp $use_dark_map
|
||||||
colour_op add
|
colour_op_ex modulate src_current src_texture
|
||||||
direct_texture $emissiveMap
|
alpha_op_ex modulate src_current src_texture
|
||||||
tex_coord_set $emissiveMapUVSet
|
direct_texture $darkMap
|
||||||
|
tex_coord_set $darkMapUVSet
|
||||||
}
|
}
|
||||||
|
|
||||||
texture_unit detailMap
|
texture_unit detailMap
|
||||||
|
@ -82,6 +92,14 @@ material openmw_objects_base
|
||||||
tex_coord_set $detailMapUVSet
|
tex_coord_set $detailMapUVSet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
texture_unit emissiveMap
|
||||||
|
{
|
||||||
|
create_in_ffp $use_emissive_map
|
||||||
|
colour_op add
|
||||||
|
direct_texture $emissiveMap
|
||||||
|
tex_coord_set $emissiveMapUVSet
|
||||||
|
}
|
||||||
|
|
||||||
texture_unit envMap
|
texture_unit envMap
|
||||||
{
|
{
|
||||||
create_in_ffp $env_map
|
create_in_ffp $env_map
|
||||||
|
|
|
@ -17,13 +17,15 @@
|
||||||
#define NORMAL_MAP @shPropertyHasValue(normalMap)
|
#define NORMAL_MAP @shPropertyHasValue(normalMap)
|
||||||
#define EMISSIVE_MAP @shPropertyHasValue(emissiveMap)
|
#define EMISSIVE_MAP @shPropertyHasValue(emissiveMap)
|
||||||
#define DETAIL_MAP @shPropertyHasValue(detailMap)
|
#define DETAIL_MAP @shPropertyHasValue(detailMap)
|
||||||
|
#define DIFFUSE_MAP @shPropertyHasValue(diffuseMap)
|
||||||
|
#define DARK_MAP @shPropertyHasValue(darkMap)
|
||||||
|
|
||||||
#define PARALLAX @shPropertyBool(use_parallax)
|
#define PARALLAX @shPropertyBool(use_parallax)
|
||||||
#define PARALLAX_SCALE 0.04
|
#define PARALLAX_SCALE 0.04
|
||||||
#define PARALLAX_BIAS -0.02
|
#define PARALLAX_BIAS -0.02
|
||||||
|
|
||||||
// right now we support 2 UV sets max. implementing them is tedious, and we're probably not going to need more
|
// right now we support 2 UV sets max. implementing them is tedious, and we're probably not going to need more
|
||||||
#define SECOND_UV_SET (@shPropertyString(emissiveMapUVSet) || @shPropertyString(detailMapUVSet))
|
#define SECOND_UV_SET (@shPropertyString(emissiveMapUVSet) || @shPropertyString(detailMapUVSet) || @shPropertyString(diffuseMapUVSet) || @shPropertyString(darkMapUVSet))
|
||||||
|
|
||||||
// if normal mapping is enabled, we force pixel lighting
|
// if normal mapping is enabled, we force pixel lighting
|
||||||
#define VERTEX_LIGHTING (!@shPropertyHasValue(normalMap))
|
#define VERTEX_LIGHTING (!@shPropertyHasValue(normalMap))
|
||||||
|
@ -246,20 +248,26 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SH_BEGIN_PROGRAM
|
SH_BEGIN_PROGRAM
|
||||||
|
#if DIFFUSE_MAP
|
||||||
shSampler2D(diffuseMap)
|
shSampler2D(diffuseMap)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if NORMAL_MAP
|
#if NORMAL_MAP
|
||||||
shSampler2D(normalMap)
|
shSampler2D(normalMap)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if EMISSIVE_MAP
|
#if DARK_MAP
|
||||||
shSampler2D(emissiveMap)
|
shSampler2D(darkMap)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if DETAIL_MAP
|
#if DETAIL_MAP
|
||||||
shSampler2D(detailMap)
|
shSampler2D(detailMap)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if EMISSIVE_MAP
|
||||||
|
shSampler2D(emissiveMap)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if ENV_MAP
|
#if ENV_MAP
|
||||||
shSampler2D(envMap)
|
shSampler2D(envMap)
|
||||||
shUniform(float3, env_map_color) @shUniformProperty3f(env_map_color, env_map_color)
|
shUniform(float3, env_map_color) @shUniformProperty3f(env_map_color, env_map_color)
|
||||||
|
@ -376,17 +384,33 @@
|
||||||
newUV += (TSeyeDir.xyxy * ( normalTex.a * PARALLAX_SCALE + PARALLAX_BIAS )).xyxy;
|
newUV += (TSeyeDir.xyxy * ( normalTex.a * PARALLAX_SCALE + PARALLAX_BIAS )).xyxy;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if DIFFUSE_MAP
|
||||||
|
#if @shPropertyString(diffuseMapUVSet)
|
||||||
|
float4 diffuse = shSample(diffuseMap, newUV.zw);
|
||||||
|
#else
|
||||||
float4 diffuse = shSample(diffuseMap, newUV.xy);
|
float4 diffuse = shSample(diffuseMap, newUV.xy);
|
||||||
shOutputColour(0) = diffuse;
|
#endif
|
||||||
|
#else
|
||||||
|
float4 diffuse = float4(1,1,1,1);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if DETAIL_MAP
|
#if DETAIL_MAP
|
||||||
#if @shPropertyString(detailMapUVSet)
|
#if @shPropertyString(detailMapUVSet)
|
||||||
shOutputColour(0) *= shSample(detailMap, newUV.zw)*2;
|
diffuse *= shSample(detailMap, newUV.zw)*2;
|
||||||
#else
|
#else
|
||||||
shOutputColour(0) *= shSample(detailMap, newUV.xy)*2;
|
diffuse *= shSample(detailMap, newUV.xy)*2;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if DARK_MAP
|
||||||
|
#if @shPropertyString(darkMapUVSet)
|
||||||
|
diffuse *= shSample(darkMap, newUV.zw);
|
||||||
|
#else
|
||||||
|
diffuse *= shSample(darkMap, newUV.xy);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
shOutputColour(0) = diffuse;
|
||||||
|
|
||||||
#if !VERTEX_LIGHTING
|
#if !VERTEX_LIGHTING
|
||||||
float3 viewPos = shMatrixMult(worldView, float4(objSpacePositionPassthrough.xyz,1)).xyz;
|
float3 viewPos = shMatrixMult(worldView, float4(objSpacePositionPassthrough.xyz,1)).xyz;
|
||||||
|
|
|
@ -345,6 +345,7 @@ float2 blendUV = (UV - 0.5) * (16.0 / (16.0+1.0)) + 0.5;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@shForeach(@shPropertyString(num_layers))
|
@shForeach(@shPropertyString(num_layers))
|
||||||
|
thisLayerUV = layerUV;
|
||||||
#if @shPropertyBool(use_normal_map_@shIterator)
|
#if @shPropertyBool(use_normal_map_@shIterator)
|
||||||
normalTex = shSample(normalMap@shIterator, thisLayerUV);
|
normalTex = shSample(normalMap@shIterator, thisLayerUV);
|
||||||
#if @shIterator == 0 && IS_FIRST_PASS
|
#if @shIterator == 0 && IS_FIRST_PASS
|
||||||
|
@ -354,7 +355,6 @@ float2 blendUV = (UV - 0.5) * (16.0 / (16.0+1.0)) + 0.5;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
thisLayerUV = layerUV;
|
|
||||||
#if @shPropertyBool(use_parallax_@shIterator)
|
#if @shPropertyBool(use_parallax_@shIterator)
|
||||||
thisLayerUV += TSeyeDir.xy * ( normalTex.a * PARALLAX_SCALE + PARALLAX_BIAS );
|
thisLayerUV += TSeyeDir.xy * ( normalTex.a * PARALLAX_SCALE + PARALLAX_BIAS );
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include <extern/sdl4ogre/sdlwindowhelper.hpp>
|
#include <extern/sdl4ogre/sdlwindowhelper.hpp>
|
||||||
|
|
||||||
|
#include <components/ogreinit/ogreinit.hpp>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
@ -23,6 +25,12 @@ void OgreRenderer::cleanup()
|
||||||
delete mFader;
|
delete mFader;
|
||||||
mFader = NULL;
|
mFader = NULL;
|
||||||
|
|
||||||
|
Ogre::Root::getSingleton().destroyRenderTarget(mWindow);
|
||||||
|
mWindow = NULL;
|
||||||
|
|
||||||
|
delete mOgreInit;
|
||||||
|
mOgreInit = NULL;
|
||||||
|
|
||||||
// If we don't do this, the desktop resolution is not restored on exit
|
// If we don't do this, the desktop resolution is not restored on exit
|
||||||
SDL_SetWindowFullscreen(mSDLWindow, 0);
|
SDL_SetWindowFullscreen(mSDLWindow, 0);
|
||||||
|
|
||||||
|
@ -50,7 +58,8 @@ void OgreRenderer::configure(const std::string &logPath,
|
||||||
const std::string& rttMode
|
const std::string& rttMode
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
mRoot = mOgreInit.init(logPath + "/ogre.log");
|
mOgreInit = new OgreInit::OgreInit();
|
||||||
|
mRoot = mOgreInit->init(logPath + "/ogre.log");
|
||||||
|
|
||||||
RenderSystem* rs = mRoot->getRenderSystemByName(renderSystem);
|
RenderSystem* rs = mRoot->getRenderSystemByName(renderSystem);
|
||||||
if (rs == 0)
|
if (rs == 0)
|
||||||
|
|
|
@ -9,8 +9,6 @@
|
||||||
|
|
||||||
#include <OgreTexture.h>
|
#include <OgreTexture.h>
|
||||||
|
|
||||||
#include <components/ogreinit/ogreinit.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
struct SDL_Window;
|
struct SDL_Window;
|
||||||
struct SDL_Surface;
|
struct SDL_Surface;
|
||||||
|
@ -26,6 +24,11 @@ namespace Ogre
|
||||||
class ParticleAffectorFactory;
|
class ParticleAffectorFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace OgreInit
|
||||||
|
{
|
||||||
|
class OgreInit;
|
||||||
|
}
|
||||||
|
|
||||||
namespace OEngine
|
namespace OEngine
|
||||||
{
|
{
|
||||||
namespace Render
|
namespace Render
|
||||||
|
@ -57,7 +60,7 @@ namespace OEngine
|
||||||
Ogre::Camera *mCamera;
|
Ogre::Camera *mCamera;
|
||||||
Ogre::Viewport *mView;
|
Ogre::Viewport *mView;
|
||||||
|
|
||||||
OgreInit::OgreInit mOgreInit;
|
OgreInit::OgreInit* mOgreInit;
|
||||||
|
|
||||||
Fader* mFader;
|
Fader* mFader;
|
||||||
|
|
||||||
|
|
59
readme.txt
59
readme.txt
|
@ -36,49 +36,58 @@ https://wiki.openmw.org/index.php?title=Development_Environment_Setup
|
||||||
|
|
||||||
THE DATA PATH
|
THE DATA PATH
|
||||||
|
|
||||||
The data path tells OpenMW where to find your Morrowind files. From 0.12.0 on OpenMW should be able to
|
The data path tells OpenMW where to find your Morrowind files. If you run the launcher, OpenMW should be able to
|
||||||
pick up the location of these files on its own, if both Morrowind and OpenMW are installed properly
|
pick up the location of these files on its own, if both Morrowind and OpenMW are installed properly
|
||||||
(installing Morrowind under WINE is considered a proper install).
|
(installing Morrowind under WINE is considered a proper install).
|
||||||
|
|
||||||
If that does not work for you, please check if you have any leftover openmw.cfg files from versions earlier than 0.12.0. These can interfere with the configuration process, so try to remove then.
|
|
||||||
|
|
||||||
If you are running OpenMW without installing it, you still need to manually adjust the data path. Create a text file named openmw.cfg in the location of the binary and enter the following line:
|
|
||||||
|
|
||||||
data=path to your data directory
|
|
||||||
|
|
||||||
(where you replace "path to your data directory" with the actual location of your data directory)
|
|
||||||
|
|
||||||
|
|
||||||
COMMAND LINE OPTIONS
|
COMMAND LINE OPTIONS
|
||||||
|
|
||||||
Syntax: openmw <options>
|
Syntax: openmw <options>
|
||||||
Allowed options:
|
Allowed options:
|
||||||
--help print help message
|
--help print help message
|
||||||
--version print version information and quit
|
--version print version information and quit
|
||||||
--data arg (=data) set data directories (later directories have higher priority)
|
--data arg (=data) set data directories (later directories
|
||||||
--data-local arg set local data directory (highest priority)
|
have higher priority)
|
||||||
|
--data-local arg set local data directory (highest
|
||||||
|
priority)
|
||||||
|
--fallback-archive arg (=fallback-archive)
|
||||||
|
set fallback BSA archives (later
|
||||||
|
archives have higher priority)
|
||||||
--resources arg (=resources) set resources directory
|
--resources arg (=resources) set resources directory
|
||||||
--start arg (=Beshara) set initial cell
|
--start arg (=Beshara) set initial cell
|
||||||
--master arg master file(s)
|
--content arg content file(s): esm/esp, or
|
||||||
--plugin arg plugin file(s)
|
omwgame/omwaddon
|
||||||
--anim-verbose [=arg(=1)] (=0) output animation indices files
|
--anim-verbose [=arg(=1)] (=0) output animation indices files
|
||||||
--debug [=arg(=1)] (=0) debug mode
|
--no-sound [=arg(=1)] (=0) disable all sounds
|
||||||
--nosound [=arg(=1)] (=0) disable all sounds
|
|
||||||
--script-verbose [=arg(=1)] (=0) verbose script output
|
--script-verbose [=arg(=1)] (=0) verbose script output
|
||||||
--script-all [=arg(=1)] (=0) compile all scripts (excluding dialogue scripts) at startup
|
--script-all [=arg(=1)] (=0) compile all scripts (excluding dialogue
|
||||||
--script-console [=arg(=1)] (=0) enable console-only script functionality
|
scripts) at startup
|
||||||
--script-run arg select a file containing a list of console commands that is executed on startup
|
--script-console [=arg(=1)] (=0) enable console-only script
|
||||||
|
functionality
|
||||||
|
--script-run arg select a file containing a list of
|
||||||
|
console commands that is executed on
|
||||||
|
startup
|
||||||
--new-game [=arg(=1)] (=0) activate char gen/new game mechanics
|
--new-game [=arg(=1)] (=0) activate char gen/new game mechanics
|
||||||
--fs-strict [=arg(=1)] (=0) strict file system handling (no case folding)
|
--fs-strict [=arg(=1)] (=0) strict file system handling (no case
|
||||||
--encoding arg (=win1252) Character encoding used in OpenMW game messages:
|
folding)
|
||||||
|
--encoding arg (=win1252) Character encoding used in OpenMW game
|
||||||
|
messages:
|
||||||
|
|
||||||
win1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages
|
win1250 - Central and Eastern European
|
||||||
|
such as Polish, Czech, Slovak,
|
||||||
|
Hungarian, Slovene, Bosnian, Croatian,
|
||||||
|
Serbian (Latin script), Romanian and
|
||||||
|
Albanian languages
|
||||||
|
|
||||||
win1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages
|
win1251 - Cyrillic alphabet such as
|
||||||
|
Russian, Bulgarian, Serbian Cyrillic
|
||||||
win1252 - Western European (Latin) alphabet, used by default
|
and other languages
|
||||||
|
|
||||||
|
win1252 - Western European (Latin)
|
||||||
|
alphabet, used by default
|
||||||
--fallback arg fallback values
|
--fallback arg fallback values
|
||||||
|
--no-grab Don't grab mouse cursor
|
||||||
|
--activate-dist arg (=-1) activation distance override
|
||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue