Merge upstream (shadermanager log system revamp)

pull/541/head
AnyOldName3 6 years ago
commit 80082308f0

@ -24,8 +24,6 @@ addons:
packages: [
# Dev
cmake, clang-3.6, libunshield-dev, libtinyxml-dev,
# Tests
libgtest-dev, google-mock,
# Boost
libboost-filesystem-dev, libboost-program-options-dev, libboost-system-dev,
# FFmpeg

@ -171,6 +171,7 @@ Programmers
viadanna
Vincent Heuken
vocollapse
Yohaulticetl
zelurker
Documentation

@ -14,14 +14,19 @@
Bug #2862: [macOS] Can't quit launcher using Command-Q or OpenMW->Quit
Bug #2872: Tab completion in console doesn't work with explicit reference
Bug #2971: Compiler did not reject lines with naked expressions beginning with x.y
Bug #3049: Drain and Fortify effects are not properly applied on health, magicka and fatigue
Bug #3072: Fatal error on AddItem <item> that has a script containing Equip <item>
Bug #3249: Fixed revert function not updating views properly
Bug #3374: Touch spells not hitting kwama foragers
Bug #3486: [Mod] NPC Commands does not work
Bug #3533: GetSpellEffects should detect effects with zero duration
Bug #3591: Angled hit distance too low
Bug #3629: DB assassin attack never triggers creature spawning
Bug #3788: GetPCInJail and GetPCTraveling do not work as in vanilla
Bug #3876: Landscape texture painting is misaligned
Bug #3897: Have Goodbye give all choices the effects of Goodbye
Bug #3911: [macOS] Typing in the "Content List name" dialog box produces double characters
Bug #3948: AiCombat moving target aiming uses incorrect speed for magic projectiles
Bug #3950: FLATTEN_STATIC_TRANSFORMS optimization breaks animated collision shapes
Bug #3993: Terrain texture blending map is not upscaled
Bug #3997: Almalexia doesn't pace
@ -32,12 +37,15 @@
Bug #4215: OpenMW shows book text after last EOL tag
Bug #4221: Characters get stuck in V-shaped terrain
Bug #4230: AiTravel package issues break some Tribunal quests
Bug #4231: Infected rats from the "Crimson Plague" quest rendered unconscious by change in Drain Fatigue functionality
Bug #4251: Stationary NPCs do not return to their position after combat
Bug #4274: Pre-0.43 death animations are not forward-compatible with 0.43+
Bug #4286: Scripted animations can be interrupted
Bug #4291: Non-persistent actors that started the game as dead do not play death animations
Bug #4293: Faction members are not aware of faction ownerships in barter
Bug #4304: "Follow" not working as a second AI package
Bug #4307: World cleanup should remove dead bodies only if death animation is finished
Bug #4311: OpenMW does not handle RootCollisionNode correctly
Bug #4327: Missing animations during spell/weapon stance switching
Bug #4358: Running animation is interrupted when magic mode is toggled
Bug #4368: Settings window ok button doesn't have key focus by default
@ -61,11 +69,11 @@
Bug #4461: "Open" spell from non-player caster isn't a crime
Bug #4464: OpenMW keeps AiState cached storages even after we cancel AI packages
Bug #4469: Abot Silt Striders Model turn 90 degrees on horizontal
Bug #4470: Non-bipedal creatures with Weapon & Shield flag have inconsistent behaviour
Bug #4474: No fallback when getVampireHead fails
Bug #4475: Scripted animations should not cause movement
Bug #4479: "Game" category on Advanced page is getting too long
Bug #4480: Segfault in QuickKeysMenu when item no longer in inventory
Bug #4483: Shapes without NiTexturingProperty are rendered
Bug #4489: Goodbye doesn't block dialogue hyperlinks
Bug #4490: PositionCell on player gives "Error: tried to add local script twice"
Bug #4494: Training cap based off Base Skill instead of Modified Skill
@ -81,6 +89,12 @@
Bug #4553: Forcegreeting on non-actor opens a dialogue window which cannot be closed
Bug #4557: Topics with reserved names are handled differently from vanilla
Bug #4558: Mesh optimizer: check for reserved node name is case-sensitive
Bug #4563: Fast travel price logic checks destination cell instead of service actor cell
Bug #4565: Underwater view distance should be limited
Bug #4573: Player uses headtracking in the 1st-person mode
Bug #4574: Player turning animations are twitchy
Bug #4575: Weird result of attack animation blending with movement animations
Bug #4576: Reset of idle animations when attack can not be started
Feature #2606: Editor: Implemented (optional) case sensitive global search
Feature #3083: Play animation when NPC is casting spell via script
Feature #3103: Provide option for disposition to get increased by successful trade
@ -101,6 +115,8 @@
Feature #4548: Weapon priority: use the actual chance to hit the target instead of weapon skill
Feature #4549: Weapon priority: use the actual damage in weapon rating calculations
Feature #4550: Weapon priority: make ranged weapon bonus more sensible
Feature #4579: Add option for applying Strength into hand to hand damage
Feature #4581: Use proper logging system
Task #2490: Don't open command prompt window on Release-mode builds automatically
Task #4545: Enable is_pod string test

@ -1,11 +1,3 @@
#!/bin/sh
sudo ln -s /usr/bin/clang-3.6 /usr/local/bin/clang
sudo ln -s /usr/bin/clang++-3.6 /usr/local/bin/clang++
# build libgtest & libgtest_main
sudo mkdir /usr/src/gtest/build
cd /usr/src/gtest/build
sudo cmake .. -DBUILD_SHARED_LIBS=1
sudo make -j4
sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so
sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so

@ -1,8 +1,21 @@
#!/bin/sh
#!/bin/sh -e
free -m
env GENERATOR='Unix Makefiles' CONFIGURATION=Release CI/build_googletest.sh
GOOGLETEST_DIR="$(pwd)/googletest/build"
mkdir build
cd build
export CODE_COVERAGE=1
if [ "${CC}" = "clang" ]; then export CODE_COVERAGE=0; fi
${ANALYZE}cmake .. -DBUILD_WITH_CODE_COVERAGE=${CODE_COVERAGE} -DBUILD_UNITTESTS=1 -DCMAKE_INSTALL_PREFIX=/usr -DBINDIR=/usr/games -DCMAKE_BUILD_TYPE="None" -DUSE_SYSTEM_TINYXML=TRUE
${ANALYZE}cmake \
-DBUILD_WITH_CODE_COVERAGE=${CODE_COVERAGE} \
-DBUILD_UNITTESTS=1 \
-DCMAKE_INSTALL_PREFIX=/usr \
-DBINDIR=/usr/games \
-DCMAKE_BUILD_TYPE="None" \
-DUSE_SYSTEM_TINYXML=TRUE \
-DGTEST_ROOT="${GOOGLETEST_DIR}" \
-DGMOCK_ROOT="${GOOGLETEST_DIR}" \
..

@ -0,0 +1,13 @@
#!/bin/sh -e
git clone https://github.com/google/googletest.git
cd googletest
mkdir build
cd build
cmake \
-D CMAKE_BUILD_TYPE="${CONFIGURATION}" \
-D CMAKE_INSTALL_PREFIX=. \
-G "${GENERATOR}" \
..
cmake --build . --config "${CONFIGURATION}"
cmake --build . --target install --config "${CONFIGURATION}"

@ -1,6 +1,7 @@
set(LAUNCHER
datafilespage.cpp
graphicspage.cpp
sdlinit.cpp
main.cpp
maindialog.cpp
playpage.cpp
@ -19,6 +20,7 @@ set(LAUNCHER
set(LAUNCHER_HEADER
datafilespage.hpp
graphicspage.hpp
sdlinit.hpp
maindialog.hpp
playpage.hpp
textslotmsgbox.hpp

@ -76,6 +76,9 @@ bool Launcher::AdvancedPage::loadSettings()
loadSettingBool(chargeForEveryFollowerCheckBox, "charge for every follower travelling", "Game");
loadSettingBool(enchantedWeaponsMagicalCheckBox, "enchanted weapons are magical", "Game");
loadSettingBool(permanentBarterDispositionChangeCheckBox, "barter disposition change is permanent", "Game");
int unarmedFactorsStrengthIndex = mEngineSettings.getInt("strength influences hand to hand", "Game");
if (unarmedFactorsStrengthIndex >= 0 && unarmedFactorsStrengthIndex <= 2)
unarmedFactorsStrengthComboBox->setCurrentIndex(unarmedFactorsStrengthIndex);
// Input Settings
loadSettingBool(allowThirdPersonZoomCheckBox, "allow third person zoom", "Input");
@ -131,6 +134,9 @@ void Launcher::AdvancedPage::saveSettings()
saveSettingBool(chargeForEveryFollowerCheckBox, "charge for every follower travelling", "Game");
saveSettingBool(enchantedWeaponsMagicalCheckBox, "enchanted weapons are magical", "Game");
saveSettingBool(permanentBarterDispositionChangeCheckBox, "barter disposition change is permanent", "Game");
int unarmedFactorsStrengthIndex = unarmedFactorsStrengthComboBox->currentIndex();
if (unarmedFactorsStrengthIndex != mEngineSettings.getInt("strength influences hand to hand", "Game"))
mEngineSettings.setInt("strength influences hand to hand", "Game", unarmedFactorsStrengthIndex);
// Input Settings
saveSettingBool(allowThirdPersonZoomCheckBox, "allow third person zoom", "Input");

@ -12,7 +12,6 @@
#define MAC_OS_X_VERSION_MIN_REQUIRED __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
#endif // MAC_OS_X_VERSION_MIN_REQUIRED
#include <SDL.h>
#include <SDL_video.h>
#include <components/files/configurationmanager.hpp>
@ -48,27 +47,15 @@ Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, Settings:
}
bool Launcher::GraphicsPage::connectToSdl() {
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
SDL_SetMainReady();
// Required for determining screen resolution and such on the Graphics tab
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
return false;
}
signal(SIGINT, SIG_DFL); // We don't want to use the SDL event loop in the launcher,
// so reset SIGINT which SDL wants to redirect to an SDL_Quit event.
return true;
}
bool Launcher::GraphicsPage::setupSDL()
{
bool sdlConnectSuccessful = connectToSdl();
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
bool sdlConnectSuccessful = initSDL();
if (!sdlConnectSuccessful)
{
return false;
}
#endif
int displays = SDL_GetNumVideoDisplays();
@ -89,8 +76,10 @@ bool Launcher::GraphicsPage::setupSDL()
screenComboBox->addItem(QString(tr("Screen ")) + QString::number(i + 1));
}
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
// Disconnect from SDL processes
SDL_Quit();
quitSDL();
#endif
return true;
}

@ -7,6 +7,8 @@
#include <components/settings/settings.hpp>
#include "sdlinit.hpp"
namespace Files { struct ConfigurationManager; }
namespace Launcher
@ -37,11 +39,6 @@ namespace Launcher
QStringList getAvailableResolutions(int screen);
QRect getMaximumResolution();
/**
* Connect to the SDL so that we can use it to determine graphics
* @return whether or not connecting to SDL is successful
*/
bool connectToSdl();
bool setupSDL();
};
}

@ -12,11 +12,18 @@
#endif // MAC_OS_X_VERSION_MIN_REQUIRED
#include "maindialog.hpp"
#include "sdlinit.hpp"
int main(int argc, char *argv[])
{
try
{
// Note: we should init SDL2 before Qt4 to avoid crashes on Linux,
// but we should init SDL2 after Qt5 to avoid input issues on MacOS X.
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
initSDL();
#endif
QApplication app(argc, argv);
// Now we make sure the current dir is set to application path
@ -33,11 +40,18 @@ int main(int argc, char *argv[])
if (result == Launcher::FirstRunDialogResultContinue)
mainWin.show();
return app.exec();
int exitCode = app.exec();
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
// Disconnect from SDL processes
quitSDL();
#endif
return exitCode;
}
catch (std::exception& e)
{
std::cerr << "ERROR: " << e.what() << std::endl;
return 0;
}
}
}

@ -0,0 +1,25 @@
#include <signal.h>
#include <SDL.h>
#include <SDL_video.h>
bool initSDL()
{
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
SDL_SetMainReady();
// Required for determining screen resolution and such on the Graphics tab
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
return false;
}
signal(SIGINT, SIG_DFL); // We don't want to use the SDL event loop in the launcher,
// so reset SIGINT which SDL wants to redirect to an SDL_Quit event.
return true;
}
void quitSDL()
{
// Disconnect from SDL processes
SDL_Quit();
}

@ -0,0 +1,8 @@
#ifndef SDLINIT_H
#define SDLINIT_H
bool initSDL();
void quitSDL();
#endif

@ -5,11 +5,8 @@
#include <QLocalSocket>
#include <QMessageBox>
#include <components/crashcatcher/crashcatcher.hpp>
#include <components/debug/debuglog.hpp>
#include <components/fallback/validate.hpp>
#include <components/nifosg/nifloader.hpp>
#include "model/doc/document.hpp"
@ -27,10 +24,6 @@ CS::Editor::Editor (int argc, char **argv)
mLock(), mMerge (mDocumentManager),
mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL)
{
// install the crash handler as soon as possible. note that the log path
// does not depend on config being read.
crashCatcherInstall(argc, argv, (mCfgMgr.getLogPath() / "openmw-cs-crash.log").string());
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig();
setupDataFiles (config.first);
@ -301,7 +294,7 @@ bool CS::Editor::makeIPCServer()
mLock = boost::interprocess::file_lock(mPid.string().c_str());
if(!mLock.try_lock())
{
std::cerr << "OpenCS already running." << std::endl;
Log(Debug::Error) << "Error: OpenMW-CS is already running.";
return false;
}
@ -324,17 +317,17 @@ bool CS::Editor::makeIPCServer()
if(boost::filesystem::exists(fullPath.toUtf8().constData()))
{
// TODO: compare pid of the current process with that in the file
std::cout << "Detected unclean shutdown." << std::endl;
Log(Debug::Info) << "Detected unclean shutdown.";
// delete the stale file
if(remove(fullPath.toUtf8().constData()))
std::cerr << "ERROR removing stale connection file" << std::endl;
Log(Debug::Error) << "Error: can not remove stale connection file.";
}
}
}
catch(const std::exception& e)
{
std::cerr << "ERROR " << e.what() << std::endl;
Log(Debug::Error) << "Error: " << e.what();
return false;
}

@ -1,14 +1,13 @@
#include "editor.hpp"
#include <exception>
#include <iostream>
#include <string>
#include <QApplication>
#include <QIcon>
#include <QMetaType>
#include <components/misc/debugging.hpp>
#include <components/debug/debugging.hpp>
#include "model/doc/messages.hpp"
#include "model/world/universalid.hpp"
@ -31,7 +30,7 @@ class Application : public QApplication
}
catch (const std::exception& exception)
{
std::cerr << "An exception has been caught: " << exception.what() << std::endl;
Log(Debug::Error) << "An exception has been caught: " << exception.what();
}
return false;
@ -80,5 +79,5 @@ int runApplication(int argc, char *argv[])
int main(int argc, char *argv[])
{
return wrapApplication(&runApplication, argc, argv, "/openmw-cs.log");
return wrapApplication(&runApplication, argc, argv, "OpenMW-CS");
}

@ -2,7 +2,6 @@
#include <cassert>
#include <fstream>
#include <iostream>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
@ -13,6 +12,8 @@
#include <components/files/configurationmanager.hpp>
#endif
#include <components/debug/debuglog.hpp>
void CSMDoc::Document::addGmsts()
{
for (size_t i=0; i < CSMWorld::DefaultGmsts::FloatCount; ++i)
@ -435,7 +436,7 @@ void CSMDoc::Document::modificationStateChanged (bool clean)
void CSMDoc::Document::reportMessage (const CSMDoc::Message& message, int type)
{
/// \todo find a better way to get these messages to the user.
std::cout << message.mMessage << std::endl;
Log(Debug::Info) << message.mMessage;
}
void CSMDoc::Document::operationDone2 (int type, bool failed)

@ -1,8 +1,8 @@
#include "refcollection.hpp"
#include <sstream>
#include <iostream>
#include <components/debug/debuglog.hpp>
#include <components/misc/stringops.hpp>
#include <components/esm/loadcell.hpp>
@ -58,10 +58,10 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
// message
if (index.first != mref.mTarget[0] || index.second != mref.mTarget[1])
{
std::cerr << "The Position of moved ref "
<< ref.mRefID << " does not match the target cell" << std::endl;
std::cerr << "Position: #" << index.first << " " << index.second
<<", Target #"<< mref.mTarget[0] << " " << mref.mTarget[1] << std::endl;
Log(Debug::Warning) << "Warning: the Position of moved ref "
<< ref.mRefID << " does not match the target cell";
Log(Debug::Warning) << "Position: #" << index.first << " " << index.second
<<", Target #"<< mref.mTarget[0] << " " << mref.mTarget[1];
stream.clear();
stream << "#" << mref.mTarget[0] << " " << mref.mTarget[1];

@ -1,7 +1,6 @@
#include "object.hpp"
#include <stdexcept>
#include <iostream>
#include <osg/Depth>
#include <osg/Group>
@ -24,6 +23,7 @@
#include "../../model/world/cellcoordinates.hpp"
#include "../../model/prefs/state.hpp"
#include <components/debug/debuglog.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/sceneutil/lightutil.hpp>
#include <components/sceneutil/lightmanager.hpp>
@ -133,7 +133,7 @@ void CSVRender::Object::update()
catch (std::exception& e)
{
// TODO: use error marker mesh
std::cerr << e.what() << std::endl;
Log(Debug::Error) << e.what();
}
}

@ -10,6 +10,8 @@
#include <SDL.h>
#include <components/debug/debuglog.hpp>
#include <components/misc/rng.hpp>
#include <components/vfs/manager.hpp>
@ -61,7 +63,7 @@ namespace
void checkSDLError(int ret)
{
if (ret != 0)
std::cerr << "SDL error: " << SDL_GetError() << std::endl;
Log(Debug::Error) << "SDL error: " << SDL_GetError();
}
}
@ -189,7 +191,7 @@ bool OMW::Engine::frame(float frametime)
}
catch (const std::exception& e)
{
std::cerr << "Error in frame: " << e.what() << std::endl;
Log(Debug::Error) << "Error in frame: " << e.what();
}
return true;
}
@ -364,7 +366,7 @@ void OMW::Engine::createWindow(Settings::Manager& settings)
// Try with a lower AA
if (antialiasing > 0)
{
std::cout << "Note: " << antialiasing << "x antialiasing not supported, trying " << antialiasing/2 << std::endl;
Log(Debug::Warning) << "Warning: " << antialiasing << "x antialiasing not supported, trying " << antialiasing/2;
antialiasing /= 2;
Settings::Manager::setInt("antialiasing", "Video", antialiasing);
checkSDLError(SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antialiasing));
@ -373,7 +375,7 @@ void OMW::Engine::createWindow(Settings::Manager& settings)
else
{
std::stringstream error;
error << "Failed to create SDL window: " << SDL_GetError() << std::endl;
error << "Failed to create SDL window: " << SDL_GetError();
throw std::runtime_error(error.str());
}
}
@ -420,16 +422,16 @@ void OMW::Engine::setWindowIcon()
std::string windowIcon = (mResDir / "mygui" / "openmw.png").string();
windowIconStream.open(windowIcon, std::ios_base::in | std::ios_base::binary);
if (windowIconStream.fail())
std::cerr << "Error: Failed to open " << windowIcon << std::endl;
Log(Debug::Error) << "Error: Failed to open " << windowIcon;
osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png");
if (!reader)
{
std::cerr << "Error: Failed to read window icon, no png readerwriter found" << std::endl;
Log(Debug::Error) << "Error: Failed to read window icon, no png readerwriter found";
return;
}
osgDB::ReaderWriter::ReadResult result = reader->readImage(windowIconStream);
if (!result.success())
std::cerr << "Error: Failed to read " << windowIcon << ": " << result.message() << " code " << result.status() << std::endl;
Log(Debug::Error) << "Error: Failed to read " << windowIcon << ": " << result.message() << " code " << result.status();
else
{
osg::ref_ptr<osg::Image> image = result.getImage();
@ -564,21 +566,19 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
{
std::pair<int, int> result = mEnvironment.getScriptManager()->compileAll();
if (result.first)
std::cout
Log(Debug::Info)
<< "compiled " << result.second << " of " << result.first << " scripts ("
<< 100*static_cast<double> (result.second)/result.first
<< "%)"
<< std::endl;
<< "%)";
}
if (mCompileAllDialogue)
{
std::pair<int, int> result = MWDialogue::ScriptTest::compileAll(&mExtensions, mWarningsMode);
if (result.first)
std::cout
Log(Debug::Info)
<< "compiled " << result.second << " of " << result.first << " dialogue script/actor combinations a("
<< 100*static_cast<double> (result.second)/result.first
<< "%)"
<< std::endl;
<< "%)";
}
}
@ -614,14 +614,14 @@ public:
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension(mScreenshotFormat);
if (!readerwriter)
{
std::cerr << "Error: Can't write screenshot, no '" << mScreenshotFormat << "' readerwriter found" << std::endl;
Log(Debug::Error) << "Error: Can't write screenshot, no '" << mScreenshotFormat << "' readerwriter found";
return;
}
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(image, outStream);
if (!result.success())
{
std::cerr << "Error: Can't write screenshot: " << result.message() << " code " << result.status() << std::endl;
Log(Debug::Error) << "Error: Can't write screenshot: " << result.message() << " code " << result.status();
}
}
@ -636,7 +636,7 @@ void OMW::Engine::go()
{
assert (!mContentFiles.empty());
std::cout << "OSG version: " << osgGetVersion() << std::endl;
Log(Debug::Info) << "OSG version: " << osgGetVersion();
// Load settings
Settings::Manager settings;
@ -738,7 +738,7 @@ void OMW::Engine::go()
// Save user settings
settings.saveUser(settingspath);
std::cout << "Quitting peacefully." << std::endl;
Log(Debug::Info) << "Quitting peacefully.";
}
void OMW::Engine::setCompileAll (bool all)

@ -1,11 +1,8 @@
#include <iostream>
#include <components/version/version.hpp>
#include <components/crashcatcher/crashcatcher.hpp>
#include <components/files/configurationmanager.hpp>
#include <components/files/escape.hpp>
#include <components/fallback/validate.hpp>
#include <components/misc/debugging.hpp>
#include <components/debug/debugging.hpp>
#include "engine.hpp"
@ -203,8 +200,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
StringsVector content = variables["content"].as<Files::EscapeStringVector>().toStdStringVector();
if (content.empty())
{
std::cout << "No content file given (esm/esp, nor omwgame/omwaddon). Aborting..." << std::endl;
return false;
Log(Debug::Error) << "No content file given (esm/esp, nor omwgame/omwaddon). Aborting...";
return false;
}
StringsVector::const_iterator it(content.begin());
@ -218,7 +215,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
engine.setCell(variables["start"].as<Files::EscapeHashString>().toStdString());
engine.setSkipMenu (variables["skip-menu"].as<bool>(), variables["new-game"].as<bool>());
if (!variables["skip-menu"].as<bool>() && variables["new-game"].as<bool>())
std::cerr << "Warning: new-game used without skip-menu -> ignoring it" << std::endl;
Log(Debug::Warning) << "Warning: new-game used without skip-menu -> ignoring it";
// scripts
engine.setCompileAll(variables["script-all"].as<bool>());
@ -265,7 +262,7 @@ extern "C" int SDL_main(int argc, char**argv)
int main(int argc, char**argv)
#endif
{
return wrapApplication(&runApplication, argc, argv, "/openmw.log");
return wrapApplication(&runApplication, argc, argv, "OpenMW");
}
// Platform specific for Windows when there is no console built into the executable.

@ -566,6 +566,9 @@ namespace MWBase
virtual bool isPlayerInJail() const = 0;
virtual void setPlayerTraveling(bool traveling) = 0;
virtual bool isPlayerTraveling() const = 0;
virtual void rotateWorldObject (const MWWorld::Ptr& ptr, osg::Quat rotate) = 0;
/// Return terrain height at \a worldPos position.

@ -1,7 +1,7 @@
#include "creature.hpp"
#include <components/misc/rng.hpp>
#include <components/debug/debuglog.hpp>
#include <components/esm/loadcrea.hpp>
#include <components/esm/creaturestate.hpp>
#include <components/settings/settings.hpp>
@ -146,7 +146,7 @@ namespace MWClass
if (const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(*iter))
data->mCreatureStats.getSpells().add (spell);
else /// \todo add option to make this a fatal error message pop-up, but default to warning for vanilla compatibility
std::cerr << "Warning: ignoring nonexistent spell '" << *iter << "' on creature '" << ref->mBase->mId << "'" << std::endl;
Log(Debug::Warning) << "Warning: ignoring nonexistent spell '" << *iter << "' on creature '" << ref->mBase->mId << "'";
}
// inventory

@ -4,6 +4,7 @@
#include <components/misc/rng.hpp>
#include <components/debug/debuglog.hpp>
#include <components/esm/loadmgef.hpp>
#include <components/esm/loadnpc.hpp>
#include <components/esm/npcstate.hpp>
@ -365,7 +366,7 @@ namespace MWClass
if (const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(*iter))
data->mNpcStats.getSpells().add (spell);
else
std::cerr << "Warning: ignoring nonexistent race power '" << *iter << "' on NPC '" << ref->mBase->mId << "'" << std::endl;
Log(Debug::Warning) << "Warning: ignoring nonexistent race power '" << *iter << "' on NPC '" << ref->mBase->mId << "'";
}
if (!ref->mBase->mFaction.empty())
@ -395,7 +396,7 @@ namespace MWClass
else
{
/// \todo add option to make this a fatal error message pop-up, but default to warning for vanilla compatibility
std::cerr << "Warning: ignoring nonexistent spell '" << *iter << "' on NPC '" << ref->mBase->mId << "'" << std::endl;
Log(Debug::Warning) << "Warning: ignoring nonexistent spell '" << *iter << "' on NPC '" << ref->mBase->mId << "'";
}
}

@ -5,7 +5,8 @@
#include <algorithm>
#include <iterator>
#include <list>
#include <iostream>
#include <components/debug/debuglog.hpp>
#include <components/esm/loaddial.hpp>
#include <components/esm/loadinfo.hpp>
@ -203,16 +204,14 @@ namespace MWDialogue
}
catch (const std::exception& error)
{
std::cerr << std::string ("Dialogue error: An exception has been thrown: ") + error.what() << std::endl;
Log(Debug::Error) << std::string ("Dialogue error: An exception has been thrown: ") + error.what();
success = false;
}
if (!success)
{
std::cerr
<< "Warning: compiling failed (dialogue script)" << std::endl
<< cmd
<< std::endl << std::endl;
Log(Debug::Warning)
<< "Warning: compiling failed (dialogue script)\n" << cmd << "\n\n";
}
return success;
@ -232,7 +231,7 @@ namespace MWDialogue
}
catch (const std::exception& error)
{
std::cerr << std::string ("Dialogue error: An exception has been thrown: ") + error.what() << std::endl;
Log(Debug::Error) << std::string ("Dialogue error: An exception has been thrown: ") + error.what();
}
}
}

@ -1,7 +1,5 @@
#include "scripttest.hpp"
#include <iostream>
#include "../mwworld/manualref.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/class.hpp"
@ -12,6 +10,7 @@
#include "../mwscript/compilercontext.hpp"
#include <components/debug/debuglog.hpp>
#include <components/compiler/exception.hpp>
#include <components/compiler/streamerrorhandler.hpp>
#include <components/compiler/scanner.hpp>
@ -80,16 +79,14 @@ void test(const MWWorld::Ptr& actor, int &compiled, int &total, const Compiler::
}
catch (const std::exception& error)
{
std::cerr << std::string ("Dialogue error: An exception has been thrown: ") + error.what() << std::endl;
Log(Debug::Error) << std::string ("Dialogue error: An exception has been thrown: ") + error.what();
success = false;
}
if (!success)
{
std::cerr
<< "compiling failed (dialogue script)" << std::endl
<< info->mResultScript
<< std::endl << std::endl;
Log(Debug::Warning)
<< "compiling failed (dialogue script)\n" << info->mResultScript << "\n\n";
}
}
}

@ -1,5 +1,6 @@
#include "charactercreation.hpp"
#include <components/debug/debuglog.hpp>
#include <components/fallback/fallback.hpp>
#include "../mwbase/environment.hpp"
@ -284,7 +285,7 @@ namespace MWGui
}
catch (std::exception& e)
{
std::cerr << "Error: Failed to create chargen window: " << e.what() << std::endl;
Log(Debug::Error) << "Error: Failed to create chargen window: " << e.what();
}
}
@ -602,7 +603,7 @@ namespace MWGui
mGenerateClass = "Mage";
else
{
std::cout << "Failed to deduce class from chosen answers in generate class dialog" << std::endl;
Log(Debug::Warning) << "Failed to deduce class from chosen answers in generate class dialog.";
mGenerateClass = "Thief";
}
}

@ -12,6 +12,8 @@
#include "../mwworld/esmstore.hpp"
#include <components/debug/debuglog.hpp>
#include "tooltips.hpp"
namespace
@ -924,7 +926,7 @@ namespace MWGui
std::string classImage = std::string("textures\\levelup\\") + classId + ".dds";
if (!MWBase::Environment::get().getWindowManager()->textureExists(classImage))
{
std::cout << "No class image for " << classId << ", falling back to default" << std::endl;
Log(Debug::Warning) << "No class image for " << classId << ", falling back to default";
classImage = "textures\\levelup\\warrior.dds";
}
imageBox->setImageTexture(classImage);

@ -6,6 +6,7 @@
#include <MyGUI_ScrollBar.h>
#include <MyGUI_Button.h>
#include <components/debug/debuglog.hpp>
#include <components/widgets/list.hpp>
#include <components/translation/translation.hpp>
@ -411,7 +412,7 @@ namespace MWGui
{
if (!actor.getClass().isActor())
{
std::cerr << "Warning: can not talk with non-actor object." << std::endl;
Log(Debug::Warning) << "Warning: can not talk with non-actor object.";
return;
}

@ -13,6 +13,7 @@
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <components/debug/debuglog.hpp>
#include <components/interpreter/defines.hpp>
#include <components/misc/stringops.hpp>
@ -300,7 +301,7 @@ namespace MWGui
if (!exists)
{
std::cerr << "Warning: Could not find \"" << src << "\" referenced by an <img> tag." << std::endl;
Log(Debug::Warning) << "Warning: Could not find \"" << src << "\" referenced by an <img> tag.";
break;
}

@ -517,7 +517,7 @@ namespace MWGui
// Give the script a chance to run once before we do anything else
// this is important when setting pcskipequip as a reaction to onpcequip being set (bk_treasuryreport does this)
if (!script.empty() && MWBase::Environment::get().getWorld()->getScriptsEnabled())
if (!force && !script.empty() && MWBase::Environment::get().getWorld()->getScriptsEnabled())
{
MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr);
MWBase::Environment::get().getScriptManager()->run (script, interpreterContext);

@ -10,9 +10,8 @@
#include <MyGUI_TextBox.h>
#include <components/misc/rng.hpp>
#include <components/debug/debuglog.hpp>
#include <components/myguiplatform/myguitexture.hpp>
#include <components/settings/settings.hpp>
#include <components/vfs/manager.hpp>
@ -94,7 +93,7 @@ namespace MWGui
++found;
}
if (mSplashScreens.empty())
std::cerr << "No splash screens found!" << std::endl;
Log(Debug::Warning) << "Warning: no splash screens found!";
}
void LoadingScreen::setLabel(const std::string &label, bool important)
@ -170,12 +169,18 @@ namespace MWGui
// We are already using node masks to avoid the scene from being updated/rendered, but node masks don't work for computeBound()
mViewer->getSceneData()->setComputeBoundingSphereCallback(new DontComputeBoundCallback);
mShowWallpaper = visible && (MWBase::Environment::get().getStateManager()->getState()
== MWBase::StateManager::State_NoGame);
if (!visible)
{
draw();
return;
}
mVisible = visible;
mLoadingBox->setVisible(mVisible);
mShowWallpaper = mVisible && (MWBase::Environment::get().getStateManager()->getState()
== MWBase::StateManager::State_NoGame);
setVisible(true);
if (mShowWallpaper)
@ -184,9 +189,6 @@ namespace MWGui
}
MWBase::Environment::get().getWindowManager()->pushGuiMode(mShowWallpaper ? GM_LoadingWallpaper : GM_Loading);
if (!mVisible)
draw();
}
void LoadingScreen::loadingOff()

@ -5,6 +5,7 @@
#include <MyGUI_RenderManager.h>
#include <MyGUI_Button.h>
#include <components/debug/debuglog.hpp>
#include <components/misc/stringops.hpp>
#include "../mwbase/environment.hpp"
@ -125,7 +126,7 @@ namespace MWGui
{
if (mInterMessageBoxe != NULL)
{
std::cerr << "Warning: replacing an interactive message box that was not answered yet" << std::endl;
Log(Debug::Warning) << "Warning: replacing an interactive message box that was not answered yet";
mInterMessageBoxe->setVisible(false);
delete mInterMessageBoxe;
mInterMessageBoxe = NULL;

@ -6,6 +6,7 @@
#include <osg/Texture2D>
#include <components/debug/debuglog.hpp>
#include <components/myguiplatform/myguitexture.hpp>
#include "../mwworld/esmstore.hpp"
@ -340,7 +341,7 @@ namespace MWGui
}
catch (std::exception& e)
{
std::cerr << "Error creating preview: " << e.what() << std::endl;
Log(Debug::Error) << "Error creating preview: " << e.what();
}
}

@ -12,6 +12,8 @@
#include <osgDB/ReadFile>
#include <osg/Texture2D>
#include <components/debug/debuglog.hpp>
#include <components/myguiplatform/myguitexture.hpp>
#include <components/misc/stringops.hpp>
@ -438,14 +440,14 @@ namespace MWGui
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("jpg");
if (!readerwriter)
{
std::cerr << "Error: Can't open savegame screenshot, no jpg readerwriter found" << std::endl;
Log(Debug::Error) << "Error: Can't open savegame screenshot, no jpg readerwriter found";
return;
}
osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(instream);
if (!result.success())
{
std::cerr << "Error: Failed to read savegame screenshot: " << result.message() << " code " << result.status() << std::endl;
Log(Debug::Error) << "Error: Failed to read savegame screenshot: " << result.message() << " code " << result.status();
return;
}

@ -12,6 +12,7 @@
#include <SDL_video.h>
#include <components/debug/debuglog.hpp>
#include <components/widgets/sharedstatebutton.hpp>
#include <components/settings/settings.hpp>
@ -31,7 +32,8 @@ namespace
if (val == "linear") return "Trilinear";
if (val == "nearest") return "Bilinear";
if (val != "none")
std::cerr<< "Warning: Invalid texture mipmap option: "<<val <<std::endl;
Log(Debug::Warning) << "Warning: Invalid texture mipmap option: "<< val;
return "Other";
}
@ -398,7 +400,7 @@ namespace MWGui
else if(pos == 1)
Settings::Manager::setString("texture mipmap", "General", "linear");
else
std::cerr<< "Unexpected option pos "<<pos <<std::endl;
Log(Debug::Warning) << "Unexpected option pos " << pos;
apply();
}

@ -1,9 +1,7 @@
#include "sortfilteritemmodel.hpp"
#include <iostream>
#include <components/misc/stringops.hpp>
#include <components/debug/debuglog.hpp>
#include <components/esm/loadalch.hpp>
#include <components/esm/loadappa.hpp>
#include <components/esm/loadarmo.hpp>
@ -245,7 +243,7 @@ namespace MWGui
const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(enchId);
if (!ench)
{
std::cerr << "Warning: Can't find enchantment '" << enchId << "' on item " << base.getCellRef().getRefId() << std::endl;
Log(Debug::Warning) << "Warning: Can't find enchantment '" << enchId << "' on item " << base.getCellRef().getRefId();
return false;
}

@ -1,6 +1,6 @@
#include "spellmodel.hpp"
#include <iostream>
#include <components/debug/debuglog.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -94,7 +94,7 @@ namespace MWGui
const ESM::Enchantment* enchant = esmStore.get<ESM::Enchantment>().search(enchantId);
if (!enchant)
{
std::cerr << "Warning: Can't find enchantment '" << enchantId << "' on item " << item.getCellRef().getRefId() << std::endl;
Log(Debug::Warning) << "Warning: Can't find enchantment '" << enchantId << "' on item " << item.getCellRef().getRefId();
continue;
}

@ -46,7 +46,7 @@ namespace MWGui
mSelect->getHeight());
}
void TravelWindow::addDestination(const std::string& name,ESM::Position pos,bool interior)
void TravelWindow::addDestination(const std::string& name, ESM::Position pos, bool interior)
{
int price;
@ -56,7 +56,7 @@ namespace MWGui
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId);
if(interior)
if (!mPtr.getCell()->isExterior())
{
price = gmst.find("fMagesGuildTravel")->getInt();
}
@ -154,6 +154,10 @@ namespace MWGui
if (playerGold<price)
return;
// Set "traveling" flag, so GetPCTraveling can detect teleportation.
// We will reset this flag during next world update.
MWBase::Environment::get().getWorld()->setPlayerTraveling(true);
if (!mPtr.getCell()->isExterior())
// Interior cell -> mages guild transport
MWBase::Environment::get().getWindowManager()->playSound("mysticism cast");
@ -168,7 +172,7 @@ namespace MWGui
ESM::Position pos = *_sender->getUserData<ESM::Position>();
std::string cellname = _sender->getUserString("Destination");
bool interior = _sender->getUserString("interior") == "y";
if (!interior)
if (mPtr.getCell()->isExterior())
{
ESM::Position playerPos = player.getRefData().getPosition();
float d = (osg::Vec3f(pos.pos[0], pos.pos[1], 0) - osg::Vec3f(playerPos.pos[0], playerPos.pos[1], 0)).length();

@ -6,6 +6,7 @@
#include <osg/Texture2D>
#include <components/debug/debuglog.hpp>
#include <components/vfs/manager.hpp>
#include <components/myguiplatform/myguitexture.hpp>
@ -37,7 +38,7 @@ void VideoWidget::playVideo(const std::string &video)
}
catch (std::exception& e)
{
std::cerr << "Failed to open video: " << e.what() << std::endl;
Log(Debug::Error) << "Failed to open video: " << e.what();
return;
}

@ -21,6 +21,8 @@
#include <SDL_keyboard.h>
#include <SDL_clipboard.h>
#include <components/debug/debuglog.hpp>
#include <components/sdlutil/sdlcursormanager.hpp>
#include <components/esm/esmreader.hpp>
@ -1082,7 +1084,7 @@ namespace MWGui
{
if (!mStore)
{
std::cerr << "Error: WindowManager::onRetrieveTag: no Store set up yet, can not replace '" << tag << "'" << std::endl;
Log(Debug::Error) << "Error: WindowManager::onRetrieveTag: no Store set up yet, can not replace '" << tag << "'";
return;
}
const ESM::GameSetting *setting = mStore->get<ESM::GameSetting>().find(tag);
@ -1788,7 +1790,7 @@ namespace MWGui
if (found != mCurrentModals.end())
mCurrentModals.erase(found);
else
std::cerr << " warning: can't find modal window " << input << std::endl;
Log(Debug::Warning) << "Warning: can't find modal window " << input;
}
}
if (mCurrentModals.empty())

@ -10,6 +10,7 @@
#include <SDL_version.h>
#include <components/debug/debuglog.hpp>
#include <components/sdlutil/sdlinputwrapper.hpp>
#include <components/sdlutil/sdlvideowrapper.hpp>
#include <components/esm/esmwriter.hpp>
@ -120,11 +121,11 @@ namespace MWInput
SDL_ControllerDeviceEvent evt;
evt.which = i;
controllerAdded(mFakeDeviceID, evt);
std::cout << "Detected game controller: " << SDL_GameControllerNameForIndex(i) << std::endl;
Log(Debug::Info) << "Detected game controller: " << SDL_GameControllerNameForIndex(i);
}
else
{
std::cout << "Detected unusable controller: " << SDL_JoystickNameForIndex(i) << std::endl;
Log(Debug::Info) << "Detected unusable controller: " << SDL_JoystickNameForIndex(i);
}
}

@ -2,13 +2,12 @@
#include <typeinfo>
#include <iostream>
#include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp>
#include <components/esm/loadnpc.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
#include <components/debug/debuglog.hpp>
#include <components/settings/settings.hpp>
#include "../mwworld/esmstore.hpp"
@ -404,7 +403,7 @@ namespace MWMechanics
std::set<MWWorld::Ptr> playerAllies;
getActorsSidingWith(MWMechanics::getPlayer(), playerAllies, cachedAllies);
bool isPlayerFollowerOrEscorter = std::find(playerAllies.begin(), playerAllies.end(), actor1) != playerAllies.end();
bool isPlayerFollowerOrEscorter = playerAllies.find(actor1) != playerAllies.end();
// If actor2 and at least one actor2 are in combat with actor1, actor1 and its allies start combat with them
// Doesn't apply for player followers/escorters
@ -458,7 +457,7 @@ namespace MWMechanics
// Do aggression check if actor2 is the player or a player follower or escorter
if (!aggressive)
{
if (againstPlayer || std::find(playerAllies.begin(), playerAllies.end(), actor2) != playerAllies.end())
if (againstPlayer || playerAllies.find(actor2) != playerAllies.end())
{
// Player followers and escorters with high fight should not initiate combat with the player or with
// other player followers or escorters
@ -546,7 +545,7 @@ namespace MWMechanics
float diff = (static_cast<int>(magickaFactor*intelligence)) - magicka.getBase();
float currentToBaseRatio = (magicka.getCurrent() / magicka.getBase());
magicka.setModified(magicka.getModified() + diff, 0);
magicka.setCurrent(magicka.getBase() * currentToBaseRatio);
magicka.setCurrent(magicka.getBase() * currentToBaseRatio, false, true);
creatureStats.setMagicka(magicka);
}
@ -577,8 +576,14 @@ namespace MWMechanics
float normalizedEncumbrance = ptr.getClass().getNormalizedEncumbrance(ptr);
if (normalizedEncumbrance > 1)
normalizedEncumbrance = 1;
// Current fatigue can be above base value due to a fortify effect.
// In that case stop here and don't try to restore.
DynamicStat<float> fatigue = stats.getFatigue();
if (fatigue.getCurrent() >= fatigue.getBase())
return;
// restore fatigue
// Restore fatigue
float fFatigueReturnBase = settings.find("fFatigueReturnBase")->getFloat ();
float fFatigueReturnMult = settings.find("fFatigueReturnMult")->getFloat ();
float fEndFatigueMult = settings.find("fEndFatigueMult")->getFloat ();
@ -586,7 +591,6 @@ namespace MWMechanics
float x = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance);
x *= fEndFatigueMult * endurance;
DynamicStat<float> fatigue = stats.getFatigue();
fatigue.setCurrent (fatigue.getCurrent() + 3600 * x);
stats.setFatigue (fatigue);
}
@ -598,16 +602,20 @@ namespace MWMechanics
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats (ptr);
int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
// Current fatigue can be above base value due to a fortify effect.
// In that case stop here and don't try to restore.
DynamicStat<float> fatigue = stats.getFatigue();
if (fatigue.getCurrent() >= fatigue.getBase())
return;
// restore fatigue
// Restore fatigue
int endurance = stats.getAttribute(ESM::Attribute::Endurance).getModified();
const MWWorld::Store<ESM::GameSetting>& settings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
static const float fFatigueReturnBase = settings.find("fFatigueReturnBase")->getFloat ();
static const float fFatigueReturnMult = settings.find("fFatigueReturnMult")->getFloat ();
float x = fFatigueReturnBase + fFatigueReturnMult * endurance;
DynamicStat<float> fatigue = stats.getFatigue();
fatigue.setCurrent (fatigue.getCurrent() + duration * x);
stats.setFatigue (fatigue);
}
@ -688,6 +696,19 @@ namespace MWMechanics
}
}
// dynamic stats
for (int i = 0; i < 3; ++i)
{
DynamicStat<float> stat = creatureStats.getDynamic(i);
stat.setCurrentModifier(effects.get(ESM::MagicEffect::FortifyHealth + i).getMagnitude() -
effects.get(ESM::MagicEffect::DrainHealth + i).getMagnitude(),
// Magicka can be decreased below zero due to a fortify effect wearing off
// Fatigue can be decreased below zero meaning the actor will be knocked out
i == 1 || i == 2);
creatureStats.setDynamic(i, stat);
}
// attributes
for(int i = 0;i < ESM::Attribute::Length;++i)
{
@ -719,19 +740,6 @@ namespace MWMechanics
}
}
// dynamic stats
for(int i = 0;i < 3;++i)
{
DynamicStat<float> stat = creatureStats.getDynamic(i);
stat.setModifier(effects.get(ESM::MagicEffect::FortifyHealth+i).getMagnitude() -
effects.get(ESM::MagicEffect::DrainHealth+i).getMagnitude(),
// Magicka can be decreased below zero due to a fortify effect wearing off
// Fatigue can be decreased below zero meaning the actor will be knocked out
i == 1 || i == 2);
creatureStats.setDynamic(i, stat);
}
// AI setting modifiers
int creature = !ptr.getClass().isNpc();
if (creature && ptr.get<ESM::Creature>()->mBase->mData.mType == ESM::Creature::Humanoid)
@ -1298,6 +1306,8 @@ namespace MWMechanics
// AI and magic effects update
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
{
bool isPlayer = iter->first == player;
float distSqr = (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2();
// AI processing is only done within distance of 7168 units to the player. Note the "AI distance" slider doesn't affect this
// (it only does some throttling for targets beyond the "AI distance", so doesn't give any guarantees as to whether AI will be enabled or not)
@ -1305,7 +1315,7 @@ namespace MWMechanics
// using higher values will make a quest in Bloodmoon harder or impossible to complete (bug #1876)
bool inProcessingRange = distSqr <= sqrAiProcessingDistance;
if (iter->first == player)
if (isPlayer)
iter->second->getCharacterController()->setAttackingOrSpell(MWBase::Environment::get().getWorld()->getPlayer().getAttackingOrSpell());
// If dead or no longer in combat, no longer store any actors who attempted to hit us. Also remove for the player.
@ -1337,12 +1347,12 @@ namespace MWMechanics
{
if (timerUpdateAITargets == 0)
{
if (iter->first != player)
if (!isPlayer)
adjustCommandedActor(iter->first);
for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it)
{
if (it->first == iter->first || iter->first == player) // player is not AI-controlled
if (it->first == iter->first || isPlayer) // player is not AI-controlled
continue;
engageCombat(iter->first, it->first, cachedAllies, it->first == player);
}
@ -1353,12 +1363,15 @@ namespace MWMechanics
MWWorld::Ptr headTrackTarget;
MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first);
bool firstPersonPlayer = isPlayer && MWBase::Environment::get().getWorld()->isFirstPerson();
// Unconsious actor can not track target
// Also actors in combat and pursue mode do not bother to headtrack
// 1. Unconsious actor can not track target
// 2. Actors in combat and pursue mode do not bother to headtrack
// 3. Player character does not use headtracking in the 1st-person view
if (!stats.getKnockedDown() &&
!stats.getAiSequence().isInCombat() &&
!stats.getAiSequence().hasPackage(AiPackage::TypeIdPursue))
!stats.getAiSequence().hasPackage(AiPackage::TypeIdPursue) &&
!firstPersonPlayer)
{
for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it)
{
@ -1715,7 +1728,7 @@ namespace MWMechanics
}
else
{
std::cerr<< "Warning: Actors::playAnimationGroup: Unable to find " << ptr.getCellRef().getRefId() << std::endl;
Log(Debug::Warning) << "Warning: Actors::playAnimationGroup: Unable to find " << ptr.getCellRef().getRefId();
return false;
}
}
@ -1763,38 +1776,35 @@ namespace MWMechanics
std::list<MWWorld::Ptr> Actors::getActorsSidingWith(const MWWorld::Ptr& actor)
{
std::list<MWWorld::Ptr> list;
for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
for(PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter)
{
const MWWorld::Class &cls = iter->first.getClass();
const CreatureStats &stats = cls.getCreatureStats(iter->first);
const MWWorld::Ptr &iteratedActor = iter->first;
if (iteratedActor == getPlayer())
continue;
const CreatureStats &stats = iteratedActor.getClass().getCreatureStats(iteratedActor);
if (stats.isDead())
continue;
// An actor counts as siding with this actor if Follow or Escort is the current AI package, or there are only Combat packages before the Follow/Escort package
for (std::list<MWMechanics::AiPackage*>::const_iterator it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it)
{
if ((*it)->sideWithTarget() && (*it)->getTarget() == actor)
{
list.push_back(iter->first);
break;
}
else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat)
break;
}
// An actor counts as siding with this actor if Follow or Escort is the current AI package, or there are only Combat and Wander packages before the Follow/Escort package
// Actors that are targeted by this actor's Follow or Escort packages also side with them
if (actor != getPlayer())
for (auto package = stats.getAiSequence().begin(); package != stats.getAiSequence().end(); ++package)
{
const CreatureStats &stats2 = actor.getClass().getCreatureStats(actor);
for (std::list<MWMechanics::AiPackage*>::const_iterator it2 = stats2.getAiSequence().begin(); it2 != stats2.getAiSequence().end(); ++it2)
const MWWorld::Ptr &target = (*package)->getTarget();
if ((*package)->sideWithTarget() && !target.isEmpty())
{
if ((*it2)->sideWithTarget() && !(*it2)->getTarget().isEmpty())
if (iteratedActor == actor)
{
list.push_back((*it2)->getTarget());
break;
list.push_back(target);
}
else if ((*it2)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat)
break;
else if (target == actor)
{
list.push_back(iteratedActor);
}
break;
}
else if ((*package)->getTypeId() != AiPackage::TypeIdCombat && (*package)->getTypeId() != AiPackage::TypeIdWander)
break;
}
}
return list;
@ -1805,17 +1815,21 @@ namespace MWMechanics
std::list<MWWorld::Ptr> list;
for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
{
const MWWorld::Class &cls = iter->first.getClass();
CreatureStats &stats = cls.getCreatureStats(iter->first);
const MWWorld::Ptr &iteratedActor = iter->first;
if (iteratedActor == getPlayer())
continue;
const CreatureStats &stats = iteratedActor.getClass().getCreatureStats(iteratedActor);
if (stats.isDead())
continue;
// An actor counts as following if AiFollow is the current AiPackage, or there are only Combat packages before the AiFollow package
for (std::list<MWMechanics::AiPackage*>::const_iterator it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it)
// An actor counts as following if AiFollow is the current AiPackage,
// or there are only Combat and Wander packages before the AiFollow package
for (auto package = stats.getAiSequence().begin(); package != stats.getAiSequence().end(); ++package)
{
if ((*it)->followTargetThroughDoors() && (*it)->getTarget() == actor)
list.push_back(iter->first);
else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat)
if ((*package)->followTargetThroughDoors() && (*package)->getTarget() == actor)
list.push_back(iteratedActor);
else if ((*package)->getTypeId() != AiPackage::TypeIdCombat && (*package)->getTypeId() != AiPackage::TypeIdWander)
break;
}
}
@ -1864,24 +1878,24 @@ namespace MWMechanics
std::list<int> list;
for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
{
const MWWorld::Class &cls = iter->first.getClass();
CreatureStats &stats = cls.getCreatureStats(iter->first);
const MWWorld::Ptr &iteratedActor = iter->first;
if (iteratedActor == getPlayer())
continue;
const CreatureStats &stats = iteratedActor.getClass().getCreatureStats(iteratedActor);
if (stats.isDead())
continue;
// An actor counts as following if AiFollow is the current AiPackage, or there are only Combat packages before the AiFollow package
for (std::list<MWMechanics::AiPackage*>::const_iterator it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it)
// An actor counts as following if AiFollow is the current AiPackage,
// or there are only Combat and Wander packages before the AiFollow package
for (auto package = stats.getAiSequence().begin(); package != stats.getAiSequence().end(); ++package)
{
if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow)
if ((*package)->followTargetThroughDoors() && (*package)->getTarget() == actor)
{
MWWorld::Ptr followTarget = (*it)->getTarget();
if (followTarget.isEmpty())
continue;
if (followTarget == actor)
list.push_back(static_cast<MWMechanics::AiFollow*>(*it)->getFollowIndex());
list.push_back(static_cast<AiFollow*>(*package)->getFollowIndex());
break;
}
else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat)
else if ((*package)->getTypeId() != AiPackage::TypeIdCombat && (*package)->getTypeId() != AiPackage::TypeIdWander)
break;
}
}
@ -1893,14 +1907,14 @@ namespace MWMechanics
std::vector<MWWorld::Ptr> neighbors;
osg::Vec3f position (actor.getRefData().getPosition().asVec3());
getObjectsInRange(position, aiProcessingDistance, neighbors);
for(std::vector<MWWorld::Ptr>::const_iterator iter(neighbors.begin());iter != neighbors.end();++iter)
for(auto neighbor = neighbors.begin(); neighbor != neighbors.end(); ++neighbor)
{
const MWWorld::Class &cls = iter->getClass();
const CreatureStats &stats = cls.getCreatureStats(*iter);
if (stats.isDead() || *iter == actor)
const CreatureStats &stats = neighbor->getClass().getCreatureStats(*neighbor);
if (stats.isDead() || *neighbor == actor)
continue;
if (stats.getAiSequence().isInCombat(actor))
list.push_front(*iter);
list.push_front(*neighbor);
}
return list;
}
@ -1912,15 +1926,18 @@ namespace MWMechanics
osg::Vec3f position (actor.getRefData().getPosition().asVec3());
getObjectsInRange(position, aiProcessingDistance, neighbors);
std::list<MWWorld::Ptr> followers = getActorsFollowing(actor);
for(std::vector<MWWorld::Ptr>::const_iterator iter(neighbors.begin());iter != neighbors.end();++iter)
std::set<MWWorld::Ptr> followers;
getActorsFollowing(actor, followers);
for (auto neighbor = neighbors.begin(); neighbor != neighbors.end(); ++neighbor)
{
const CreatureStats &stats = iter->getClass().getCreatureStats(*iter);
if (stats.isDead() || *iter == actor || iter->getClass().isPureWaterCreature(*iter))
const CreatureStats &stats = neighbor->getClass().getCreatureStats(*neighbor);
if (stats.isDead() || *neighbor == actor || neighbor->getClass().isPureWaterCreature(*neighbor))
continue;
const bool isFollower = std::find(followers.begin(), followers.end(), *iter) != followers.end();
if (stats.getAiSequence().isInCombat(actor) || (MWBase::Environment::get().getMechanicsManager()->isAggressive(*iter, actor) && !isFollower))
list.push_back(*iter);
const bool isFollower = followers.find(*neighbor) != followers.end();
if (stats.getAiSequence().isInCombat(actor) || (MWBase::Environment::get().getMechanicsManager()->isAggressive(*neighbor, actor) && !isFollower))
list.push_back(*neighbor);
}
return list;
}

@ -600,27 +600,26 @@ osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& t
float duration, int weapType, float strength)
{
float projSpeed;
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
// get projectile speed (depending on weapon type)
if (weapType == ESM::Weapon::MarksmanThrown)
{
static float fThrownWeaponMinSpeed =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fThrownWeaponMinSpeed")->getFloat();
static float fThrownWeaponMaxSpeed =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fThrownWeaponMaxSpeed")->getFloat();
static float fThrownWeaponMinSpeed = gmst.find("fThrownWeaponMinSpeed")->getFloat();
static float fThrownWeaponMaxSpeed = gmst.find("fThrownWeaponMaxSpeed")->getFloat();
projSpeed =
fThrownWeaponMinSpeed + (fThrownWeaponMaxSpeed - fThrownWeaponMinSpeed) * strength;
projSpeed = fThrownWeaponMinSpeed + (fThrownWeaponMaxSpeed - fThrownWeaponMinSpeed) * strength;
}
else
else if (weapType != 0)
{
static float fProjectileMinSpeed =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fProjectileMinSpeed")->getFloat();
static float fProjectileMaxSpeed =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fProjectileMaxSpeed")->getFloat();
static float fProjectileMinSpeed = gmst.find("fProjectileMinSpeed")->getFloat();
static float fProjectileMaxSpeed = gmst.find("fProjectileMaxSpeed")->getFloat();
projSpeed =
fProjectileMinSpeed + (fProjectileMaxSpeed - fProjectileMinSpeed) * strength;
projSpeed = fProjectileMinSpeed + (fProjectileMaxSpeed - fProjectileMinSpeed) * strength;
}
else // weapType is 0 ==> it's a target spell projectile
{
projSpeed = gmst.find("fTargetSpellMaxSpeed")->getFloat();
}
// idea: perpendicular to dir to target speed components of target move vector and projectile vector should be the same

@ -1,8 +1,8 @@
#include "aisequence.hpp"
#include <limits>
#include <iostream>
#include <components/debug/debuglog.hpp>
#include <components/esm/aisequence.hpp>
#include "../mwbase/environment.hpp"
@ -282,7 +282,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
}
catch (std::exception& e)
{
std::cerr << "Error during AiSequence::execute: " << e.what() << std::endl;
Log(Debug::Error) << "Error during AiSequence::execute: " << e.what();
}
}
}

@ -1,10 +1,9 @@
#include "aiwander.hpp"
#include <cfloat>
#include <iostream>
#include <components/debug/debuglog.hpp>
#include <components/misc/rng.hpp>
#include <components/esm/aisequence.hpp>
#include "../mwbase/world.hpp"
@ -24,8 +23,6 @@
#include "coordinateconverter.hpp"
#include "actorutil.hpp"
namespace MWMechanics
{
static const int COUNT_BEFORE_RESET = 10;
@ -677,7 +674,7 @@ namespace MWMechanics
}
else
{
std::cerr<< "Error: Attempted to play out of range idle animation \""<<idleSelect<<"\" for " << actor.getCellRef().getRefId() << std::endl;
Log(Debug::Verbose) << "Attempted to play out of range idle animation \"" << idleSelect << "\" for " << actor.getCellRef().getRefId();
return false;
}
}

@ -583,7 +583,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
refreshHitRecoilAnims();
const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType));
if (!mPtr.getClass().isBipedal(mPtr))
if (!mPtr.getClass().hasInventoryStore(mPtr))
weap = sWeaponTypeListEnd;
refreshJumpAnims(weap, jump, force);
@ -592,7 +592,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
// idle handled last as it can depend on the other states
// FIXME: if one of the below states is close to their last animation frame (i.e. will be disabled in the coming update),
// the idle animation should be displayed
if ((mUpperBodyState != UpperCharState_Nothing
if (((mUpperBodyState != UpperCharState_Nothing && mUpperBodyState != UpperCharState_WeapEquiped)
|| (mMovementState != CharState_None && !isTurning())
|| mHitState != CharState_None)
&& !mPtr.getClass().isBipedal(mPtr))
@ -773,6 +773,20 @@ void CharacterController::playRandomDeath(float startpoint)
playDeath(startpoint, mDeathState);
}
std::string CharacterController::chooseRandomAttackAnimation() const
{
std::string result;
bool isSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr);
if (isSwimming)
result = chooseRandomGroup("swimattack");
if (!isSwimming || !mAnimation->hasAnimation(result))
result = chooseRandomGroup("attack");
return result;
}
CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim)
: mPtr(ptr)
, mWeapon(MWWorld::Ptr())
@ -1123,16 +1137,10 @@ bool CharacterController::updateCreatureState()
else
mCurrentWeapon = "";
}
if (weapType != WeapType_Spell || !mAnimation->hasAnimation("spellcast")) // Not all creatures have a dedicated spellcast animation
{
bool isSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr);
int roll = Misc::Rng::rollDice(3); // [0, 2]
if (roll == 0)
mCurrentWeapon = isSwimming && mAnimation->hasAnimation("swimattack1") ? "swimattack1" : "attack1";
else if (roll == 1)
mCurrentWeapon = isSwimming && mAnimation->hasAnimation("swimattack2") ? "swimattack2" : "attack2";
else
mCurrentWeapon = isSwimming && mAnimation->hasAnimation("swimattack3") ? "swimattack3" : "attack3";
mCurrentWeapon = chooseRandomAttackAnimation();
}
if (!mCurrentWeapon.empty())
@ -1212,8 +1220,11 @@ bool CharacterController::updateWeaponState()
mWeapon = weapon != inv.end() ? *weapon : MWWorld::Ptr();
}
// Use blending only with 3d-person movement animations for bipedal actors
bool firstPersonPlayer = (mPtr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson());
MWRender::Animation::AnimPriority priorityWeapon(Priority_Weapon);
priorityWeapon[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody;
if (!firstPersonPlayer && mPtr.getClass().isBipedal(mPtr))
priorityWeapon[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody;
bool forcestateupdate = false;
@ -1239,6 +1250,10 @@ bool CharacterController::updateWeaponState()
MWRender::Animation::BlendMask_All, false,
1.0f, "unequip start", "unequip stop", 0.0f, 0);
mUpperBodyState = UpperCharState_UnEquipingWeap;
// If we do not have the "unequip detach" key, hide weapon manually.
if (mAnimation->getTextKeyTime(weapgroup+": unequip detach") < 0)
mAnimation->showWeapons(false);
}
if(!downSoundId.empty())
@ -1250,7 +1265,6 @@ bool CharacterController::updateWeaponState()
float complete;
bool animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete);
if (!animPlaying || complete >= 1.0f)
{
// Weapon is changed, no current animation (e.g. unequipping or attack).
@ -1273,6 +1287,13 @@ bool CharacterController::updateWeaponState()
MWRender::Animation::BlendMask_All, true,
1.0f, "equip start", "equip stop", 0.0f, 0);
mUpperBodyState = UpperCharState_EquipingWeap;
// If we do not have the "equip attach" key, show weapon manually.
if (weaptype != WeapType_Spell)
{
if (mAnimation->getTextKeyTime(weapgroup+": equip attach") < 0)
mAnimation->showWeapons(true);
}
}
}
@ -1358,18 +1379,20 @@ bool CharacterController::updateWeaponState()
{
MWWorld::Ptr player = getPlayer();
// We should reset player's idle animation in the first-person mode.
if (mPtr == player && MWBase::Environment::get().getWorld()->isFirstPerson())
mIdleState = CharState_None;
// In other cases we should not break swim and sneak animations
if (mIdleState != CharState_IdleSneak && mIdleState != CharState_IdleSwim)
mIdleState = CharState_None;
bool resetIdle = ammunition;
if(mUpperBodyState == UpperCharState_WeapEquiped && (mHitState == CharState_None || mHitState == CharState_Block))
{
MWBase::Environment::get().getWorld()->breakInvisibility(mPtr);
mAttackStrength = 0;
// Randomize attacks for non-bipedal creatures with Weapon flag
if (mPtr.getClass().getTypeName() == typeid(ESM::Creature).name() &&
!mPtr.getClass().isBipedal(mPtr) &&
(!mAnimation->hasAnimation(mCurrentWeapon) || isRandomAttackAnimation(mCurrentWeapon)))
{
mCurrentWeapon = chooseRandomAttackAnimation();
}
if(mWeaponType == WeapType_Spell)
{
// Unset casting flag, otherwise pressing the mouse button down would
@ -1417,19 +1440,39 @@ bool CharacterController::updateWeaponState()
const ESM::ENAMstruct &firstEffect = spell->mEffects.mList.at(0); // first effect used for casting animation
switch(firstEffect.mRange)
std::string startKey;
std::string stopKey;
if (isRandomAttackAnimation(mCurrentWeapon))
{
case 0: mAttackType = "self"; break;
case 1: mAttackType = "touch"; break;
case 2: mAttackType = "target"; break;
startKey = "start";
stopKey = "stop";
MWBase::Environment::get().getWorld()->castSpell(mPtr, mCastingManualSpell); // No "release" text key to use, so cast immediately
mCastingManualSpell = false;
}
else
{
switch(firstEffect.mRange)
{
case 0: mAttackType = "self"; break;
case 1: mAttackType = "touch"; break;
case 2: mAttackType = "target"; break;
}
startKey = mAttackType+" start";
stopKey = mAttackType+" stop";
}
mAnimation->play(mCurrentWeapon, priorityWeapon,
MWRender::Animation::BlendMask_All, true,
weapSpeed, mAttackType+" start", mAttackType+" stop",
1, startKey, stopKey,
0.0f, 0);
mUpperBodyState = UpperCharState_CastingSpell;
}
else
{
resetIdle = false;
}
if (mPtr.getClass().hasInventoryStore(mPtr))
{
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
@ -1469,16 +1512,27 @@ bool CharacterController::updateWeaponState()
}
else if (ammunition)
{
if(mWeaponType == WeapType_Crossbow || mWeaponType == WeapType_BowAndArrow ||
mWeaponType == WeapType_Thrown)
std::string startKey;
std::string stopKey;
if(mWeaponType == WeapType_Crossbow || mWeaponType == WeapType_BowAndArrow || mWeaponType == WeapType_Thrown)
{
mAttackType = "shoot";
else
startKey = mAttackType+" start";
stopKey = mAttackType+" min attack";
}
if (isRandomAttackAnimation(mCurrentWeapon))
{
startKey = "start";
stopKey = "stop";
}
else if (mAttackType != "shoot")
{
if(mPtr == getPlayer())
{
if (isWeapon)
{
if (Settings::Manager::getBool("best attack", "Game"))
if (Settings::Manager::getBool("best attack", "Game"))
{
MWWorld::ConstContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
mAttackType = getBestAttack(weapon->get<ESM::Weapon>()->mBase);
@ -1487,19 +1541,32 @@ bool CharacterController::updateWeaponState()
setAttackTypeBasedOnMovement();
}
else
setAttackTypeRandomly(mAttackType);
{
// There is no "best attack" for Hand-to-Hand
setAttackTypeRandomly(mAttackType);
}
}
// else if (mPtr != getPlayer()) use mAttackType set by AiCombat
startKey = mAttackType+" start";
stopKey = mAttackType+" min attack";
}
mAnimation->play(mCurrentWeapon, priorityWeapon,
MWRender::Animation::BlendMask_All, false,
weapSpeed, mAttackType+" start", mAttackType+" min attack",
weapSpeed, startKey, stopKey,
0.0f, 0);
mUpperBodyState = UpperCharState_StartToMinAttack;
}
}
// We should reset player's idle animation in the first-person mode.
if (resetIdle && mPtr == player && MWBase::Environment::get().getWorld()->isFirstPerson())
mIdleState = CharState_None;
// In other cases we should not break swim and sneak animations
if (resetIdle && mIdleState != CharState_IdleSneak && mIdleState != CharState_IdleSwim)
mIdleState = CharState_None;
animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete);
if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && !isKnockedDown())
mAttackStrength = complete;
@ -1611,7 +1678,7 @@ bool CharacterController::updateWeaponState()
else if(mUpperBodyState == UpperCharState_UnEquipingWeap)
mUpperBodyState = UpperCharState_Nothing;
}
else if(complete >= 1.0f)
else if(complete >= 1.0f && !isRandomAttackAnimation(mCurrentWeapon))
{
std::string start, stop;
switch(mUpperBodyState)
@ -1663,21 +1730,30 @@ bool CharacterController::updateWeaponState()
break;
}
// Note: apply reload animations only for upper body since blending with movement animations can give weird result.
// Especially noticable with crossbow reload animation.
// Note: apply crossbow reload animation only for upper body
// since blending with movement animations can give weird result.
if(!start.empty())
{
int mask = MWRender::Animation::BlendMask_All;
if (mWeaponType == WeapType_Crossbow)
mask = MWRender::Animation::BlendMask_UpperBody;
mAnimation->disable(mCurrentWeapon);
if (mUpperBodyState == UpperCharState_FollowStartToFollowStop)
mAnimation->play(mCurrentWeapon, priorityWeapon,
MWRender::Animation::BlendMask_UpperBody, true,
mask, true,
weapSpeed, start, stop, 0.0f, 0);
else
mAnimation->play(mCurrentWeapon, priorityWeapon,
MWRender::Animation::BlendMask_UpperBody, false,
mask, false,
weapSpeed, start, stop, 0.0f, 0);
}
}
else if(complete >= 1.0f && isRandomAttackAnimation(mCurrentWeapon))
{
mAnimation->disable(mCurrentWeapon);
mUpperBodyState = UpperCharState_WeapEquiped;
}
if (mPtr.getClass().hasInventoryStore(mPtr))
{
@ -1980,25 +2056,37 @@ void CharacterController::update(float duration)
else if(rot.z() != 0.0f && !sneak && !(mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson()))
{
if(rot.z() > 0.0f)
{
movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight;
mAnimation->disable(mCurrentJump);
}
else if(rot.z() < 0.0f)
{
movestate = inwater ? CharState_SwimTurnLeft : CharState_TurnLeft;
mAnimation->disable(mCurrentJump);
}
}
}
mTurnAnimationThreshold -= duration;
if (isTurning())
mTurnAnimationThreshold = 0.05f;
else if (movestate == CharState_None && isTurning()
&& mTurnAnimationThreshold > 0)
// Player can not use smooth turning as NPCs, so we play turning animation a bit to avoid jittering
if (mPtr == getPlayer())
{
float threshold = mCurrentMovement.find("swim") == std::string::npos ? 0.4f : 0.8f;
float complete;
bool animPlaying = mAnimation->getInfo(mCurrentMovement, &complete);
if (movestate == CharState_None && isTurning())
{
if (animPlaying && complete < threshold)
movestate = mMovementState;
}
}
else
{
movestate = mMovementState;
mTurnAnimationThreshold -= duration;
if (movestate == CharState_TurnRight || movestate == CharState_TurnLeft ||
movestate == CharState_SwimTurnRight || movestate == CharState_SwimTurnLeft)
{
mTurnAnimationThreshold = 0.05f;
}
else if (movestate == CharState_None && isTurning()
&& mTurnAnimationThreshold > 0)
{
movestate = mMovementState;
}
}
if(movestate != CharState_None && !isTurning())
@ -2028,8 +2116,10 @@ void CharacterController::update(float duration)
if (isTurning())
{
// Adjust animation speed from 1.0 to 1.5 multiplier
float turnSpeed = std::min(1.5f, std::abs(rot.z()) / duration / static_cast<float>(osg::PI));
if (duration > 0)
mAnimation->adjustSpeedMult(mCurrentMovement, std::min(1.5f, std::abs(rot.z()) / duration / static_cast<float>(osg::PI)));
mAnimation->adjustSpeedMult(mCurrentMovement, std::max(turnSpeed, 1.0f));
}
else if (mMovementState != CharState_None && mAdjustMovementAnimSpeed)
{
@ -2396,6 +2486,13 @@ void CharacterController::setAttackTypeBasedOnMovement()
mAttackType = "chop";
}
bool CharacterController::isRandomAttackAnimation(const std::string& group) const
{
return (group == "attack1" || group == "swimattack1" ||
group == "attack2" || group == "swimattack2" ||
group == "attack3" || group == "swimattack3");
}
bool CharacterController::isAttackPrepairing() const
{
return mUpperBodyState == UpperCharState_StartToMinAttack ||
@ -2497,7 +2594,7 @@ void CharacterController::setAttackTypeRandomly(std::string& attackType)
bool CharacterController::readyToPrepareAttack() const
{
return (mHitState == CharState_None || mHitState == CharState_Block)
&& mUpperBodyState <= UpperCharState_WeapEquiped;
&& mUpperBodyState <= UpperCharState_WeapEquiped;
}
bool CharacterController::readyToStartAttack() const

@ -31,8 +31,10 @@ enum Priority {
Priority_WeaponLowerBody,
Priority_SneakIdleLowerBody,
Priority_SwimIdle,
Priority_Jump,
Priority_Movement,
// Note: in vanilla movement anims have higher priority than jump ones.
// It causes issues with landing animations during movement.
Priority_Jump,
Priority_Hit,
Priority_Weapon,
Priority_Block,
@ -222,6 +224,9 @@ class CharacterController : public MWRender::Animation::TextKeyListener
bool updateCreatureState();
void updateIdleStormState(bool inwater);
std::string chooseRandomAttackAnimation() const;
bool isRandomAttackAnimation(const std::string& group) const;
bool isPersistentAnimPlaying();
void updateAnimQueue();

@ -388,9 +388,6 @@ namespace MWMechanics
void getHandToHandDamage(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, float &damage, bool &healthdmg, float attackStrength)
{
// Note: MCP contains an option to include Strength in hand-to-hand damage
// calculations. Some mods recommend using it, so we may want to include an
// option for it.
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
float minstrike = store.get<ESM::GameSetting>().find("fMinHandToHandMult")->getFloat();
float maxstrike = store.get<ESM::GameSetting>().find("fMaxHandToHandMult")->getFloat();
@ -401,6 +398,16 @@ namespace MWMechanics
healthdmg = otherstats.isParalyzed()
|| otherstats.getKnockedDown();
bool isWerewolf = (attacker.getClass().isNpc() && attacker.getClass().getNpcStats(attacker).isWerewolf());
// Options in the launcher's combo box: unarmedFactorsStrengthComboBox
// 0 = Do not factor strength into hand-to-hand combat.
// 1 = Factor into werewolf hand-to-hand combat.
// 2 = Ignore werewolves.
int factorStrength = Settings::Manager::getInt("strength influences hand to hand", "Game");
if (factorStrength == 1 || (factorStrength == 2 && !isWerewolf)) {
damage *= attacker.getClass().getCreatureStats(attacker).getAttribute(ESM::Attribute::Strength).getModified() / 40.0f;
}
if(isWerewolf)
{
healthdmg = true;

@ -195,6 +195,7 @@ namespace MWMechanics
mDead = true;
mDynamic[index].setModifier(0);
mDynamic[index].setCurrentModifier(0);
mDynamic[index].setCurrent(0);
if (MWBase::Environment::get().getWorld()->getGodModeState())

@ -1,8 +1,7 @@
#ifndef OPENMW_MECHANICS_LEVELLEDLIST_H
#define OPENMW_MECHANICS_LEVELLEDLIST_H
#include <iostream>
#include <components/debug/debuglog.hpp>
#include <components/misc/rng.hpp>
#include "../mwworld/ptr.hpp"
@ -63,7 +62,7 @@ namespace MWMechanics
// Vanilla doesn't fail on nonexistent items in levelled lists
if (!MWBase::Environment::get().getWorld()->getStore().find(Misc::StringUtils::lowerCase(item)))
{
std::cerr << "Warning: ignoring nonexistent item '" << item << "' in levelled list '" << levItem->mId << "'" << std::endl;
Log(Debug::Warning) << "Warning: ignoring nonexistent item '" << item << "' in levelled list '" << levItem->mId << "'";
return std::string();
}

@ -1,6 +1,7 @@
#include "mechanicsmanagerimp.hpp"
#include <limits.h>
#include <set>
#include <components/misc/rng.hpp>
@ -1445,11 +1446,12 @@ namespace MWMechanics
if (target == getPlayer() || !attacker.getClass().isActor())
return false;
std::list<MWWorld::Ptr> followersAttacker = getActorsSidingWith(attacker);
std::set<MWWorld::Ptr> followersAttacker;
getActorsSidingWith(attacker, followersAttacker);
MWMechanics::CreatureStats& statsTarget = target.getClass().getCreatureStats(target);
if (std::find(followersAttacker.begin(), followersAttacker.end(), target) != followersAttacker.end())
if (followersAttacker.find(target) != followersAttacker.end())
{
statsTarget.friendlyHit();

@ -1,6 +1,6 @@
#include "objects.hpp"
#include <iostream>
#include <components/debug/debuglog.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -88,7 +88,7 @@ bool Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& gro
}
else
{
std::cerr<< "Warning: Objects::playAnimationGroup: Unable to find " << ptr.getCellRef().getRefId() << std::endl;
Log(Debug::Warning) << "Warning: Objects::playAnimationGroup: Unable to find " << ptr.getCellRef().getRefId();
return false;
}
}

@ -509,9 +509,18 @@ namespace MWMechanics
}
else // target.getClass().isActor() == true
{
ActiveSpells::ActiveEffect effect;
effect.mEffectId = effectIt->mEffectID;
effect.mArg = MWMechanics::EffectKey(*effectIt).mArg;
effect.mMagnitude = magnitude;
bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration);
if (hasDuration && effectIt->mDuration == 0)
{
// We still should add effect to list to allow GetSpellEffects to detect this spell
effect.mDuration = 0.f;
appliedLastingEffects.push_back(effect);
// duration 0 means apply full magnitude instantly
bool wasDead = target.getClass().getCreatureStats(target).isDead();
effectTick(target.getClass().getCreatureStats(target), target, EffectKey(*effectIt), magnitude);
@ -522,18 +531,15 @@ namespace MWMechanics
}
else
{
// add to list of active effects, to apply in next frame
ActiveSpells::ActiveEffect effect;
effect.mEffectId = effectIt->mEffectID;
effect.mArg = MWMechanics::EffectKey(*effectIt).mArg;
if (!hasDuration)
effect.mDuration = 1.0f;
else
effect.mDuration = static_cast<float>(effectIt->mDuration);
effect.mMagnitude = magnitude;
targetEffects.add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(effect.mMagnitude));
// add to list of active effects, to apply in next frame
appliedLastingEffects.push_back(effect);
// Unequip all items, if a spell with the ExtraSpell effect was casted

@ -5,11 +5,11 @@
namespace MWMechanics
{
template<typename T>
Stat<T>::Stat() : mBase (0), mModified (0) {}
Stat<T>::Stat() : mBase (0), mModified (0), mCurrentModified (0) {}
template<typename T>
Stat<T>::Stat(T base) : mBase (base), mModified (base) {}
Stat<T>::Stat(T base) : mBase (base), mModified (base), mCurrentModified (base) {}
template<typename T>
Stat<T>::Stat(T base, T modified) : mBase (base), mModified (modified) {}
Stat<T>::Stat(T base, T modified) : mBase (base), mModified (modified), mCurrentModified (modified) {}
template<typename T>
const T& Stat<T>::getBase() const
@ -22,23 +22,42 @@ namespace MWMechanics
{
return std::max(static_cast<T>(0), mModified);
}
template<typename T>
T Stat<T>::getCurrentModified() const
{
return mCurrentModified;
}
template<typename T>
T Stat<T>::getModifier() const
{
return mModified-mBase;
}
template<typename T>
T Stat<T>::getCurrentModifier() const
{
return mCurrentModified - mModified;
}
template<typename T>
void Stat<T>::set (const T& value)
{
T diff = value - mBase;
mBase = mModified = value;
mCurrentModified += diff;
}
template<typename T>
void Stat<T>::setBase (const T& value)
{
T diff = value - mBase;
mBase = value;
mModified += diff;
mCurrentModified += diff;
}
template<typename T>
void Stat<T>::setModified (T value, const T& min, const T& max)
{
@ -57,24 +76,39 @@ namespace MWMechanics
mModified = value;
mBase += diff;
mCurrentModified += diff;
}
template<typename T>
void Stat<T>::setCurrentModified(T value)
{
mCurrentModified = value;
}
template<typename T>
void Stat<T>::setModifier (const T& modifier)
{
mModified = mBase + modifier;
}
template<typename T>
void Stat<T>::setCurrentModifier(const T& modifier)
{
mCurrentModified = mModified + modifier;
}
template<typename T>
void Stat<T>::writeState (ESM::StatState<T>& state) const
{
state.mBase = mBase;
state.mMod = mModified;
state.mMod = mCurrentModified;
}
template<typename T>
void Stat<T>::readState (const ESM::StatState<T>& state)
{
mBase = state.mBase;
mModified = state.mMod;
mModified = state.mBase;
mCurrentModified = state.mMod;
}
@ -98,6 +132,12 @@ namespace MWMechanics
{
return mStatic.getModified();
}
template<typename T>
T DynamicStat<T>::getCurrentModified() const
{
return mStatic.getCurrentModified();
}
template<typename T>
const T& DynamicStat<T>::getCurrent() const
{
@ -127,14 +167,21 @@ namespace MWMechanics
mCurrent = getModified();
}
template<typename T>
void DynamicStat<T>::setCurrent (const T& value, bool allowDecreaseBelowZero)
void DynamicStat<T>::setCurrentModified(T value)
{
mStatic.setCurrentModified(value);
}
template<typename T>
void DynamicStat<T>::setCurrent (const T& value, bool allowDecreaseBelowZero, bool allowIncreaseAboveModified)
{
if (value > mCurrent)
{
// increase
mCurrent = value;
if (mCurrent > getModified())
if (value <= getModified() || allowIncreaseAboveModified)
mCurrent = value;
else if (mCurrent > getModified())
return;
else
mCurrent = getModified();
}
else if (value > 0 || allowDecreaseBelowZero)
@ -156,6 +203,16 @@ namespace MWMechanics
setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero);
}
template<typename T>
void DynamicStat<T>::setCurrentModifier(const T& modifier, bool allowCurrentDecreaseBelowZero)
{
T diff = modifier - mStatic.getCurrentModifier();
mStatic.setCurrentModifier(modifier);
// The (modifier > 0) check here allows increase over modified only if the modifier is positive (a fortify effect is active).
setCurrent (getCurrent() + diff, allowCurrentDecreaseBelowZero, (modifier > 0));
}
template<typename T>
void DynamicStat<T>::writeState (ESM::StatState<T>& state) const
{

@ -17,6 +17,7 @@ namespace MWMechanics
{
T mBase;
T mModified;
T mCurrentModified;
public:
typedef T Type;
@ -28,7 +29,9 @@ namespace MWMechanics
const T& getBase() const;
T getModified() const;
T getCurrentModified() const;
T getModifier() const;
T getCurrentModifier() const;
/// Set base and modified to \a value.
void set (const T& value);
@ -36,9 +39,15 @@ namespace MWMechanics
/// Set base and adjust modified accordingly.
void setBase (const T& value);
/// Set modified value an adjust base accordingly.
/// Set modified value and adjust base accordingly.
void setModified (T value, const T& min, const T& max = std::numeric_limits<T>::max());
/// Set "current modified," used for drain and fortify. Unlike the regular modifier
/// this just adds and subtracts from the current value without changing the maximum.
void setCurrentModified(T value);
void setModifier (const T& modifier);
void setCurrentModifier (const T& modifier);
void writeState (ESM::StatState<T>& state) const;
void readState (const ESM::StatState<T>& state);
@ -73,6 +82,7 @@ namespace MWMechanics
const T& getBase() const;
T getModified() const;
T getCurrentModified() const;
const T& getCurrent() const;
/// Set base, modified and current to \a value.
@ -81,11 +91,16 @@ namespace MWMechanics
/// Set base and adjust modified accordingly.
void setBase (const T& value);
/// Set modified value an adjust base accordingly.
/// Set modified value and adjust base accordingly.
void setModified (T value, const T& min, const T& max = std::numeric_limits<T>::max());
void setCurrent (const T& value, bool allowDecreaseBelowZero = false);
void setModifier (const T& modifier, bool allowCurrentDecreaseBelowZero=false);
/// Set "current modified," used for drain and fortify. Unlike the regular modifier
/// this just adds and subtracts from the current value without changing the maximum.
void setCurrentModified(T value);
void setCurrent (const T& value, bool allowDecreaseBelowZero = false, bool allowIncreaseAboveModified = false);
void setModifier (const T& modifier, bool allowCurrentToDecreaseBelowZero=false);
void setCurrentModifier (const T& modifier, bool allowCurrentToDecreaseBelowZero = false);
void writeState (ESM::StatState<T>& state) const;
void readState (const ESM::StatState<T>& state);

@ -1,6 +1,6 @@
#include "summoning.hpp"
#include <iostream>
#include <components/debug/debuglog.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -76,7 +76,7 @@ namespace MWMechanics
}
catch (std::exception& e)
{
std::cerr << "Failed to spawn summoned creature: " << e.what() << std::endl;
Log(Debug::Error) << "Failed to spawn summoned creature: " << e.what();
// still insert into creatureMap so we don't try to spawn again every frame, that would spam the warning log
}

@ -1,6 +1,5 @@
#include "physicssystem.hpp"
#include <iostream>
#include <stdexcept>
#include <osg/Group>
@ -20,7 +19,7 @@
#include <components/nifbullet/bulletnifloader.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/bulletshapemanager.hpp>
#include <components/debug/debuglog.hpp>
#include <components/esm/loadgmst.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
#include <components/sceneutil/unrefqueue.hpp>
@ -638,7 +637,7 @@ namespace MWPhysics
mPtr.getRefData().getBaseNode()->accept(visitor);
if (!visitor.mFound)
{
std::cerr << "Error: animateCollisionShapes can't find node " << recIndex << " for " << mPtr.getCellRef().getRefId() << std::endl;
Log(Debug::Warning) << "Warning: animateCollisionShapes can't find node " << recIndex << " for " << mPtr.getCellRef().getRefId();
// Remove nonexistent nodes from animated shapes map and early out
mShapeInstance->mAnimatedShapes.erase(recIndex);
@ -708,7 +707,7 @@ namespace MWPhysics
if (physFramerate > 0)
{
mPhysicsDt = 1.f / physFramerate;
std::cerr << "Warning: physics framerate was overridden (a new value is " << physFramerate << ")." << std::endl;
Log(Debug::Warning) << "Warning: using custom physics framerate (" << physFramerate << " FPS).";
}
}
}

@ -12,6 +12,8 @@
#include <osgParticle/ParticleSystem>
#include <osgParticle/ParticleProcessor>
#include <components/debug/debuglog.hpp>
#include <components/nifosg/nifloader.hpp>
#include <components/resource/resourcesystem.hpp>
@ -192,7 +194,7 @@ namespace
for (RemoveVec::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it)
{
if (!it->second->removeChild(it->first))
std::cerr << "error removing " << it->first->getName() << std::endl;
Log(Debug::Error) << "Error removing " << it->first->getName();
}
}
@ -612,7 +614,7 @@ namespace MWRender
NodeMap::const_iterator found = nodeMap.find(bonename);
if (found == nodeMap.end())
{
std::cerr << "Warning: addAnimSource: can't find bone '" + bonename << "' in " << baseModel << " (referenced by " << kfname << ")" << std::endl;
Log(Debug::Warning) << "Warning: addAnimSource: can't find bone '" + bonename << "' in " << baseModel << " (referenced by " << kfname << ")";
continue;
}
@ -724,7 +726,7 @@ namespace MWRender
}
catch (std::exception& e)
{
std::cerr << "Error handling text key " << evt << ": " << e.what() << std::endl;
Log(Debug::Error) << "Error handling text key " << evt << ": " << e.what();
}
}
}
@ -1767,12 +1769,12 @@ namespace MWRender
PartHolder::~PartHolder()
{
if (mNode.get() && !mNode->getNumParents())
std::cerr << "Error: part has no parents " << std::endl;
Log(Debug::Verbose) << "Part has no parents" ;
if (mNode.get() && mNode->getNumParents())
{
if (mNode->getNumParents() > 1)
std::cerr << "Error: part has multiple parents " << mNode->getNumParents() << " " << mNode.get() << std::endl;
Log(Debug::Verbose) << "Part has multiple (" << mNode->getNumParents() << ") parents";
mNode->getParent(0)->removeChild(mNode);
}
}

@ -1,12 +1,12 @@
#include "bulletdebugdraw.hpp"
#include <iostream>
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
#include <osg/Geometry>
#include <osg/Group>
#include <components/debug/debuglog.hpp>
#include "vismask.hpp"
namespace
@ -91,7 +91,7 @@ void DebugDrawer::drawContactPoint(const btVector3 &PointOnB, const btVector3 &n
void DebugDrawer::reportErrorWarning(const char *warningString)
{
std::cerr << warningString << std::endl;
Log(Debug::Warning) << warningString;
}
void DebugDrawer::setDebugMode(int isOn)

@ -1,7 +1,6 @@
#include "characterpreview.hpp"
#include <cmath>
#include <iostream>
#include <osg/Material>
#include <osg/Fog>
@ -14,6 +13,7 @@
#include <osgUtil/IntersectionVisitor>
#include <osgUtil/LineSegmentIntersector>
#include <components/debug/debuglog.hpp>
#include <components/fallback/fallback.hpp>
#include <components/sceneutil/lightmanager.hpp>
#include <components/sceneutil/shadow.hpp>
@ -477,7 +477,7 @@ namespace MWRender
mCamera->addUpdateCallback(mUpdateCameraCallback);
}
else
std::cerr << "Error: Bip01 Head node not found" << std::endl;
Log(Debug::Error) << "Error: Bip01 Head node not found";
}
}

@ -1,11 +1,9 @@
#include "creatureanimation.hpp"
#include <iostream>
#include <osg/MatrixTransform>
#include <components/esm/loadcrea.hpp>
#include <components/debug/debuglog.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/sceneutil/attach.hpp>
@ -155,7 +153,7 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot)
}
catch (std::exception& e)
{
std::cerr << "Can not add creature part: " << e.what() << std::endl;
Log(Debug::Error) << "Can not add creature part: " << e.what();
}
}

@ -15,6 +15,8 @@
#include <components/settings/settings.hpp>
#include <components/files/memorystream.hpp>
#include <components/debug/debuglog.hpp>
#include <components/sceneutil/workqueue.hpp>
#include <components/esm/globalmap.hpp>
@ -411,14 +413,14 @@ namespace MWRender
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png");
if (!readerwriter)
{
std::cerr << "Error: Can't write map overlay: no png readerwriter found" << std::endl;
Log(Debug::Error) << "Error: Can't write map overlay: no png readerwriter found";
return;
}
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*mOverlayImage, ostream);
if (!result.success())
{
std::cerr << "Error: Can't write map overlay: " << result.message() << " code " << result.status() << std::endl;
Log(Debug::Warning) << "Error: Can't write map overlay: " << result.message() << " code " << result.status();
return;
}
@ -463,14 +465,14 @@ namespace MWRender
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png");
if (!readerwriter)
{
std::cerr << "Error: Can't read map overlay: no png readerwriter found" << std::endl;
Log(Debug::Error) << "Error: Can't read map overlay: no png readerwriter found";
return;
}
osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(istream);
if (!result.success())
{
std::cerr << "Error: Can't read map overlay: " << result.message() << " code " << result.status() << std::endl;
Log(Debug::Error) << "Error: Can't read map overlay: " << result.message() << " code " << result.status();
return;
}
@ -572,7 +574,7 @@ namespace MWRender
CameraVector::iterator found = std::find(mActiveCameras.begin(), mActiveCameras.end(), camera);
if (found == mActiveCameras.end())
{
std::cerr << "Error: GlobalMap trying to remove an inactive camera" << std::endl;
Log(Debug::Error) << "Error: GlobalMap trying to remove an inactive camera";
return;
}
mActiveCameras.erase(found);

@ -1,6 +1,5 @@
#include "localmap.hpp"
#include <iostream>
#include <stdint.h>
#include <osg/Fog>
@ -12,6 +11,7 @@
#include <osgDB/ReadFile>
#include <components/debug/debuglog.hpp>
#include <components/esm/fogstate.hpp>
#include <components/esm/loadcell.hpp>
#include <components/settings/settings.hpp>
@ -323,7 +323,7 @@ void LocalMap::markForRemoval(osg::Camera *cam)
CameraVector::iterator found = std::find(mActiveCameras.begin(), mActiveCameras.end(), cam);
if (found == mActiveCameras.end())
{
std::cerr << "Error: trying to remove an inactive camera" << std::endl;
Log(Debug::Error) << "Error: trying to remove an inactive camera";
return;
}
mActiveCameras.erase(found);
@ -495,7 +495,7 @@ void LocalMap::requestInteriorMap(const MWWorld::CellStore* cell)
// We are using the same bounds and angle as we were using when the textures were originally made. Segments should come out the same.
if (i >= int(fog->mFogTextures.size()))
{
std::cout << "Error: fog texture count mismatch" << std::endl;
Log(Debug::Warning) << "Warning: fog texture count mismatch";
break;
}
@ -687,7 +687,7 @@ void LocalMap::MapSegment::loadFogOfWar(const ESM::FogTexture &esm)
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("tga");
if (!readerwriter)
{
std::cerr << "Error: Unable to load fog, can't find a tga ReaderWriter" << std::endl;
Log(Debug::Error) << "Error: Unable to load fog, can't find a tga ReaderWriter" ;
return;
}
@ -696,7 +696,7 @@ void LocalMap::MapSegment::loadFogOfWar(const ESM::FogTexture &esm)
osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(in);
if (!result.success())
{
std::cerr << "Error: Failed to read fog: " << result.message() << " code " << result.status() << std::endl;
Log(Debug::Error) << "Error: Failed to read fog: " << result.message() << " code " << result.status();
return;
}
@ -719,7 +719,7 @@ void LocalMap::MapSegment::saveFogOfWar(ESM::FogTexture &fog) const
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("tga");
if (!readerwriter)
{
std::cerr << "Error: Unable to write fog, can't find a tga ReaderWriter" << std::endl;
Log(Debug::Error) << "Error: Unable to write fog, can't find a tga ReaderWriter";
return;
}
@ -728,7 +728,7 @@ void LocalMap::MapSegment::saveFogOfWar(ESM::FogTexture &fog) const
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*mFogOfWarImage, ostream);
if (!result.success())
{
std::cerr << "Error: Unable to write fog: " << result.message() << " code " << result.status() << std::endl;
Log(Debug::Error) << "Error: Unable to write fog: " << result.message() << " code " << result.status();
return;
}
mFogOfWarImage->flipVertical();

@ -7,6 +7,8 @@
#include <osgUtil/RenderBin>
#include <osgUtil/CullVisitor>
#include <components/debug/debuglog.hpp>
#include <components/misc/rng.hpp>
#include <components/misc/resourcehelpers.hpp>
@ -440,7 +442,7 @@ void NpcAnimation::updateNpcBase()
if (bp)
mHeadModel = "meshes\\" + bp->mModel;
else
std::cerr << "Warning: Failed to load body part '" << mNpc->mHead << "'" << std::endl;
Log(Debug::Warning) << "Warning: Failed to load body part '" << mNpc->mHead << "'";
}
mHairModel = "";
@ -450,7 +452,7 @@ void NpcAnimation::updateNpcBase()
if (bp)
mHairModel = "meshes\\" + bp->mModel;
else
std::cerr << "Warning: Failed to load body part '" << mNpc->mHair << "'" << std::endl;
Log(Debug::Warning) << "Warning: Failed to load body part '" << mNpc->mHair << "'";
}
}
@ -763,7 +765,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g
}
catch (std::exception& e)
{
std::cerr << "Error adding NPC part: " << e.what() << std::endl;
Log(Debug::Error) << "Error adding NPC part: " << e.what();
return false;
}
@ -850,7 +852,7 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector<ESM::
bodypart = NULL;
}
else if (!bodypart)
std::cerr << "Warning: Failed to find body part '" << part->mFemale << "'" << std::endl;
Log(Debug::Warning) << "Warning: Failed to find body part '" << part->mFemale << "'";
}
if(!bodypart && !part->mMale.empty())
{
@ -865,7 +867,7 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector<ESM::
bodypart = NULL;
}
else if (!bodypart)
std::cerr << "Warning: Failed to find body part '" << part->mMale << "'" << std::endl;
Log(Debug::Warning) << "Warning: Failed to find body part '" << part->mMale << "'";
}
if(bodypart)

@ -22,6 +22,8 @@
#include <osgViewer/Viewer>
#include <components/debug/debuglog.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/imagemanager.hpp>
#include <components/resource/scenemanager.hpp>
@ -580,8 +582,8 @@ namespace MWRender
mLandFogStart = mViewDistance * (1 - fogDepth);
mLandFogEnd = mViewDistance;
}
mUnderwaterFogStart = mViewDistance * (1 - underwaterFog);
mUnderwaterFogEnd = mViewDistance;
mUnderwaterFogStart = std::min(mViewDistance, 6666.f) * (1 - underwaterFog);
mUnderwaterFogEnd = std::min(mViewDistance, 6666.f);
}
mFogColor = color;
}
@ -611,8 +613,6 @@ namespace MWRender
mCurrentCameraPos = cameraPos;
if (mWater->isUnderwater(cameraPos))
{
float viewDistance = mViewDistance;
viewDistance = std::min(viewDistance, 6666.f);
setFogColor(mUnderwaterColor * mUnderwaterWeight + mFogColor * (1.f-mUnderwaterWeight));
mStateUpdater->setFogStart(mUnderwaterFogStart);
mStateUpdater->setFogEnd(mUnderwaterFogEnd);
@ -737,7 +737,7 @@ namespace MWRender
if (!found)
{
std::cerr << "Wrong screenshot type: " << settingArgs[0] << "." << std::endl;
Log(Debug::Warning) << "Wrong screenshot type: " << settingArgs[0] << ".";
return false;
}
}
@ -756,7 +756,7 @@ namespace MWRender
if (mCamera->isVanityOrPreviewModeEnabled())
{
std::cerr << "Spherical screenshots are not allowed in preview mode." << std::endl;
Log(Debug::Warning) << "Spherical screenshots are not allowed in preview mode.";
return false;
}

@ -19,6 +19,8 @@
#include <osgUtil/IncrementalCompileOperation>
#include <osgUtil/CullVisitor>
#include <components/debug/debuglog.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/imagemanager.hpp>
#include <components/resource/scenemanager.hpp>
@ -29,7 +31,6 @@
#include <components/shader/shadermanager.hpp>
#include <components/esm/loadcell.hpp>
#include <components/fallback/fallback.hpp>
@ -193,16 +194,16 @@ osg::ref_ptr<osg::Image> readPngImage (const std::string& file)
boost::filesystem::ifstream inStream;
inStream.open(file, std::ios_base::in | std::ios_base::binary);
if (inStream.fail())
std::cerr << "Error: Failed to open " << file << std::endl;
Log(Debug::Error) << "Error: Failed to open " << file;
osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png");
if (!reader)
{
std::cerr << "Error: Failed to read " << file << ", no png readerwriter found" << std::endl;
Log(Debug::Error) << "Error: Failed to read " << file << ", no png readerwriter found";
return osg::ref_ptr<osg::Image>();
}
osgDB::ReaderWriter::ReadResult result = reader->readImage(inStream);
if (!result.success())
std::cerr << "Error: Failed to read " << file << ": " << result.message() << " code " << result.status() << std::endl;
Log(Debug::Error) << "Error: Failed to read " << file << ": " << result.message() << " code " << result.status();
return result.getImage();
}

@ -1,7 +1,8 @@
#include "aiextensions.hpp"
#include <stdexcept>
#include <iostream>
#include <components/debug/debuglog.hpp>
#include <components/compiler/extensions.hpp>
#include <components/compiler/opcodes.hpp>
@ -50,7 +51,7 @@ namespace MWScript
MWMechanics::AiActivate activatePackage(objectID);
ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(activatePackage, ptr);
std::cout << "AiActivate" << std::endl;
Log(Debug::Info) << "AiActivate";
}
};
@ -78,7 +79,7 @@ namespace MWScript
MWMechanics::AiTravel travelPackage(x, y, z);
ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(travelPackage, ptr);
std::cout << "AiTravel: " << x << ", " << y << ", " << z << std::endl;
Log(Debug::Info) << "AiTravel: " << x << ", " << y << ", " << z;
}
};
@ -112,8 +113,7 @@ namespace MWScript
MWMechanics::AiEscort escortPackage(actorID, static_cast<int>(duration), x, y, z);
ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(escortPackage, ptr);
std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration
<< std::endl;
Log(Debug::Info) << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration;
}
};
@ -155,8 +155,7 @@ namespace MWScript
MWMechanics::AiEscort escortPackage(actorID, cellID, static_cast<int>(duration), x, y, z);
ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(escortPackage, ptr);
std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration
<< std::endl;
Log(Debug::Info) << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration;
}
};
@ -316,8 +315,7 @@ namespace MWScript
MWMechanics::AiFollow followPackage(actorID, duration, x, y ,z);
ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(followPackage, ptr);
std::cout << "AiFollow: " << actorID << ", " << x << ", " << y << ", " << z << ", " << duration
<< std::endl;
Log(Debug::Info) << "AiFollow: " << actorID << ", " << x << ", " << y << ", " << z << ", " << duration;
}
};
@ -353,8 +351,7 @@ namespace MWScript
MWMechanics::AiFollow followPackage(actorID, cellID, duration, x, y ,z);
ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(followPackage, ptr);
std::cout << "AiFollow: " << actorID << ", " << x << ", " << y << ", " << z << ", " << duration
<< std::endl;
Log(Debug::Info) << "AiFollow: " << actorID << ", " << x << ", " << y << ", " << z << ", " << duration;
}
};

@ -6,6 +6,8 @@
#include <MyGUI_LanguageManager.h>
#include <components/debug/debuglog.hpp>
#include <components/compiler/extensions.hpp>
#include <components/compiler/opcodes.hpp>
@ -190,8 +192,9 @@ namespace MWScript
if (it == invStore.end())
{
it = ptr.getClass().getContainerStore (ptr).add (item, 1, ptr);
std::cerr << "Implicitly adding one " << item << " to container "
"to fulfil requirements of Equip instruction" << std::endl;
Log(Debug::Warning) << "Implicitly adding one " << item <<
" to the inventory store of " << ptr.getCellRef().getRefId() <<
" to fulfill the requirements of Equip instruction";
}
if (ptr == MWMechanics::getPlayer())

@ -1,10 +1,8 @@
#include <iostream>
#include "dialogueextensions.hpp"
#include <components/compiler/extensions.hpp>
#include <components/compiler/opcodes.hpp>
#include <components/debug/debuglog.hpp>
#include <components/interpreter/interpreter.hpp>
#include <components/interpreter/runtime.hpp>
#include <components/interpreter/opcodes.hpp>
@ -139,8 +137,8 @@ namespace MWScript
if (!ptr.getClass().isActor())
{
const std::string error = "Warning: \"forcegreeting\" command works only for actors.";
runtime.getContext().report (error);
std::cerr << error << std::endl;
runtime.getContext().report(error);
Log(Debug::Warning) << error;
return;
}

@ -1,8 +1,8 @@
#include "globalscripts.hpp"
#include <cassert>
#include <iostream>
#include <components/debug/debuglog.hpp>
#include <components/misc/stringops.hpp>
#include <components/esm/esmwriter.hpp>
#include <components/esm/globalscript.hpp>
@ -113,9 +113,9 @@ namespace MWScript
}
catch (const std::exception& exception)
{
std::cerr
Log(Debug::Error)
<< "Failed to add start script " << *iter << " because an exception has "
<< "been thrown: " << exception.what() << std::endl;
<< "been thrown: " << exception.what();
}
}
}
@ -169,10 +169,9 @@ namespace MWScript
}
catch (const std::exception& exception)
{
std::cerr
Log(Debug::Error)
<< "Failed to add start script " << script.mId
<< " because an exception has been thrown: " << exception.what()
<< std::endl;
<< " because an exception has been thrown: " << exception.what();
return true;
}

@ -3,7 +3,7 @@
#include <components/esm/loadscpt.hpp>
#include <components/esm/variant.hpp>
#include <components/esm/locals.hpp>
#include <components/debug/debuglog.hpp>
#include <components/compiler/locals.hpp>
#include <components/compiler/exception.hpp>
@ -229,10 +229,10 @@ namespace MWScript
}
catch (std::exception& e)
{
std::cerr << "Failed to read local variable state for script '"
<< script << "' (legacy format): " << e.what()
<< "\nNum shorts: " << numshorts << " / " << mShorts.size()
<< " Num longs: " << numlongs << " / " << mLongs.size() << std::endl;
Log(Debug::Error) << "Failed to read local variable state for script '"
<< script << "' (legacy format): " << e.what()
<< "\nNum shorts: " << numshorts << " / " << mShorts.size()
<< " Num longs: " << numlongs << " / " << mLongs.size();
}
}
else

@ -1155,8 +1155,7 @@ namespace MWScript
virtual void execute (Interpreter::Runtime &runtime)
{
/// \todo implement traveling check
runtime.push (0);
runtime.push (MWBase::Environment::get().getWorld()->isPlayerTraveling());
}
};

@ -1,11 +1,12 @@
#include "scriptmanagerimp.hpp"
#include <cassert>
#include <iostream>
#include <sstream>
#include <exception>
#include <algorithm>
#include <components/debug/debuglog.hpp>
#include <components/esm/loadscpt.hpp>
#include <components/misc/stringops.hpp>
@ -65,14 +66,14 @@ namespace MWScript
}
catch (const std::exception& error)
{
std::cerr << "Error: An exception has been thrown: " << error.what() << std::endl;
Log(Debug::Error) << "Error: An exception has been thrown: " << error.what();
Success = false;
}
if (!Success)
{
std::cerr
<< "Warning: compiling failed: " << name << std::endl;
Log(Debug::Warning)
<< "Warning: compiling failed: " << name;
}
if (Success)
@ -121,8 +122,8 @@ namespace MWScript
}
catch (const std::exception& e)
{
std::cerr << "Execution of script " << name << " failed:" << std::endl;
std::cerr << e.what() << std::endl;
Log(Debug::Error) << "Execution of script " << name << " failed:";
Log(Debug::Error) << e.what();
iter->second.first.clear(); // don't execute again.
}

@ -1,6 +1,5 @@
#include "statsextensions.hpp"
#include <iostream>
#include <cmath>
#include <components/esm/loadnpc.hpp>
@ -9,7 +8,7 @@
#include <components/compiler/extensions.hpp>
#include <components/compiler/opcodes.hpp>
#include <components/debug/debuglog.hpp>
#include <components/interpreter/interpreter.hpp>
#include <components/interpreter/runtime.hpp>
#include <components/interpreter/opcodes.hpp>
@ -246,9 +245,10 @@ namespace MWScript
if (R()(runtime, false, true).isEmpty())
{
std::cerr
Log(Debug::Warning)
<< "Warning: Compensating for broken script in Morrowind.esm by "
<< "ignoring remote access to dagoth_ur_1" << std::endl;
<< "ignoring remote access to dagoth_ur_1";
return;
}
}
@ -261,6 +261,7 @@ namespace MWScript
.getDynamic (mIndex));
stat.setModified (diff + stat.getModified(), 0);
stat.setCurrentModified (diff + stat.getCurrentModified());
stat.setCurrent (diff + current);

@ -1,4 +1,4 @@
#include <iostream>
#include <components/debug/debuglog.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
@ -317,7 +317,7 @@ namespace MWScript
{
std::string error = "Warning: PositionCell: unknown interior cell (" + cellID + "), moving to exterior instead";
runtime.getContext().report (error);
std::cerr << error << std::endl;
Log(Debug::Warning) << error;
}
}
if(store)
@ -429,7 +429,7 @@ namespace MWScript
if(!cell)
{
runtime.getContext().report ("unknown cell (" + cellID + ")");
std::cerr << "unknown cell (" << cellID << ")\n";
Log(Debug::Error) << "Error: unknown cell (" << cellID << ")";
}
}
if(store)

@ -3,9 +3,9 @@
#include <memory>
#include <stdexcept>
#include <iostream>
#include <algorithm>
#include <components/debug/debuglog.hpp>
#include <components/vfs/manager.hpp>
namespace MWSound
@ -28,7 +28,7 @@ int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size)
int FFmpeg_Decoder::writePacket(void *, uint8_t *, int)
{
std::cerr<< "can't write to read-only stream" <<std::endl;
Log(Debug::Error) << "can't write to read-only stream";
return -1;
}
@ -343,7 +343,7 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *
char str[1024];
av_get_channel_layout_string(str, sizeof(str), (*mStream)->codec->channels,
(*mStream)->codec->channel_layout);
std::cerr<< "Unsupported channel layout: "<<str <<std::endl;
Log(Debug::Error) << "Unsupported channel layout: "<< str;
if((*mStream)->codec->channels == 1)
{
@ -385,7 +385,7 @@ size_t FFmpeg_Decoder::read(char *buffer, size_t bytes)
{
if(!mStream)
{
std::cerr<< "No audio stream" <<std::endl;
Log(Debug::Error) << "No audio stream";
return 0;
}
return readAVAudioData(buffer, bytes);
@ -395,7 +395,7 @@ void FFmpeg_Decoder::readAll(std::vector<char> &output)
{
if(!mStream)
{
std::cerr<< "No audio stream" <<std::endl;
Log(Debug::Error) << "No audio stream";
return;
}

@ -1,6 +1,5 @@
#include <algorithm>
#include <stdexcept>
#include <iostream>
#include <cstring>
#include <vector>
#include <memory>
@ -8,6 +7,7 @@
#include <stdint.h>
#include <components/debug/debuglog.hpp>
#include <components/vfs/manager.hpp>
#include <OpenThreads/Thread>
@ -44,8 +44,7 @@ ALCenum checkALCError(ALCdevice *device, const char *func, int line)
{
ALCenum err = alcGetError(device);
if(err != ALC_NO_ERROR)
std::cerr<< ">>>>>>>>> ALC error "<<alcGetString(device, err)<<" ("<<err<<") @ "<<
func<<":"<<line <<std::endl;
Log(Debug::Error) << "ALC error "<< alcGetString(device, err) << " (" << err << ") @ " << func << ":" << line;
return err;
}
#define getALCError(d) checkALCError((d), __FUNCTION__, __LINE__)
@ -54,8 +53,7 @@ ALenum checkALError(const char *func, int line)
{
ALenum err = alGetError();
if(err != AL_NO_ERROR)
std::cerr<< ">>>>>>>>> AL error "<<alGetString(err)<<" ("<<err<<") @ "<<
func<<":"<<line <<std::endl;
Log(Debug::Error) << "AL error " << alGetString(err) << " (" << err << ") @ " << func << ":" << line;
return err;
}
#define getALError() checkALError(__FUNCTION__, __LINE__)
@ -256,8 +254,7 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type)
}
}
std::cerr<< "Unsupported sound format ("<<getChannelConfigName(chans)<<", "<<
getSampleTypeName(type)<<")" <<std::endl;
Log(Debug::Warning) << "Unsupported sound format (" << getChannelConfigName(chans) << ", " << getSampleTypeName(type) << ")";
return AL_NONE;
}
@ -415,8 +412,9 @@ bool OpenAL_SoundStream::init(bool getLoudnessData)
mDecoder->getInfo(&mSampleRate, &chans, &type);
mFormat = getALFormat(chans, type);
}
catch(std::exception &e) {
std::cerr<< "Failed to get stream info: "<<e.what() <<std::endl;
catch(std::exception &e)
{
Log(Debug::Error) << "Failed to get stream info: " << e.what();
return false;
}
@ -522,7 +520,7 @@ bool OpenAL_SoundStream::process()
}
}
catch(std::exception&) {
std::cout<< "Error updating stream \""<<mDecoder->getName()<<"\"" <<std::endl;
Log(Debug::Error) << "Error updating stream \"" << mDecoder->getName() << "\"";
mIsFinished = true;
}
return !mIsFinished;
@ -593,17 +591,18 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname
{
deinit();
std::cout<< "Initializing OpenAL..." <<std::endl;
Log(Debug::Info) << "Initializing OpenAL...";
mDevice = alcOpenDevice(devname.c_str());
if(!mDevice && !devname.empty())
{
std::cerr<< "Failed to open \""<<devname<<"\", trying default" <<std::endl;
Log(Debug::Warning) << "Failed to open \"" << devname << "\", trying default";
mDevice = alcOpenDevice(nullptr);
}
if(!mDevice)
{
std::cerr<< "Failed to open default audio device" <<std::endl;
Log(Debug::Error) << "Failed to open default audio device";
return false;
}
@ -612,13 +611,13 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname
name = alcGetString(mDevice, ALC_ALL_DEVICES_SPECIFIER);
if(alcGetError(mDevice) != AL_NO_ERROR || !name)
name = alcGetString(mDevice, ALC_DEVICE_SPECIFIER);
std::cout<< "Opened \""<<name<<"\"" <<std::endl;
Log(Debug::Info) << "Opened \"" << name << "\"";
ALCint major=0, minor=0;
alcGetIntegerv(mDevice, ALC_MAJOR_VERSION, 1, &major);
alcGetIntegerv(mDevice, ALC_MINOR_VERSION, 1, &minor);
std::cout<< " ALC Version: "<<major<<"."<<minor<<"\n"<<
" ALC Extensions: "<<alcGetString(mDevice, ALC_EXTENSIONS) <<std::endl;
Log(Debug::Info) << " ALC Version: " << major << "." << minor <<"\n" <<
" ALC Extensions: " << alcGetString(mDevice, ALC_EXTENSIONS);
ALC.EXT_EFX = alcIsExtensionPresent(mDevice, "ALC_EXT_EFX");
ALC.SOFT_HRTF = alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF");
@ -650,7 +649,7 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname
}
if(index < 0)
std::cerr<< "Failed to find HRTF \""<<hrtfname<<"\", using default" <<std::endl;
Log(Debug::Warning) << "Failed to find HRTF \"" << hrtfname << "\", using default";
else
{
attrs.push_back(ALC_HRTF_ID_SOFT);
@ -663,7 +662,7 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname
mContext = alcCreateContext(mDevice, attrs.data());
if(!mContext || alcMakeContextCurrent(mContext) == ALC_FALSE)
{
std::cerr<< "Failed to setup audio context: "<<alcGetString(mDevice, alcGetError(mDevice)) <<std::endl;
Log(Debug::Error) << "Failed to setup audio context: "<<alcGetString(mDevice, alcGetError(mDevice));
if(mContext)
alcDestroyContext(mContext);
mContext = nullptr;
@ -672,23 +671,23 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname
return false;
}
std::cout<< " Vendor: "<<alGetString(AL_VENDOR)<<"\n"<<
" Renderer: "<<alGetString(AL_RENDERER)<<"\n"<<
" Version: "<<alGetString(AL_VERSION)<<"\n"<<
" Extensions: "<<alGetString(AL_EXTENSIONS)<<std::endl;
Log(Debug::Info) << " Vendor: "<<alGetString(AL_VENDOR)<<"\n"<<
" Renderer: "<<alGetString(AL_RENDERER)<<"\n"<<
" Version: "<<alGetString(AL_VERSION)<<"\n"<<
" Extensions: "<<alGetString(AL_EXTENSIONS);
if(!ALC.SOFT_HRTF)
std::cout<< "HRTF status unavailable" <<std::endl;
Log(Debug::Warning) << "HRTF status unavailable";
else
{
ALCint hrtf_state;
alcGetIntegerv(mDevice, ALC_HRTF_SOFT, 1, &hrtf_state);
if(!hrtf_state)
std::cout<< "HRTF disabled" <<std::endl;
Log(Debug::Info) << "HRTF disabled";
else
{
const ALCchar *hrtf = alcGetString(mDevice, ALC_HRTF_SPECIFIER_SOFT);
std::cout<< "Enabled HRTF "<<hrtf <<std::endl;
Log(Debug::Info) << "Enabled HRTF " << hrtf;
}
}
@ -716,7 +715,7 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname
}
if(mFreeSources.empty())
{
std::cerr<< "Could not allocate any sound sources" <<std::endl;
Log(Debug::Warning) << "Could not allocate any sound sourcess";
alcMakeContextCurrent(nullptr);
alcDestroyContext(mContext);
mContext = nullptr;
@ -724,7 +723,7 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname
mDevice = nullptr;
return false;
}
std::cout<< "Allocated "<<mFreeSources.size()<<" sound sources" <<std::endl;
Log(Debug::Info) << "Allocated " << mFreeSources.size() << " sound sources";
if(ALC.EXT_EFX)
{
@ -775,7 +774,7 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname
alFilteri(mWaterFilter, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
if(alGetError() == AL_NO_ERROR)
{
std::cout<< "Low-pass filter supported" <<std::endl;
Log(Debug::Info) << "Low-pass filter supported";
alFilterf(mWaterFilter, AL_LOWPASS_GAIN, 0.9f);
alFilterf(mWaterFilter, AL_LOWPASS_GAINHF, 0.125f);
}
@ -795,12 +794,12 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname
{
alEffecti(mDefaultEffect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB);
if(alGetError() == AL_NO_ERROR)
std::cout<< "EAX Reverb supported" <<std::endl;
Log(Debug::Info) << "EAX Reverb supported";
else
{
alEffecti(mDefaultEffect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
if(alGetError() == AL_NO_ERROR)
std::cout<< "Standard Reverb supported" <<std::endl;
Log(Debug::Info) << "Standard Reverb supported";
}
EFXEAXREVERBPROPERTIES props = EFX_REVERB_PRESET_GENERIC;
props.flGain = 0.0f;
@ -891,7 +890,7 @@ void OpenAL_Output::setHrtf(const std::string &hrtfname, HrtfMode hrtfmode)
{
if(!mDevice || !ALC.SOFT_HRTF)
{
std::cerr<< "HRTF extension not present" <<std::endl;
Log(Debug::Info) << "HRTF extension not present";
return;
}
@ -924,7 +923,7 @@ void OpenAL_Output::setHrtf(const std::string &hrtfname, HrtfMode hrtfmode)
}
if(index < 0)
std::cerr<< "Failed to find HRTF name \""<<hrtfname<<"\", using default" <<std::endl;
Log(Debug::Warning) << "Failed to find HRTF name \"" << hrtfname << "\", using default";
else
{
attrs.push_back(ALC_HRTF_ID_SOFT);
@ -937,11 +936,11 @@ void OpenAL_Output::setHrtf(const std::string &hrtfname, HrtfMode hrtfmode)
ALCint hrtf_state;
alcGetIntegerv(mDevice, ALC_HRTF_SOFT, 1, &hrtf_state);
if(!hrtf_state)
std::cout<< "HRTF disabled" <<std::endl;
Log(Debug::Info) << "HRTF disabled";
else
{
const ALCchar *hrtf = alcGetString(mDevice, ALC_HRTF_SPECIFIER_SOFT);
std::cout<< "Enabled HRTF "<<hrtf <<std::endl;
Log(Debug::Info) << "Enabled HRTF " << hrtf;
}
}
@ -977,7 +976,7 @@ std::pair<Sound_Handle,size_t> OpenAL_Output::loadSound(const std::string &fname
}
catch(std::exception &e)
{
std::cerr<< "Failed to load audio from "<<fname<<": "<<e.what() <<std::endl;
Log(Debug::Error) << "Failed to load audio from " << fname << ": " << e.what();
}
if(data.empty())
@ -1139,7 +1138,7 @@ bool OpenAL_Output::playSound(Sound *sound, Sound_Handle data, float offset)
if(mFreeSources.empty())
{
std::cerr<< "No free sources!" <<std::endl;
Log(Debug::Warning) << "No free sources!";
return false;
}
source = mFreeSources.front();
@ -1168,7 +1167,7 @@ bool OpenAL_Output::playSound3D(Sound *sound, Sound_Handle data, float offset)
if(mFreeSources.empty())
{
std::cerr<< "No free sources!" <<std::endl;
Log(Debug::Warning) << "No free sources!";
return false;
}
source = mFreeSources.front();
@ -1236,13 +1235,14 @@ bool OpenAL_Output::streamSound(DecoderPtr decoder, Stream *sound)
{
if(mFreeSources.empty())
{
std::cerr<< "No free sources!" <<std::endl;
Log(Debug::Warning) << "No free sources!";
return false;
}
ALuint source = mFreeSources.front();
if(sound->getIsLooping())
std::cout <<"Warning: cannot loop stream \""<<decoder->getName()<<"\""<< std::endl;
Log(Debug::Warning) << "Warning: cannot loop stream \"" << decoder->getName() << "\"";
initCommon2D(source, sound->getPosition(), sound->getRealVolume(), sound->getPitch(),
false, sound->getUseEnv());
if(getALError() != AL_NO_ERROR)
@ -1266,13 +1266,14 @@ bool OpenAL_Output::streamSound3D(DecoderPtr decoder, Stream *sound, bool getLou
{
if(mFreeSources.empty())
{
std::cerr<< "No free sources!" <<std::endl;
Log(Debug::Warning) << "No free sources!";
return false;
}
ALuint source = mFreeSources.front();
if(sound->getIsLooping())
std::cout <<"Warning: cannot loop stream \""<<decoder->getName()<<"\""<< std::endl;
Log(Debug::Warning) << "Warning: cannot loop stream \"" << decoder->getName() << "\"";
initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(),
sound->getRealVolume(), sound->getPitch(), false, sound->getUseEnv());
if(getALError() != AL_NO_ERROR)

@ -1,6 +1,5 @@
#include "soundmanagerimp.hpp"
#include <iostream>
#include <algorithm>
#include <map>
#include <numeric>
@ -8,7 +7,7 @@
#include <osg/Matrixf>
#include <components/misc/rng.hpp>
#include <components/debug/debuglog.hpp>
#include <components/vfs/manager.hpp>
#include "../mwbase/environment.hpp"
@ -81,7 +80,7 @@ namespace MWSound
if(!useSound)
{
std::cout<< "Sound disabled." <<std::endl;
Log(Debug::Info) << "Sound disabled.";
return;
}
@ -93,23 +92,28 @@ namespace MWSound
std::string devname = Settings::Manager::getString("device", "Sound");
if(!mOutput->init(devname, hrtfname, hrtfmode))
{
std::cerr<< "Failed to initialize audio output, sound disabled" <<std::endl;
Log(Debug::Error) << "Failed to initialize audio output, sound disabled";
return;
}
std::vector<std::string> names = mOutput->enumerate();
std::cout <<"Enumerated output devices:\n";
std::stringstream stream;
stream << "Enumerated output devices:\n";
for(const std::string &name : names)
std::cout <<" "<<name<<"\n";
std::cout.flush();
stream << " " << name;
Log(Debug::Info) << stream.str();
stream.str("");
names = mOutput->enumerateHrtf();
if(!names.empty())
{
std::cout<< "Enumerated HRTF names:\n";
stream << "Enumerated HRTF names:\n";
for(const std::string &name : names)
std::cout <<" "<<name<<"\n";
std::cout.flush();
stream << " " << name;
Log(Debug::Info) << stream.str();
}
}
@ -221,7 +225,7 @@ namespace MWSound
do {
if(mUnusedBuffers.empty())
{
std::cerr<< "No unused sound buffers to free, using "<<mBufferCacheSize<<" bytes!" <<std::endl;
Log(Debug::Warning) << "No unused sound buffers to free, using " << mBufferCacheSize << " bytes!";
break;
}
Sound_Buffer *unused = mUnusedBuffers.back();
@ -360,7 +364,7 @@ namespace MWSound
{
if(!mOutput->isInitialized())
return;
std::cout <<"Playing "<<filename<< std::endl;
Log(Debug::Info) << "Playing " << filename;
mLastPlayedMusic = filename;
stopMusic();

@ -1,5 +1,7 @@
#include "statemanagerimp.hpp"
#include <components/debug/debuglog.hpp>
#include <components/esm/esmwriter.hpp>
#include <components/esm/esmreader.hpp>
#include <components/esm/cellid.hpp>
@ -157,7 +159,7 @@ void MWState::StateManager::newGame (bool bypass)
std::stringstream error;
error << "Failed to start new game: " << e.what();
std::cerr << error.str() << std::endl;
Log(Debug::Error) << error.str();
cleanup (true);
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
@ -283,7 +285,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
// Ensure we have written the number of records that was estimated
if (writer.getRecordCount() != recordCount+1) // 1 extra for TES3 record
std::cerr << "Warning: number of written savegame records does not match. Estimated: " << recordCount+1 << ", written: " << writer.getRecordCount() << std::endl;
Log(Debug::Warning) << "Warning: number of written savegame records does not match. Estimated: " << recordCount+1 << ", written: " << writer.getRecordCount();
writer.close();
@ -305,7 +307,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
std::stringstream error;
error << "Failed to save game: " << e.what();
std::cerr << error.str() << std::endl;
Log(Debug::Error) << error.str();
std::vector<std::string> buttons;
buttons.push_back("#{sOk}");
@ -483,7 +485,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str
default:
// ignore invalid records
std::cerr << "Warning: Ignoring unknown record: " << n.toString() << std::endl;
Log(Debug::Warning) << "Warning: Ignoring unknown record: " << n.toString();
reader.skipRecord();
}
int progressPercent = static_cast<int>(float(reader.getFileOffset())/total*100);
@ -549,7 +551,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str
std::stringstream error;
error << "Failed to load saved game: " << e.what();
std::cerr << error.str() << std::endl;
Log(Debug::Error) << error.str();
cleanup (true);
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
@ -625,7 +627,7 @@ bool MWState::StateManager::verifyProfile(const ESM::SavedGame& profile) const
if (std::find(selectedContentFiles.begin(), selectedContentFiles.end(), *it)
== selectedContentFiles.end())
{
std::cerr << "Warning: Savegame dependency " << *it << " is missing." << std::endl;
Log(Debug::Warning) << "Warning: Savegame dependency " << *it << " is missing.";
notFound = true;
}
}
@ -653,7 +655,7 @@ void MWState::StateManager::writeScreenshot(std::vector<char> &imageData) const
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("jpg");
if (!readerwriter)
{
std::cerr << "Error: Unable to write screenshot, can't find a jpg ReaderWriter" << std::endl;
Log(Debug::Error) << "Error: Unable to write screenshot, can't find a jpg ReaderWriter";
return;
}
@ -661,7 +663,7 @@ void MWState::StateManager::writeScreenshot(std::vector<char> &imageData) const
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*screenshot, ostream);
if (!result.success())
{
std::cerr << "Error: Unable to write screenshot: " << result.message() << " code " << result.status() << std::endl;
Log(Debug::Error) << "Error: Unable to write screenshot: " << result.message() << " code " << result.status();
return;
}

@ -1,7 +1,6 @@
#include "cellpreloader.hpp"
#include <iostream>
#include <components/debug/debuglog.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/bulletshapemanager.hpp>
@ -229,12 +228,12 @@ namespace MWWorld
{
if (!mWorkQueue)
{
std::cerr << "Error: can't preload, no work queue set " << std::endl;
Log(Debug::Error) << "Error: can't preload, no work queue set";
return;
}
if (cell->getState() == CellStore::State_Unloaded)
{
std::cerr << "Error: can't preload objects for unloaded cell" << std::endl;
Log(Debug::Error) << "Error: can't preload objects for unloaded cell";
return;
}

@ -1,7 +1,6 @@
#include "cells.hpp"
#include <iostream>
#include <components/debug/debuglog.hpp>
#include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp>
#include <components/esm/defs.hpp>
@ -350,7 +349,7 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type,
catch (...)
{
// silently drop cells that don't exist anymore
std::cerr << "Warning: Dropping state for cell " << state.mId.mWorldspace << " (cell no longer exists)" << std::endl;
Log(Debug::Warning) << "Warning: Dropping state for cell " << state.mId.mWorldspace << " (cell no longer exists)";
reader.skipRecord();
return true;
}

@ -1,8 +1,9 @@
#include "cellstore.hpp"
#include <iostream>
#include <algorithm>
#include <components/debug/debuglog.hpp>
#include <components/esm/cellstate.hpp>
#include <components/esm/cellid.hpp>
#include <components/esm/esmreader.hpp>
@ -138,7 +139,7 @@ namespace
return;
}
std::cerr << "Warning: Dropping reference to " << state.mRef.mRefID << " (invalid content file link)" << std::endl;
Log(Debug::Warning) << "Warning: Dropping reference to " << state.mRef.mRefID << " (invalid content file link)";
return;
}
@ -196,9 +197,9 @@ namespace MWWorld
}
else
{
std::cerr
Log(Debug::Warning)
<< "Warning: could not resolve cell reference '" << ref.mRefID << "'"
<< " (dropping reference)" << std::endl;
<< " (dropping reference)";
}
}
@ -497,7 +498,7 @@ namespace MWWorld
}
catch (std::exception& e)
{
std::cerr << "An error occurred listing references for cell " << getCell()->getDescription() << ": " << e.what() << std::endl;
Log(Debug::Error) << "An error occurred listing references for cell " << getCell()->getDescription() << ": " << e.what();
}
}
@ -553,7 +554,7 @@ namespace MWWorld
}
catch (std::exception& e)
{
std::cerr << "An error occurred loading references for cell " << getCell()->getDescription() << ": " << e.what() << std::endl;
Log(Debug::Error) << "An error occurred loading references for cell " << getCell()->getDescription() << ": " << e.what();
}
}
@ -659,11 +660,10 @@ namespace MWWorld
case ESM::REC_WEAP: mWeapons.load(ref, deleted, store); break;
case ESM::REC_BODY: mBodyParts.load(ref, deleted, store); break;
case 0: std::cerr << "Cell reference '" + ref.mRefID + "' not found!\n"; return;
case 0: Log(Debug::Error) << "Cell reference '" + ref.mRefID + "' not found!"; return;
default:
std::cerr
<< "Error: Ignoring reference '" << ref.mRefID << "' of unhandled type\n";
Log(Debug::Error) << "Error: Ignoring reference '" << ref.mRefID << "' of unhandled type";
return;
}
@ -756,7 +756,7 @@ namespace MWWorld
int type = MWBase::Environment::get().getWorld()->getStore().find(cref.mRefID);
if (type == 0)
{
std::cerr << "Dropping reference to '" << cref.mRefID << "' (object no longer exists)" << std::endl;
Log(Debug::Warning) << "Dropping reference to '" << cref.mRefID << "' (object no longer exists)";
reader.skipHSubUntil("OBJE");
continue;
}
@ -892,7 +892,7 @@ namespace MWWorld
if (!visitor.mFound)
{
std::cerr << "Warning: Dropping moved ref tag for " << refnum.mIndex << " (moved object no longer exists)" << std::endl;
Log(Debug::Warning) << "Warning: Dropping moved ref tag for " << refnum.mIndex << " (moved object no longer exists)";
continue;
}
@ -902,8 +902,8 @@ namespace MWWorld
if (otherCell == NULL)
{
std::cerr << "Warning: Dropping moved ref tag for " << movedRef->mRef.getRefId()
<< " (target cell " << movedTo.mWorldspace << " no longer exists). Reference moved back to its original location." << std::endl;
Log(Debug::Warning) << "Warning: Dropping moved ref tag for " << movedRef->mRef.getRefId()
<< " (target cell " << movedTo.mWorldspace << " no longer exists). Reference moved back to its original location.";
// Note by dropping tag the object will automatically re-appear in its original cell, though potentially at inapproriate coordinates.
// Restore original coordinates:
movedRef->mData.setPosition(movedRef->mRef.getPosition());
@ -913,7 +913,7 @@ namespace MWWorld
if (otherCell == this)
{
// Should never happen unless someone's tampering with files.
std::cerr << "Found invalid moved ref, ignoring" << std::endl;
Log(Debug::Warning) << "Found invalid moved ref, ignoring";
continue;
}

@ -4,6 +4,7 @@
#include <typeinfo>
#include <stdexcept>
#include <components/debug/debuglog.hpp>
#include <components/esm/inventorystate.hpp>
#include "../mwbase/environment.hpp"
@ -502,7 +503,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::
}
catch (const std::exception& e)
{
std::cerr << "Warning: MWWorld::ContainerStore::addInitialItem: " << e.what() << std::endl;
Log(Debug::Warning) << "Warning: MWWorld::ContainerStore::addInitialItem: " << e.what();
}
}
@ -826,10 +827,10 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& inventory)
case ESM::REC_WEAP: readEquipmentState (getState (weapons, state), thisIndex, inventory); break;
case ESM::REC_LIGH: readEquipmentState (getState (lights, state), thisIndex, inventory); break;
case 0:
std::cerr << "Dropping inventory reference to '" << state.mRef.mRefID << "' (object no longer exists)" << std::endl;
Log(Debug::Warning) << "Dropping inventory reference to '" << state.mRef.mRefID << "' (object no longer exists)";
break;
default:
std::cerr << "Warning: Invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl;
Log(Debug::Warning) << "Warning: Invalid item type in inventory state, refid " << state.mRef.mRefID;
break;
}
}

@ -2,10 +2,10 @@
#define CONTENTLOADER_HPP
#include <iosfwd>
#include <iostream>
#include <boost/filesystem/path.hpp>
#include <MyGUI_TextIterator.h>
#include <components/debug/debuglog.hpp>
#include "components/loadinglistener/loadinglistener.hpp"
namespace MWWorld
@ -24,8 +24,8 @@ struct ContentLoader
virtual void load(const boost::filesystem::path& filepath, int& index)
{
std::cout << "Loading content file " << filepath.string() << std::endl;
mListener.setLabel(MyGUI::TextIterator::toTagsString(filepath.string()));
Log(Debug::Info) << "Loading content file " << filepath.string();
mListener.setLabel(MyGUI::TextIterator::toTagsString(filepath.string()));
}
protected:

@ -1,12 +1,11 @@
#include "esmstore.hpp"
#include <set>
#include <iostream>
#include <boost/filesystem/operations.hpp>
#include <components/debug/debuglog.hpp>
#include <components/loadinglistener/loadinglistener.hpp>
#include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp>
@ -84,7 +83,7 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener)
}
else
{
std::cerr << "error: info record without dialog" << std::endl;
Log(Debug::Error) << "Error: info record without dialog";
esm.skipRecord();
}
} else if (n.intval == ESM::REC_MGEF) {
@ -170,7 +169,7 @@ void ESMStore::validate()
const ESM::Faction *fact = mFactions.search(npcFaction);
if (!fact)
{
std::cerr << "NPC '" << npc.mId << "' (" << npc.mName << ") has nonexistent faction '" << npc.mFaction << "', ignoring it." << std::endl;
Log(Debug::Verbose) << "NPC '" << npc.mId << "' (" << npc.mName << ") has nonexistent faction '" << npc.mFaction << "', ignoring it.";
npc.mFaction = "";
npc.mNpdt.mRank = -1;
changed = true;
@ -183,7 +182,7 @@ void ESMStore::validate()
const ESM::Class *cls = mClasses.search(npcClass);
if (!cls)
{
std::cerr << "NPC '" << npc.mId << "' (" << npc.mName << ") has nonexistent class '" << npc.mClass << "', using '" << defaultCls << "' class as replacement." << std::endl;
Log(Debug::Verbose) << "NPC '" << npc.mId << "' (" << npc.mName << ") has nonexistent class '" << npc.mClass << "', using '" << defaultCls << "' class as replacement.";
npc.mClass = defaultCls;
changed = true;
}

@ -3,6 +3,7 @@
#include <iterator>
#include <algorithm>
#include <components/debug/debuglog.hpp>
#include <components/esm/loadench.hpp>
#include <components/esm/inventorystate.hpp>
#include <components/misc/rng.hpp>
@ -895,7 +896,7 @@ void MWWorld::InventoryStore::updateRechargingItems()
enchantmentId);
if (!enchantment)
{
std::cerr << "Warning: Can't find enchantment '" << enchantmentId << "' on item " << it->getCellRef().getRefId() << std::endl;
Log(Debug::Warning) << "Warning: Can't find enchantment '" << enchantmentId << "' on item " << it->getCellRef().getRefId();
continue;
}

@ -1,7 +1,6 @@
#include "livecellref.hpp"
#include <iostream>
#include <components/debug/debuglog.hpp>
#include <components/esm/objectstate.hpp>
#include "../mwbase/environment.hpp"
@ -38,10 +37,9 @@ void MWWorld::LiveCellRefBase::loadImp (const ESM::ObjectState& state)
}
catch (const std::exception& exception)
{
std::cerr
Log(Debug::Error)
<< "Error: failed to load state for local script " << scriptId
<< " because an exception has been thrown: " << exception.what()
<< std::endl;
<< " because an exception has been thrown: " << exception.what();
}
}
}
@ -51,7 +49,7 @@ void MWWorld::LiveCellRefBase::loadImp (const ESM::ObjectState& state)
if (!mRef.getSoul().empty() && !MWBase::Environment::get().getWorld()->getStore().get<ESM::Creature>().search(mRef.getSoul()))
{
std::cerr << "Soul '" << mRef.getSoul() << "' not found, removing the soul from soul gem" << std::endl;
Log(Debug::Warning) << "Soul '" << mRef.getSoul() << "' not found, removing the soul from soul gem";
mRef.setSoul(std::string());
}
}

@ -1,14 +1,12 @@
#include "localscripts.hpp"
#include <iostream>
#include <components/debug/debuglog.hpp>
#include "esmstore.hpp"
#include "cellstore.hpp"
#include "class.hpp"
#include "containerstore.hpp"
namespace
{
@ -93,7 +91,7 @@ void MWWorld::LocalScripts::add (const std::string& scriptName, const Ptr& ptr)
for (std::list<std::pair<std::string, Ptr> >::iterator iter = mScripts.begin(); iter!=mScripts.end(); ++iter)
if (iter->second==ptr)
{
std::cerr << "Error: tried to add local script twice for " << ptr.getCellRef().getRefId() << std::endl;
Log(Debug::Warning) << "Error: tried to add local script twice for " << ptr.getCellRef().getRefId();
remove(ptr);
break;
}
@ -102,15 +100,15 @@ void MWWorld::LocalScripts::add (const std::string& scriptName, const Ptr& ptr)
}
catch (const std::exception& exception)
{
std::cerr
Log(Debug::Error)
<< "failed to add local script " << scriptName
<< " because an exception has been thrown: " << exception.what() << std::endl;
<< " because an exception has been thrown: " << exception.what();
}
}
else
std::cerr
Log(Debug::Warning)
<< "failed to add local script " << scriptName
<< " because the script does not exist." << std::endl;
<< " because the script does not exist.";
}
void MWWorld::LocalScripts::addCell (CellStore *cell)

@ -1,7 +1,8 @@
#include "player.hpp"
#include <stdexcept>
#include <iostream>
#include <components/debug/debuglog.hpp>
#include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp>
@ -364,7 +365,7 @@ namespace MWWorld
if (!player.mObject.mEnabled)
{
std::cerr << "Warning: Savegame attempted to disable the player." << std::endl;
Log(Debug::Warning) << "Warning: Savegame attempted to disable the player.";
player.mObject.mEnabled = true;
}
@ -391,7 +392,7 @@ namespace MWWorld
}
catch (...)
{
std::cerr << "Warning: Player cell '" << player.mCellId.mWorldspace << "' no longer exists" << std::endl;
Log(Debug::Warning) << "Warning: Player cell '" << player.mCellId.mWorldspace << "' no longer exists";
// Cell no longer exists. The loader will have to choose a default cell.
mCellStore = NULL;
}

@ -1,11 +1,12 @@
#include "projectilemanager.hpp"
#include <iomanip>
#include <iostream>
#include <osg/PositionAttitudeTransform>
#include <osg/ComputeBoundsVisitor>
#include <components/debug/debuglog.hpp>
#include <components/esm/esmwriter.hpp>
#include <components/esm/projectilestate.hpp>
@ -647,7 +648,7 @@ namespace MWWorld
}
catch(...)
{
std::cerr << "Warning: Failed to recreate magic projectile from saved data (id \"" << state.mSpellId << "\" no longer exists?)" << std::endl;
Log(Debug::Warning) << "Warning: Failed to recreate magic projectile from saved data (id \"" << state.mSpellId << "\" no longer exists?)";
return true;
}

@ -1,8 +1,8 @@
#include "scene.hpp"
#include <limits>
#include <iostream>
#include <components/debug/debuglog.hpp>
#include <components/loadinglistener/loadinglistener.hpp>
#include <components/misc/resourcehelpers.hpp>
#include <components/settings/settings.hpp>
@ -56,7 +56,7 @@ namespace
{
if (ptr.getRefData().getBaseNode() || physics.getActor(ptr))
{
std::cerr << "Warning: Tried to add " << ptr.getCellRef().getRefId() << " to the scene twice" << std::endl;
Log(Debug::Warning) << "Warning: Tried to add " << ptr.getCellRef().getRefId() << " to the scene twice";
return;
}
@ -160,7 +160,7 @@ namespace
catch (const std::exception& e)
{
std::string error ("failed to render '" + ptr.getCellRef().getRefId() + "': ");
std::cerr << error + e.what() << std::endl;
Log(Debug::Error) << error + e.what();
}
}
@ -232,7 +232,7 @@ namespace MWWorld
void Scene::unloadCell (CellStoreCollection::iterator iter)
{
std::cout << "Unloading cell\n";
Log(Debug::Info) << "Unloading cell " << (*iter)->getCell()->getDescription();
ListAndResetObjectsVisitor visitor;
(*iter)->forEach<ListAndResetObjectsVisitor>(visitor);
@ -270,7 +270,7 @@ namespace MWWorld
if(result.second)
{
std::cout << "Loading cell " << cell->getCell()->getDescription() << std::endl;
Log(Debug::Info) << "Loading cell " << cell->getCell()->getDescription();
float verts = ESM::Land::LAND_SIZE;
float worldsize = ESM::Land::REAL_SIZE;
@ -546,7 +546,7 @@ namespace MWWorld
return;
}
std::cout << "Changing to interior\n";
Log(Debug::Info) << "Changing to interior";
// unload
CellStoreCollection::iterator active = mActiveCells.begin();
@ -624,7 +624,7 @@ namespace MWWorld
}
catch (std::exception& e)
{
std::cerr << "failed to render '" << ptr.getCellRef().getRefId() << "': " << e.what() << std::endl;
Log(Debug::Error) << "failed to render '" << ptr.getCellRef().getRefId() << "': " << e.what();
}
}

@ -1,5 +1,7 @@
#include "store.hpp"
#include <components/debug/debuglog.hpp>
#include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp>
@ -8,7 +10,6 @@
#include <stdexcept>
#include <sstream>
#include <iostream>
namespace
{
@ -692,7 +693,7 @@ namespace MWWorld
if (it_lease != wipecell->mLeasedRefs.end())
wipecell->mLeasedRefs.erase(it_lease);
else
std::cerr << "Error: can't find " << it->mRefNum.mIndex << " " << it->mRefNum.mContentFile << " in leasedRefs " << std::endl;
Log(Debug::Error) << "Error: can't find " << it->mRefNum.mIndex << " " << it->mRefNum.mContentFile << " in leasedRefs";
}
*itold = *it;
}

@ -3,6 +3,8 @@
#include <osg/Group>
#include <osg/ComputeBoundsVisitor>
#include <components/debug/debuglog.hpp>
#include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp>
#include <components/esm/cellid.hpp>
@ -153,7 +155,8 @@ namespace MWWorld
mGodMode(false), mScriptsEnabled(true), mContentFiles (contentFiles), mUserDataPath(userDataPath),
mActivationDistanceOverride (activationDistanceOverride), mStartupScript(startupScript),
mStartCell (startCell), mDistanceToFacedObject(-1), mTeleportEnabled(true),
mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0), mSpellPreloadTimer(0.f)
mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0),
mPlayerTraveling(false), mPlayerInJail(false), mSpellPreloadTimer(0.f)
{
mPhysics.reset(new MWPhysics::PhysicsSystem(resourceSystem, rootNode));
mRendering.reset(new MWRender::RenderingManager(viewer, rootNode, resourceSystem, workQueue, &mFallback, resourcePath));
@ -311,6 +314,8 @@ namespace MWWorld
mGoToJail = false;
mTeleportEnabled = true;
mLevitationEnabled = true;
mPlayerTraveling = false;
mPlayerInJail = false;
fillGlobalVariables();
}
@ -1642,6 +1647,15 @@ namespace MWWorld
if (mGoToJail && !paused)
goToJail();
// Reset "traveling" flag - there was a frame to detect traveling.
mPlayerTraveling = false;
// The same thing for "in jail" flag: reset it if:
// 1. Player was in jail
// 2. Jailing window was closed
if (mPlayerInJail && !mGoToJail && !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Jail))
mPlayerInJail = false;
updateWeather(duration, paused);
if (!paused)
@ -1794,7 +1808,7 @@ namespace MWWorld
}
catch (std::exception& e)
{
std::cerr << "Error updating window manager: " << e.what() << std::endl;
Log(Debug::Error) << "Error updating window manager: " << e.what();
}
}
@ -3075,7 +3089,7 @@ namespace MWWorld
if ( closestMarker.isEmpty() )
{
std::cerr << "Failed to teleport: no closest marker found" << std::endl;
Log(Debug::Warning) << "Failed to teleport: no closest marker found";
return;
}
@ -3250,19 +3264,19 @@ namespace MWWorld
MWWorld::ConstPtr prisonMarker = getClosestMarker( ptr, "prisonmarker" );
if ( prisonMarker.isEmpty() )
{
std::cerr << "Failed to confiscate items: no closest prison marker found." << std::endl;
Log(Debug::Warning) << "Failed to confiscate items: no closest prison marker found.";
return;
}
std::string prisonName = prisonMarker.getCellRef().getDestCell();
if ( prisonName.empty() )
{
std::cerr << "Failed to confiscate items: prison marker not linked to prison interior" << std::endl;
Log(Debug::Warning) << "Failed to confiscate items: prison marker not linked to prison interior";
return;
}
MWWorld::CellStore *prison = getInterior( prisonName );
if ( !prison )
{
std::cerr << "Failed to confiscate items: failed to load cell " << prisonName << std::endl;
Log(Debug::Warning) << "Failed to confiscate items: failed to load cell " << prisonName;
return;
}
@ -3272,7 +3286,7 @@ namespace MWWorld
MWBase::Environment::get().getMechanicsManager()->confiscateStolenItems(ptr, closestChest);
}
else
std::cerr << "Failed to confiscate items: no stolen_goods container found" << std::endl;
Log(Debug::Warning) << "Failed to confiscate items: no stolen_goods container found";
}
void World::goToJail()
@ -3281,6 +3295,7 @@ namespace MWWorld
{
// Reset bounty and forget the crime now, but don't change cell yet (the player should be able to read the dialog text first)
mGoToJail = true;
mPlayerInJail = true;
MWWorld::Ptr player = getPlayerPtr();
@ -3306,10 +3321,17 @@ namespace MWWorld
bool World::isPlayerInJail() const
{
if (mGoToJail)
return true;
return mPlayerInJail;
}
return MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Jail);
void World::setPlayerTraveling(bool traveling)
{
mPlayerTraveling = traveling;
}
bool World::isPlayerTraveling() const
{
return mPlayerTraveling;
}
float World::getTerrainHeightAt(const osg::Vec3f& worldPos) const

@ -168,6 +168,8 @@ namespace MWWorld
bool mLevitationEnabled;
bool mGoToJail;
int mDaysInPrison;
bool mPlayerTraveling;
bool mPlayerInJail;
float mSpellPreloadTimer;
@ -672,6 +674,9 @@ namespace MWWorld
bool isPlayerInJail() const override;
void setPlayerTraveling(bool traveling) override;
bool isPlayerTraveling() const override;
/// Return terrain height at \a worldPos position.
float getTerrainHeightAt(const osg::Vec3f& worldPos) const override;

@ -1,7 +1,9 @@
find_package(GTest REQUIRED)
find_package(GMock REQUIRED)
if (GTEST_FOUND)
if (GTEST_FOUND AND GMOCK_FOUND)
include_directories(SYSTEM ${GTEST_INCLUDE_DIRS})
include_directories(SYSTEM ${GMOCK_INCLUDE_DIRS})
file(GLOB UNITTEST_SRC_FILES
../openmw/mwworld/store.cpp
@ -13,17 +15,22 @@ if (GTEST_FOUND)
esm/test_fixed_string.cpp
misc/test_stringops.cpp
nifloader/testbulletnifloader.cpp
)
source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES})
openmw_add_executable(openmw_test_suite openmw_test_suite.cpp ${UNITTEST_SRC_FILES})
target_link_libraries(openmw_test_suite ${GTEST_BOTH_LIBRARIES} components)
target_link_libraries(openmw_test_suite ${GMOCK_LIBRARIES} components)
# Fix for not visible pthreads functions for linker with glibc 2.15
if (UNIX AND NOT APPLE)
target_link_libraries(openmw_test_suite ${CMAKE_THREAD_LIBS_INIT})
endif()
endif()
if (BUILD_WITH_CODE_COVERAGE)
add_definitions(--coverage)
target_link_libraries(openmw_test_suite gcov)
endif()
endif()

@ -0,0 +1,951 @@
#include <components/nifbullet/bulletnifloader.hpp>
#include <components/bullethelpers/processtrianglecallback.hpp>
#include <components/nif/node.hpp>
#include <BulletCollision/CollisionShapes/btBoxShape.h>
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
#include <BulletCollision/CollisionShapes/btTriangleMesh.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
namespace
{
template <class T>
bool compareObjects(const T* lhs, const T* rhs)
{
return (!lhs && !rhs) || (lhs && rhs && *lhs == *rhs);
}
std::vector<btVector3> getTriangles(const btBvhTriangleMeshShape& shape)
{
std::vector<btVector3> result;
auto callback = BulletHelpers::makeProcessTriangleCallback([&] (btVector3* triangle, int, int) {
for (std::size_t i = 0; i < 3; ++i)
result.push_back(triangle[i]);
});
btVector3 aabbMin;
btVector3 aabbMax;
shape.getAabb(btTransform::getIdentity(), aabbMin, aabbMax);
shape.processAllTriangles(&callback, aabbMin, aabbMax);
return result;
}
}
static std::ostream& operator <<(std::ostream& stream, const btVector3& value)
{
return stream << "btVector3 {"
<< std::setprecision(std::numeric_limits<float>::max_exponent10) << value.getX() << ", "
<< std::setprecision(std::numeric_limits<float>::max_exponent10) << value.getY() << ", "
<< std::setprecision(std::numeric_limits<float>::max_exponent10) << value.getZ() << "}";
}
static std::ostream& operator <<(std::ostream& stream, const btMatrix3x3& value)
{
stream << "btMatrix3x3 {";
for (int i = 0; i < 3; ++i)
stream << value.getRow(i) << ", ";
return stream << "}";
}
static std::ostream& operator <<(std::ostream& stream, const btTransform& value)
{
return stream << "btTransform {" << value.getBasis() << ", " << value.getOrigin() << "}";
}
static std::ostream& operator <<(std::ostream& stream, const btCollisionShape* value);
static std::ostream& operator <<(std::ostream& stream, const btCompoundShape& value)
{
stream << "btCompoundShape {" << value.getLocalScaling() << ", ";
stream << "{";
for (int i = 0; i < value.getNumChildShapes(); ++i)
stream << value.getChildShape(i) << ", ";
stream << "},";
stream << "{";
for (int i = 0; i < value.getNumChildShapes(); ++i)
stream << value.getChildTransform(i) << ", ";
stream << "}";
return stream << "}";
}
static std::ostream& operator <<(std::ostream& stream, const btBoxShape& value)
{
return stream << "btBoxShape {" << value.getLocalScaling() << ", " << value.getHalfExtentsWithoutMargin() << "}";
}
namespace Resource
{
static std::ostream& operator <<(std::ostream& stream, const TriangleMeshShape& value)
{
stream << "Resource::TriangleMeshShape {" << value.getLocalScaling() << ", "
<< value.usesQuantizedAabbCompression() << ", " << value.getOwnsBvh() << ", {";
auto callback = BulletHelpers::makeProcessTriangleCallback([&] (btVector3* triangle, int, int) {
for (std::size_t i = 0; i < 3; ++i)
stream << triangle[i] << ", ";
});
btVector3 aabbMin;
btVector3 aabbMax;
value.getAabb(btTransform::getIdentity(), aabbMin, aabbMax);
value.processAllTriangles(&callback, aabbMin, aabbMax);
return stream << "}}";
}
}
static std::ostream& operator <<(std::ostream& stream, const btCollisionShape& value)
{
switch (value.getShapeType())
{
case COMPOUND_SHAPE_PROXYTYPE:
return stream << static_cast<const btCompoundShape&>(value);
case BOX_SHAPE_PROXYTYPE:
return stream << static_cast<const btBoxShape&>(value);
case TRIANGLE_MESH_SHAPE_PROXYTYPE:
if (const auto casted = dynamic_cast<const Resource::TriangleMeshShape*>(&value))
return stream << *casted;
break;
}
return stream << "btCollisionShape {" << value.getShapeType() << "}";
}
static std::ostream& operator <<(std::ostream& stream, const btCollisionShape* value)
{
return value ? stream << "&" << *value : stream << "nullptr";
}
namespace osg
{
static std::ostream& operator <<(std::ostream& stream, const Vec3f& value)
{
return stream << "osg::Vec3f {"
<< value.x() << ", "
<< value.y() << ", "
<< value.z() << "}";
}
}
namespace std
{
static std::ostream& operator <<(std::ostream& stream, const map<int, int>& value)
{
stream << "std::map<int, int> {";
for (const auto& v : value)
stream << "{" << v.first << ", " << v.second << "},";
return stream << "}";
}
}
namespace Resource
{
static bool operator ==(const Resource::BulletShape& lhs, const Resource::BulletShape& rhs)
{
return compareObjects(lhs.mCollisionShape, rhs.mCollisionShape)
&& lhs.mCollisionBoxHalfExtents == rhs.mCollisionBoxHalfExtents
&& lhs.mCollisionBoxTranslate == rhs.mCollisionBoxTranslate
&& lhs.mAnimatedShapes == rhs.mAnimatedShapes;
}
static std::ostream& operator <<(std::ostream& stream, const Resource::BulletShape& value)
{
return stream << "Resource::BulletShape {"
<< value.mCollisionShape << ", "
<< value.mCollisionBoxHalfExtents << ", "
<< value.mAnimatedShapes
<< "}";
}
}
static bool operator ==(const btCollisionShape& lhs, const btCollisionShape& rhs);
static bool operator ==(const btCompoundShape& lhs, const btCompoundShape& rhs)
{
if (lhs.getNumChildShapes() != rhs.getNumChildShapes() || lhs.getLocalScaling() != rhs.getLocalScaling())
return false;
for (int i = 0; i < lhs.getNumChildShapes(); ++i)
{
if (!compareObjects(lhs.getChildShape(i), rhs.getChildShape(i))
|| !(lhs.getChildTransform(i) == rhs.getChildTransform(i)))
return false;
}
return true;
}
static bool operator ==(const btBoxShape& lhs, const btBoxShape& rhs)
{
return lhs.getLocalScaling() == rhs.getLocalScaling()
&& lhs.getHalfExtentsWithoutMargin() == rhs.getHalfExtentsWithoutMargin();
}
static bool operator ==(const btBvhTriangleMeshShape& lhs, const btBvhTriangleMeshShape& rhs)
{
return lhs.getLocalScaling() == rhs.getLocalScaling()
&& lhs.usesQuantizedAabbCompression() == rhs.usesQuantizedAabbCompression()
&& lhs.getOwnsBvh() == rhs.getOwnsBvh()
&& getTriangles(lhs) == getTriangles(rhs);
}
static bool operator ==(const btCollisionShape& lhs, const btCollisionShape& rhs)
{
if (lhs.getShapeType() != rhs.getShapeType())
return false;
switch (lhs.getShapeType())
{
case COMPOUND_SHAPE_PROXYTYPE:
return static_cast<const btCompoundShape&>(lhs) == static_cast<const btCompoundShape&>(rhs);
case BOX_SHAPE_PROXYTYPE:
return static_cast<const btBoxShape&>(lhs) == static_cast<const btBoxShape&>(rhs);
case TRIANGLE_MESH_SHAPE_PROXYTYPE:
if (const auto lhsCasted = dynamic_cast<const Resource::TriangleMeshShape*>(&lhs))
if (const auto rhsCasted = dynamic_cast<const Resource::TriangleMeshShape*>(&rhs))
return *lhsCasted == *rhsCasted;
return false;
}
return false;
}
namespace
{
using namespace testing;
using NifBullet::BulletNifLoader;
void init(Nif::Transformation& value)
{
value = Nif::Transformation::getIdentity();
}
void init(Nif::Extra& value)
{
value.extra = Nif::ExtraPtr(nullptr);
}
void init(Nif::Controlled& value)
{
init(static_cast<Nif::Extra&>(value));
value.controller = Nif::ControllerPtr(nullptr);
}
void init(Nif::Named& value)
{
init(static_cast<Nif::Controlled&>(value));
}
void init(Nif::Node& value)
{
init(static_cast<Nif::Named&>(value));
value.flags = 0;
init(value.trafo);
value.hasBounds = false;
value.parent = nullptr;
value.isBone = false;
}
void init(Nif::NiTriShape& value)
{
init(static_cast<Nif::Node&>(value));
value.recType = Nif::RC_NiTriShape;
value.data = Nif::NiTriShapeDataPtr(nullptr);
value.skin = Nif::NiSkinInstancePtr(nullptr);
}
void init(Nif::NiSkinInstance& value)
{
value.data = Nif::NiSkinDataPtr(nullptr);
value.root = Nif::NodePtr(nullptr);
}
void init(Nif::Controller& value)
{
value.next = Nif::ControllerPtr(nullptr);
value.flags = 0;
value.frequency = 0;
value.phase = 0;
value.timeStart = 0;
value.timeStop = 0;
value.target = Nif::ControlledPtr(nullptr);
}
void copy(const btTransform& src, Nif::Transformation& dst) {
dst.pos = osg::Vec3f(src.getOrigin().x(), src.getOrigin().y(), src.getOrigin().z());
for (int row = 0; row < 3; ++row)
for (int column = 0; column < 3; ++column)
dst.rotation.mValues[column][row] = src.getBasis().getRow(row)[column];
}
struct NifFileMock : Nif::File
{
MOCK_CONST_METHOD1(fail, void (const std::string&));
MOCK_CONST_METHOD1(warn, void (const std::string&));
MOCK_CONST_METHOD1(getRecord, Nif::Record* (std::size_t));
MOCK_CONST_METHOD0(numRecords, std::size_t ());
MOCK_CONST_METHOD1(getRoot, Nif::Record* (std::size_t));
MOCK_CONST_METHOD0(numRoots, std::size_t ());
MOCK_METHOD1(setUseSkinning, void (bool));
MOCK_CONST_METHOD0(getUseSkinning, bool ());
MOCK_CONST_METHOD0(getFilename, std::string ());
};
struct RecordMock : Nif::Record
{
MOCK_METHOD1(read, void (Nif::NIFStream *nif));
};
struct TestBulletNifLoader : Test
{
BulletNifLoader mLoader;
const StrictMock<const NifFileMock> mNifFile;
Nif::Node mNode;
Nif::Node mNode2;
Nif::NiNode mNiNode;
Nif::NiNode mNiNode2;
Nif::NiNode mNiNode3;
Nif::NiTriShapeData mNiTriShapeData;
Nif::NiTriShape mNiTriShape;
Nif::NiTriShapeData mNiTriShapeData2;
Nif::NiTriShape mNiTriShape2;
Nif::NiSkinInstance mNiSkinInstance;
Nif::NiStringExtraData mNiStringExtraData;
Nif::NiStringExtraData mNiStringExtraData2;
Nif::Controller mController;
btTransform mTransform {btMatrix3x3(btQuaternion(btVector3(1, 0, 0), 0.5f)), btVector3(1, 2, 3)};
btTransform mResultTransform {
btMatrix3x3(
1, 0, 0,
0, 0.82417738437652587890625, 0.56633174419403076171875,
0, -0.56633174419403076171875, 0.82417738437652587890625
),
btVector3(1, 2, 3)
};
btTransform mResultTransform2 {
btMatrix3x3(
1, 0, 0,
0, 0.7951543331146240234375, 0.606407105922698974609375,
0, -0.606407105922698974609375, 0.7951543331146240234375
),
btVector3(4, 8, 12)
};
TestBulletNifLoader()
{
init(mNode);
init(mNode2);
init(mNiNode);
init(mNiNode2);
init(mNiNode3);
init(mNiTriShape);
init(mNiTriShape2);
init(mNiSkinInstance);
init(mNiStringExtraData);
init(mNiStringExtraData2);
init(mController);
mNiTriShapeData.vertices = {osg::Vec3f(0, 0, 0), osg::Vec3f(1, 0, 0), osg::Vec3f(1, 1, 0)};
mNiTriShapeData.triangles = {0, 1, 2};
mNiTriShape.data = Nif::NiTriShapeDataPtr(&mNiTriShapeData);
mNiTriShapeData2.vertices = {osg::Vec3f(0, 0, 1), osg::Vec3f(1, 0, 1), osg::Vec3f(1, 1, 1)};
mNiTriShapeData2.triangles = {0, 1, 2};
mNiTriShape2.data = Nif::NiTriShapeDataPtr(&mNiTriShapeData2);
}
};
TEST_F(TestBulletNifLoader, for_zero_num_roots_should_return_default)
{
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(0));
const auto result = mLoader.load(mNifFile);
Resource::BulletShape expected;
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_root_not_nif_node_should_return_default)
{
StrictMock<RecordMock> record;
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&record));
const auto result = mLoader.load(mNifFile);
Resource::BulletShape expected;
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_default_root_nif_node_should_return_default)
{
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNode));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
const auto result = mLoader.load(mNifFile);
Resource::BulletShape expected;
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_default_root_collision_node_nif_node_should_return_default)
{
mNode.recType = Nif::RC_RootCollisionNode;
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNode));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
const auto result = mLoader.load(mNifFile);
Resource::BulletShape expected;
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_default_root_nif_node_and_filename_starting_with_x_should_return_default)
{
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNode));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("xtest.nif"));
const auto result = mLoader.load(mNifFile);
Resource::BulletShape expected;
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_root_nif_node_with_bounding_box_should_return_shape_with_compound_shape_and_box_inside)
{
mNode.hasBounds = true;
mNode.flags |= Nif::NiNode::Flag_BBoxCollision;
mNode.boundXYZ = osg::Vec3f(1, 2, 3);
mNode.boundPos = osg::Vec3f(-1, -2, -3);
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNode));
const auto result = mLoader.load(mNifFile);
Resource::BulletShape expected;
expected.mCollisionBoxHalfExtents = osg::Vec3f(1, 2, 3);
expected.mCollisionBoxTranslate = osg::Vec3f(-1, -2, -3);
std::unique_ptr<btBoxShape> box(new btBoxShape(btVector3(1, 2, 3)));
std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
shape->addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(-1, -2, -3)), box.release());
expected.mCollisionShape = shape.release();
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_child_nif_node_with_bounding_box)
{
mNode.hasBounds = true;
mNode.flags |= Nif::NiNode::Flag_BBoxCollision;
mNode.boundXYZ = osg::Vec3f(1, 2, 3);
mNode.boundPos = osg::Vec3f(-1, -2, -3);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNode)}));
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
const auto result = mLoader.load(mNifFile);
Resource::BulletShape expected;
expected.mCollisionBoxHalfExtents = osg::Vec3f(1, 2, 3);
expected.mCollisionBoxTranslate = osg::Vec3f(-1, -2, -3);
std::unique_ptr<btBoxShape> box(new btBoxShape(btVector3(1, 2, 3)));
std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
shape->addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(-1, -2, -3)), box.release());
expected.mCollisionShape = shape.release();
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_root_and_child_nif_node_with_bounding_box_but_root_without_flag_should_use_child_bounds)
{
mNode.hasBounds = true;
mNode.flags |= Nif::NiNode::Flag_BBoxCollision;
mNode.boundXYZ = osg::Vec3f(1, 2, 3);
mNode.boundPos = osg::Vec3f(-1, -2, -3);
mNiNode.hasBounds = true;
mNiNode.boundXYZ = osg::Vec3f(4, 5, 6);
mNiNode.boundPos = osg::Vec3f(-4, -5, -6);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNode)}));
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
const auto result = mLoader.load(mNifFile);
Resource::BulletShape expected;
expected.mCollisionBoxHalfExtents = osg::Vec3f(1, 2, 3);
expected.mCollisionBoxTranslate = osg::Vec3f(-1, -2, -3);
std::unique_ptr<btBoxShape> box(new btBoxShape(btVector3(1, 2, 3)));
std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
shape->addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(-1, -2, -3)), box.release());
expected.mCollisionShape = shape.release();
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_root_and_two_children_where_both_with_bounds_but_only_first_with_flag_should_use_first_bounds)
{
mNode.hasBounds = true;
mNode.flags |= Nif::NiNode::Flag_BBoxCollision;
mNode.boundXYZ = osg::Vec3f(1, 2, 3);
mNode.boundPos = osg::Vec3f(-1, -2, -3);
mNode2.hasBounds = true;
mNode2.boundXYZ = osg::Vec3f(4, 5, 6);
mNode2.boundPos = osg::Vec3f(-4, -5, -6);
mNiNode.hasBounds = true;
mNiNode.boundXYZ = osg::Vec3f(7, 8, 9);
mNiNode.boundPos = osg::Vec3f(-7, -8, -9);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNode), Nif::NodePtr(&mNode2)}));
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
const auto result = mLoader.load(mNifFile);
Resource::BulletShape expected;
expected.mCollisionBoxHalfExtents = osg::Vec3f(1, 2, 3);
expected.mCollisionBoxTranslate = osg::Vec3f(-1, -2, -3);
std::unique_ptr<btBoxShape> box(new btBoxShape(btVector3(1, 2, 3)));
std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
shape->addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(-1, -2, -3)), box.release());
expected.mCollisionShape = shape.release();
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_root_and_two_children_where_both_with_bounds_but_only_second_with_flag_should_use_second_bounds)
{
mNode.hasBounds = true;
mNode.boundXYZ = osg::Vec3f(1, 2, 3);
mNode.boundPos = osg::Vec3f(-1, -2, -3);
mNode2.hasBounds = true;
mNode2.flags |= Nif::NiNode::Flag_BBoxCollision;
mNode2.boundXYZ = osg::Vec3f(4, 5, 6);
mNode2.boundPos = osg::Vec3f(-4, -5, -6);
mNiNode.hasBounds = true;
mNiNode.boundXYZ = osg::Vec3f(7, 8, 9);
mNiNode.boundPos = osg::Vec3f(-7, -8, -9);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNode), Nif::NodePtr(&mNode2)}));
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
const auto result = mLoader.load(mNifFile);
Resource::BulletShape expected;
expected.mCollisionBoxHalfExtents = osg::Vec3f(4, 5, 6);
expected.mCollisionBoxTranslate = osg::Vec3f(-4, -5, -6);
std::unique_ptr<btBoxShape> box(new btBoxShape(btVector3(4, 5, 6)));
std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
shape->addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(-4, -5, -6)), box.release());
expected.mCollisionShape = shape.release();
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_root_nif_node_with_bounds_but_without_flag_should_return_shape_with_bounds_but_with_null_collision_shape)
{
mNode.hasBounds = true;
mNode.boundXYZ = osg::Vec3f(1, 2, 3);
mNode.boundPos = osg::Vec3f(-1, -2, -3);
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNode));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
const auto result = mLoader.load(mNifFile);
Resource::BulletShape expected;
expected.mCollisionBoxHalfExtents = osg::Vec3f(1, 2, 3);
expected.mCollisionBoxTranslate = osg::Vec3f(-1, -2, -3);
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_tri_shape_root_node_should_return_shape_with_triangle_mesh_shape)
{
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiTriShape));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
const auto result = mLoader.load(mNifFile);
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
Resource::BulletShape expected;
expected.mCollisionShape = new Resource::TriangleMeshShape(triangles.release(), true);
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_tri_shape_root_node_with_bounds_should_return_shape_with_bounds_but_with_null_collision_shape)
{
mNiTriShape.hasBounds = true;
mNiTriShape.boundXYZ = osg::Vec3f(1, 2, 3);
mNiTriShape.boundPos = osg::Vec3f(-1, -2, -3);
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiTriShape));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
const auto result = mLoader.load(mNifFile);
Resource::BulletShape expected;
expected.mCollisionBoxHalfExtents = osg::Vec3f(1, 2, 3);
expected.mCollisionBoxTranslate = osg::Vec3f(-1, -2, -3);
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_should_return_shape_with_triangle_mesh_shape)
{
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
const auto result = mLoader.load(mNifFile);
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
Resource::BulletShape expected;
expected.mCollisionShape = new Resource::TriangleMeshShape(triangles.release(), true);
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_nested_tri_shape_child_should_return_shape_with_triangle_mesh_shape)
{
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiNode2)}));
mNiNode2.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
const auto result = mLoader.load(mNifFile);
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
Resource::BulletShape expected;
expected.mCollisionShape = new Resource::TriangleMeshShape(triangles.release(), true);
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_two_tri_shape_children_should_return_shape_with_triangle_mesh_shape_with_all_meshes)
{
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({
Nif::NodePtr(&mNiTriShape),
Nif::NodePtr(&mNiTriShape2)
}));
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
const auto result = mLoader.load(mNifFile);
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 1), btVector3(1, 0, 1), btVector3(1, 1, 1));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
Resource::BulletShape expected;
expected.mCollisionShape = new Resource::TriangleMeshShape(triangles.release(), true);
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_and_filename_starting_with_x_and_not_empty_skin_should_return_shape_with_triangle_mesh_shape)
{
mNiTriShape.skin = Nif::NiSkinInstancePtr(&mNiSkinInstance);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("xtest.nif"));
const auto result = mLoader.load(mNifFile);
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
Resource::BulletShape expected;
expected.mCollisionShape = new Resource::TriangleMeshShape(triangles.release(), true);
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_tri_shape_root_node_and_filename_starting_with_x_should_return_shape_with_compound_shape)
{
copy(mTransform, mNiTriShape.trafo);
mNiTriShape.trafo.scale = 3;
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiTriShape));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("xtest.nif"));
const auto result = mLoader.load(mNifFile);
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
std::unique_ptr<Resource::TriangleMeshShape> mesh(new Resource::TriangleMeshShape(triangles.release(), true));
mesh->setLocalScaling(btVector3(3, 3, 3));
std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
shape->addChildShape(mResultTransform, mesh.release());
Resource::BulletShape expected;
expected.mCollisionShape = shape.release();
expected.mAnimatedShapes = {{-1, 0}};
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_and_filename_starting_with_x_should_return_shape_with_compound_shape)
{
copy(mTransform, mNiTriShape.trafo);
mNiTriShape.trafo.scale = 3;
mNiTriShape.parent = &mNiNode;
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
mNiNode.trafo.scale = 4;
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("xtest.nif"));
const auto result = mLoader.load(mNifFile);
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
std::unique_ptr<Resource::TriangleMeshShape> mesh(new Resource::TriangleMeshShape(triangles.release(), true));
mesh->setLocalScaling(btVector3(12, 12, 12));
std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
shape->addChildShape(mResultTransform2, mesh.release());
Resource::BulletShape expected;
expected.mCollisionShape = shape.release();
expected.mAnimatedShapes = {{-1, 0}};
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_two_tri_shape_children_nodes_and_filename_starting_with_x_should_return_shape_with_compound_shape)
{
copy(mTransform, mNiTriShape.trafo);
mNiTriShape.trafo.scale = 3;
copy(mTransform, mNiTriShape2.trafo);
mNiTriShape2.trafo.scale = 3;
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({
Nif::NodePtr(&mNiTriShape),
Nif::NodePtr(&mNiTriShape2),
}));
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("xtest.nif"));
const auto result = mLoader.load(mNifFile);
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
std::unique_ptr<Resource::TriangleMeshShape> mesh(new Resource::TriangleMeshShape(triangles.release(), true));
mesh->setLocalScaling(btVector3(3, 3, 3));
std::unique_ptr<btTriangleMesh> triangles2(new btTriangleMesh(false));
triangles2->addTriangle(btVector3(0, 0, 1), btVector3(1, 0, 1), btVector3(1, 1, 1));
std::unique_ptr<Resource::TriangleMeshShape> mesh2(new Resource::TriangleMeshShape(triangles2.release(), true));
mesh2->setLocalScaling(btVector3(3, 3, 3));
std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
shape->addChildShape(mResultTransform, mesh.release());
shape->addChildShape(mResultTransform, mesh2.release());
Resource::BulletShape expected;
expected.mCollisionShape = shape.release();
expected.mAnimatedShapes = {{-1, 0}};
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_controller_should_return_shape_with_compound_shape)
{
mController.recType = Nif::RC_NiKeyframeController;
mController.flags |= Nif::NiNode::ControllerFlag_Active;
copy(mTransform, mNiTriShape.trafo);
mNiTriShape.trafo.scale = 3;
mNiTriShape.parent = &mNiNode;
mNiTriShape.controller = Nif::ControllerPtr(&mController);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
mNiNode.trafo.scale = 4;
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
const auto result = mLoader.load(mNifFile);
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
std::unique_ptr<Resource::TriangleMeshShape> mesh(new Resource::TriangleMeshShape(triangles.release(), true));
mesh->setLocalScaling(btVector3(12, 12, 12));
std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
shape->addChildShape(mResultTransform2, mesh.release());
Resource::BulletShape expected;
expected.mCollisionShape = shape.release();
expected.mAnimatedShapes = {{-1, 0}};
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_two_tri_shape_children_nodes_where_one_with_controller_should_return_shape_with_compound_shape)
{
mController.recType = Nif::RC_NiKeyframeController;
mController.flags |= Nif::NiNode::ControllerFlag_Active;
copy(mTransform, mNiTriShape.trafo);
mNiTriShape.trafo.scale = 3;
copy(mTransform, mNiTriShape2.trafo);
mNiTriShape2.trafo.scale = 3;
mNiTriShape2.parent = &mNiNode;
mNiTriShape2.controller = Nif::ControllerPtr(&mController);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({
Nif::NodePtr(&mNiTriShape),
Nif::NodePtr(&mNiTriShape2),
}));
mNiNode.trafo.scale = 4;
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
const auto result = mLoader.load(mNifFile);
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(1, 2, 3), btVector3(4, 2, 3), btVector3(4, 4.632747650146484375, 1.56172335147857666015625));
std::unique_ptr<Resource::TriangleMeshShape> mesh(new Resource::TriangleMeshShape(triangles.release(), true));
mesh->setLocalScaling(btVector3(1, 1, 1));
std::unique_ptr<btTriangleMesh> triangles2(new btTriangleMesh(false));
triangles2->addTriangle(btVector3(0, 0, 1), btVector3(1, 0, 1), btVector3(1, 1, 1));
std::unique_ptr<Resource::TriangleMeshShape> mesh2(new Resource::TriangleMeshShape(triangles2.release(), true));
mesh2->setLocalScaling(btVector3(12, 12, 12));
std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
shape->addChildShape(mResultTransform2, mesh2.release());
shape->addChildShape(btTransform::getIdentity(), mesh.release());
Resource::BulletShape expected;
expected.mCollisionShape = shape.release();
expected.mAnimatedShapes = {{-1, 0}};
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_root_avoid_node_and_tri_shape_child_node_should_return_shape_with_null_collision_shape)
{
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
mNiNode.recType = Nif::RC_AvoidNode;
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
const auto result = mLoader.load(mNifFile);
Resource::BulletShape expected;
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_empty_data_should_return_shape_with_null_collision_shape)
{
mNiTriShape.data = Nif::NiTriShapeDataPtr(nullptr);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
const auto result = mLoader.load(mNifFile);
Resource::BulletShape expected;
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_empty_data_triangles_should_return_shape_with_null_collision_shape)
{
mNiTriShape.data->triangles.clear();
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
const auto result = mLoader.load(mNifFile);
Resource::BulletShape expected;
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_extra_data_string_starting_with_nc_should_return_shape_with_null_collision_shape)
{
mNiStringExtraData.string = "NC___";
mNiStringExtraData.recType = Nif::RC_NiStringExtraData;
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
const auto result = mLoader.load(mNifFile);
Resource::BulletShape expected;
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_not_first_extra_data_string_starting_with_nc_should_return_shape_with_null_collision_shape)
{
mNiStringExtraData.extra = Nif::ExtraPtr(&mNiStringExtraData2);
mNiStringExtraData2.string = "NC___";
mNiStringExtraData2.recType = Nif::RC_NiStringExtraData;
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
const auto result = mLoader.load(mNifFile);
Resource::BulletShape expected;
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_extra_data_string_mrk_should_return_shape_with_null_collision_shape)
{
mNiStringExtraData.string = "MRK";
mNiStringExtraData.recType = Nif::RC_NiStringExtraData;
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
const auto result = mLoader.load(mNifFile);
Resource::BulletShape expected;
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_extra_data_string_mrk_and_other_collision_node_should_return_shape_with_triangle_mesh_shape_with_all_meshes)
{
mNiStringExtraData.string = "MRK";
mNiStringExtraData.recType = Nif::RC_NiStringExtraData;
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
mNiNode3.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
mNiNode3.recType = Nif::RC_RootCollisionNode;
mNiNode2.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(nullptr), Nif::NodePtr(&mNiNode3)}));
mNiNode2.recType = Nif::RC_NiNode;
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiNode2)}));
mNiNode.recType = Nif::RC_NiNode;
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
const auto result = mLoader.load(mNifFile);
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
Resource::BulletShape expected;
expected.mCollisionShape = new Resource::TriangleMeshShape(triangles.release(), true);
EXPECT_EQ(*result, expected);
}
}

@ -0,0 +1,515 @@
# Get the Google C++ Mocking Framework.
# (This file is almost an copy of the original FindGTest.cmake file,
# altered to download and compile GMock and GTest if not found
# in GMOCK_ROOT or GTEST_ROOT respectively,
# feel free to use it as it is or modify it for your own needs.)
#
# Defines the following variables:
#
# GMOCK_FOUND - Found or got the Google Mocking framework
# GTEST_FOUND - Found or got the Google Testing framework
# GMOCK_INCLUDE_DIRS - GMock include directory
# GTEST_INCLUDE_DIRS - GTest include direcotry
#
# Also defines the library variables below as normal variables
#
# GMOCK_BOTH_LIBRARIES - Both libgmock & libgmock_main
# GMOCK_LIBRARIES - libgmock
# GMOCK_MAIN_LIBRARIES - libgmock-main
#
# GTEST_BOTH_LIBRARIES - Both libgtest & libgtest_main
# GTEST_LIBRARIES - libgtest
# GTEST_MAIN_LIBRARIES - libgtest_main
#
# Accepts the following variables as input:
#
# GMOCK_ROOT - The root directory of the gmock install prefix
# GTEST_ROOT - The root directory of the gtest install prefix
# GMOCK_SRC_DIR -The directory of the gmock sources
# GMOCK_VER - The version of the gmock sources to be downloaded
#
#-----------------------
# Example Usage:
#
# set(GMOCK_ROOT "~/gmock")
# find_package(GMock REQUIRED)
# include_directories(${GMOCK_INCLUDE_DIRS})
#
# add_executable(foo foo.cc)
# target_link_libraries(foo ${GMOCK_BOTH_LIBRARIES})
#
#=============================================================================
# Copyright (c) 2016 Michel Estermann
# Copyright (c) 2016 Kamil Strzempowicz
# Copyright (c) 2011 Matej Svec
#
# CMake - Cross Platform Makefile Generator
# Copyright 2000-2016 Kitware, Inc.
# Copyright 2000-2011 Insight Software Consortium
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# * Neither the names of Kitware, Inc., the Insight Software Consortium,
# nor the names of their contributors may be used to endorse or promote
# products derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# ------------------------------------------------------------------------------
#
# The above copyright and license notice applies to distributions of
# CMake in source and binary form. Some source files contain additional
# notices of original copyright by their contributors; see each source
# for details. Third-party software packages supplied with CMake under
# compatible licenses provide their own copyright notices documented in
# corresponding subdirectories.
#
# ------------------------------------------------------------------------------
#
# CMake was initially developed by Kitware with the following sponsorship:
#
# * National Library of Medicine at the National Institutes of Health
# as part of the Insight Segmentation and Registration Toolkit (ITK).
#
# * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel
# Visualization Initiative.
#
# * National Alliance for Medical Image Computing (NAMIC) is funded by the
# National Institutes of Health through the NIH Roadmap for Medical Research,
# Grant U54 EB005149.
#
# * Kitware, Inc.
#=============================================================================
# Thanks to Daniel Blezek <blezek@gmail.com> for the GTEST_ADD_TESTS code
function(gtest_add_tests executable extra_args)
if(NOT ARGN)
message(FATAL_ERROR "Missing ARGN: Read the documentation for GTEST_ADD_TESTS")
endif()
if(ARGN STREQUAL "AUTO")
# obtain sources used for building that executable
get_property(ARGN TARGET ${executable} PROPERTY SOURCES)
endif()
set(gtest_case_name_regex ".*\\( *([A-Za-z_0-9]+) *, *([A-Za-z_0-9]+) *\\).*")
set(gtest_test_type_regex "(TYPED_TEST|TEST_?[FP]?)")
foreach(source ${ARGN})
file(READ "${source}" contents)
string(REGEX MATCHALL "${gtest_test_type_regex} *\\(([A-Za-z_0-9 ,]+)\\)" found_tests ${contents})
foreach(hit ${found_tests})
string(REGEX MATCH "${gtest_test_type_regex}" test_type ${hit})
# Parameterized tests have a different signature for the filter
if("x${test_type}" STREQUAL "xTEST_P")
string(REGEX REPLACE ${gtest_case_name_regex} "*/\\1.\\2/*" test_name ${hit})
elseif("x${test_type}" STREQUAL "xTEST_F" OR "x${test_type}" STREQUAL "xTEST")
string(REGEX REPLACE ${gtest_case_name_regex} "\\1.\\2" test_name ${hit})
elseif("x${test_type}" STREQUAL "xTYPED_TEST")
string(REGEX REPLACE ${gtest_case_name_regex} "\\1/*.\\2" test_name ${hit})
else()
message(WARNING "Could not parse GTest ${hit} for adding to CTest.")
continue()
endif()
add_test(NAME ${test_name} COMMAND ${executable} --gtest_filter=${test_name} ${extra_args})
endforeach()
endforeach()
endfunction()
function(_append_debugs _endvar _library)
if(${_library} AND ${_library}_DEBUG)
set(_output optimized ${${_library}} debug ${${_library}_DEBUG})
else()
set(_output ${${_library}})
endif()
set(${_endvar} ${_output} PARENT_SCOPE)
endfunction()
function(_gmock_find_library _name)
find_library(${_name}
NAMES ${ARGN}
HINTS
ENV GMOCK_ROOT
${GMOCK_ROOT}
PATH_SUFFIXES ${_gmock_libpath_suffixes}
)
mark_as_advanced(${_name})
endfunction()
function(_gtest_find_library _name)
find_library(${_name}
NAMES ${ARGN}
HINTS
ENV GTEST_ROOT
${GTEST_ROOT}
PATH_SUFFIXES ${_gtest_libpath_suffixes}
)
mark_as_advanced(${_name})
endfunction()
if(NOT DEFINED GMOCK_MSVC_SEARCH)
set(GMOCK_MSVC_SEARCH MD)
endif()
set(_gmock_libpath_suffixes lib)
set(_gtest_libpath_suffixes lib)
if(MSVC)
if(GMOCK_MSVC_SEARCH STREQUAL "MD")
list(APPEND _gmock_libpath_suffixes
msvc/gmock-md/Debug
msvc/gmock-md/Release)
list(APPEND _gtest_libpath_suffixes
msvc/gtest-md/Debug
msvc/gtest-md/Release)
elseif(GMOCK_MSVC_SEARCH STREQUAL "MT")
list(APPEND _gmock_libpath_suffixes
msvc/gmock/Debug
msvc/gmock/Release)
list(APPEND _gtest_libpath_suffixes
msvc/gtest/Debug
msvc/gtest/Release)
endif()
endif()
find_path(GMOCK_INCLUDE_DIR gmock/gmock.h
HINTS
$ENV{GMOCK_ROOT}/include
${GMOCK_ROOT}/include
)
mark_as_advanced(GMOCK_INCLUDE_DIR)
find_path(GTEST_INCLUDE_DIR gtest/gtest.h
HINTS
$ENV{GTEST_ROOT}/include
${GTEST_ROOT}/include
)
mark_as_advanced(GTEST_INCLUDE_DIR)
if(MSVC AND GMOCK_MSVC_SEARCH STREQUAL "MD")
# The provided /MD project files for Google Mock add -md suffixes to the
# library names.
_gmock_find_library(GMOCK_LIBRARY gmock-md gmock)
_gmock_find_library(GMOCK_LIBRARY_DEBUG gmock-mdd gmockd)
_gmock_find_library(GMOCK_MAIN_LIBRARY gmock_main-md gmock_main)
_gmock_find_library(GMOCK_MAIN_LIBRARY_DEBUG gmock_main-mdd gmock_maind)
_gtest_find_library(GTEST_LIBRARY gtest-md gtest)
_gtest_find_library(GTEST_LIBRARY_DEBUG gtest-mdd gtestd)
_gtest_find_library(GTEST_MAIN_LIBRARY gtest_main-md gtest_main)
_gtest_find_library(GTEST_MAIN_LIBRARY_DEBUG gtest_main-mdd gtest_maind)
else()
_gmock_find_library(GMOCK_LIBRARY gmock)
_gmock_find_library(GMOCK_LIBRARY_DEBUG gmockd)
_gmock_find_library(GMOCK_MAIN_LIBRARY gmock_main)
_gmock_find_library(GMOCK_MAIN_LIBRARY_DEBUG gmock_maind)
_gtest_find_library(GTEST_LIBRARY gtest)
_gtest_find_library(GTEST_LIBRARY_DEBUG gtestd)
_gtest_find_library(GTEST_MAIN_LIBRARY gtest_main)
_gtest_find_library(GTEST_MAIN_LIBRARY_DEBUG gtest_maind)
endif()
if(NOT TARGET GTest::GTest)
add_library(GTest::GTest UNKNOWN IMPORTED)
endif()
if(NOT TARGET GTest::Main)
add_library(GTest::Main UNKNOWN IMPORTED)
endif()
if(NOT TARGET GMock::GMock)
add_library(GMock::GMock UNKNOWN IMPORTED)
endif()
if(NOT TARGET GMock::Main)
add_library(GMock::Main UNKNOWN IMPORTED)
endif()
set(GMOCK_LIBRARY_EXISTS OFF)
set(GTEST_LIBRARY_EXISTS OFF)
if(EXISTS "${GMOCK_LIBRARY}" OR EXISTS "${GMOCK_LIBRARY_DEBUG}" AND GMOCK_INCLUDE_DIR)
set(GMOCK_LIBRARY_EXISTS ON)
endif()
if(EXISTS "${GTEST_LIBRARY}" OR EXISTS "${GTEST_LIBRARY_DEBUG}" AND GTEST_INCLUDE_DIR)
set(GTEST_LIBRARY_EXISTS ON)
endif()
if(NOT (${GMOCK_LIBRARY_EXISTS} AND ${GTEST_LIBRARY_EXISTS}))
include(ExternalProject)
if(GTEST_USE_STATIC_LIBS)
set(GTEST_CMAKE_ARGS -Dgtest_force_shared_crt:BOOL=ON -DBUILD_SHARED_LIBS=OFF)
if(BUILD_SHARED_LIBS)
list(APPEND GTEST_CMAKE_ARGS
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
-Dgtest_hide_internal_symbols=ON
-DCMAKE_CXX_VISIBILITY_PRESET=hidden
-DCMAKE_VISIBILITY_INLINES_HIDDEN=ON
-DCMAKE_POLICY_DEFAULT_CMP0063=NEW
)
endif()
set(GTEST_LIBRARY_PREFIX ${CMAKE_STATIC_LIBRARY_PREFIX})
else()
set(GTEST_CMAKE_ARGS -DBUILD_SHARED_LIBS=ON)
set(GTEST_LIBRARY_PREFIX ${CMAKE_SHARED_LIBRARY_PREFIX})
endif()
if(WIN32)
list(APPEND GTEST_CMAKE_ARGS -Dgtest_disable_pthreads=ON)
endif()
if("${GMOCK_SRC_DIR}" STREQUAL "")
message(STATUS "Downloading GMock / GTest version ${GMOCK_VER} from git")
if("${GMOCK_VER}" STREQUAL "1.6.0" OR "${GMOCK_VER}" STREQUAL "1.7.0")
set(GTEST_BIN_DIR "${GMOCK_ROOT}/src/gtest-build")
set(GTEST_LIBRARY "${GTEST_BIN_DIR}/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(GTEST_MAIN_LIBRARY "${GTEST_BIN_DIR}/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX}")
mark_as_advanced(GTEST_LIBRARY)
mark_as_advanced(GTEST_MAIN_LIBRARY)
externalproject_add(
gtest
GIT_REPOSITORY "https://github.com/google/googletest.git"
GIT_TAG "release-${GMOCK_VER}"
PREFIX ${GMOCK_ROOT}
INSTALL_COMMAND ""
LOG_DOWNLOAD ON
LOG_CONFIGURE ON
LOG_BUILD ON
CMAKE_ARGS
${GTEST_CMAKE_ARGS}
BINARY_DIR ${GTEST_BIN_DIR}
BUILD_BYPRODUCTS
"${GTEST_LIBRARY}"
"${GTEST_MAIN_LIBRARY}"
)
set(GMOCK_BIN_DIR "${GMOCK_ROOT}/src/gmock-build")
set(GMOCK_LIBRARY "${GMOCK_BIN_DIR}/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gmock${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(GMOCK_MAIN_LIBRARY "${GMOCK_BIN_DIR}/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gmock_main${CMAKE_STATIC_LIBRARY_SUFFIX}")
mark_as_advanced(GMOCK_LIBRARY)
mark_as_advanced(GMOCK_MAIN_LIBRARY)
externalproject_add(
gmock
GIT_REPOSITORY "https://github.com/google/googlemock.git"
GIT_TAG "release-${GMOCK_VER}"
PREFIX ${GMOCK_ROOT}
INSTALL_COMMAND ""
LOG_DOWNLOAD ON
LOG_CONFIGURE ON
LOG_BUILD ON
CMAKE_ARGS
${GTEST_CMAKE_ARGS}
BINARY_DIR ${GMOCK_BIN_DIR}
BUILD_BYPRODUCTS
"${GMOCK_LIBRARY}"
"${GMOCK_MAIN_LIBRARY}"
)
add_dependencies(gmock gtest)
add_dependencies(GTest::GTest gtest)
add_dependencies(GTest::Main gtest)
add_dependencies(GMock::GMock gmock)
add_dependencies(GMock::Main gmock)
externalproject_get_property(gtest source_dir)
set(GTEST_INCLUDE_DIR "${source_dir}/include")
mark_as_advanced(GTEST_INCLUDE_DIR)
externalproject_get_property(gmock source_dir)
set(GMOCK_INCLUDE_DIR "${source_dir}/include")
mark_as_advanced(GMOCK_INCLUDE_DIR)
else() #1.8.0
set(GMOCK_BIN_DIR "${GMOCK_ROOT}/src/gmock-build")
set(GTEST_LIBRARY "${GMOCK_BIN_DIR}/googlemock/gtest/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(GTEST_MAIN_LIBRARY "${GMOCK_BIN_DIR}/googlemock/gtest/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(GMOCK_LIBRARY "${GMOCK_BIN_DIR}/googlemock/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gmock${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(GMOCK_MAIN_LIBRARY "${GMOCK_BIN_DIR}/googlemock/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gmock_main${CMAKE_STATIC_LIBRARY_SUFFIX}")
mark_as_advanced(GTEST_LIBRARY)
mark_as_advanced(GTEST_MAIN_LIBRARY)
mark_as_advanced(GMOCK_LIBRARY)
mark_as_advanced(GMOCK_MAIN_LIBRARY)
externalproject_add(
gmock
GIT_REPOSITORY "https://github.com/google/googletest.git"
GIT_TAG "release-${GMOCK_VER}"
PREFIX ${GMOCK_ROOT}
INSTALL_COMMAND ""
LOG_DOWNLOAD ON
LOG_CONFIGURE ON
LOG_BUILD ON
CMAKE_ARGS
${GTEST_CMAKE_ARGS}
BINARY_DIR "${GMOCK_BIN_DIR}"
BUILD_BYPRODUCTS
"${GTEST_LIBRARY}"
"${GTEST_MAIN_LIBRARY}"
"${GMOCK_LIBRARY}"
"${GMOCK_MAIN_LIBRARY}"
)
add_dependencies(GTest::GTest gmock)
add_dependencies(GTest::Main gmock)
add_dependencies(GMock::GMock gmock)
add_dependencies(GMock::Main gmock)
externalproject_get_property(gmock source_dir)
set(GTEST_INCLUDE_DIR "${source_dir}/googletest/include")
set(GMOCK_INCLUDE_DIR "${source_dir}/googlemock/include")
mark_as_advanced(GMOCK_INCLUDE_DIR)
mark_as_advanced(GTEST_INCLUDE_DIR)
endif()
# Prevent CMake from complaining about these directories missing when the libgtest/libgmock targets get used as dependencies
file(MAKE_DIRECTORY ${GTEST_INCLUDE_DIR} ${GMOCK_INCLUDE_DIR})
else()
message(STATUS "Building Gmock / Gtest from dir ${GMOCK_SRC_DIR}")
set(GMOCK_BIN_DIR "${GMOCK_ROOT}/src/gmock-build")
set(GTEST_LIBRARY "${GMOCK_BIN_DIR}/gtest/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(GTEST_MAIN_LIBRARY "${GMOCK_BIN_DIR}/gtest/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(GMOCK_LIBRARY "${GMOCK_BIN_DIR}/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gmock${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(GMOCK_MAIN_LIBRARY "${GMOCK_BIN_DIR}/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gmock_main${CMAKE_STATIC_LIBRARY_SUFFIX}")
mark_as_advanced(GTEST_LIBRARY)
mark_as_advanced(GTEST_MAIN_LIBRARY)
mark_as_advanced(GMOCK_LIBRARY)
mark_as_advanced(GMOCK_MAIN_LIBRARY)
if(EXISTS "${GMOCK_SRC_DIR}/gtest/include/gtest/gtest.h")
set(GTEST_INCLUDE_DIR "${GMOCK_SRC_DIR}/gtest/include")
mark_as_advanced(GTEST_INCLUDE_DIR)
endif()
if(EXISTS "${GMOCK_SRC_DIR}/include/gmock/gmock.h")
set(GMOCK_INCLUDE_DIR "${GMOCK_SRC_DIR}/include")
mark_as_advanced(GMOCK_INCLUDE_DIR)
elseif(EXISTS "${GMOCK_SRC_DIR}/../../include/gmock/gmock.h")
set(GMOCK_INCLUDE_DIR "${GMOCK_SRC_DIR}/../../include")
if(IS_ABSOLUTE "${GMOCK_INCLUDE_DIR}")
get_filename_component(GMOCK_INCLUDE_DIR "${GMOCK_INCLUDE_DIR}" ABSOLUTE)
endif()
mark_as_advanced(GMOCK_INCLUDE_DIR)
endif()
externalproject_add(
gmock
SOURCE_DIR ${GMOCK_SRC_DIR}
PREFIX ${GMOCK_ROOT}
INSTALL_COMMAND ""
LOG_DOWNLOAD ON
LOG_CONFIGURE ON
LOG_BUILD ON
CMAKE_ARGS
${GTEST_CMAKE_ARGS}
BINARY_DIR "${GMOCK_BIN_DIR}"
BUILD_BYPRODUCTS
"${GTEST_LIBRARY}"
"${GTEST_MAIN_LIBRARY}"
"${GMOCK_LIBRARY}"
"${GMOCK_MAIN_LIBRARY}"
)
add_dependencies(GTest::GTest gmock)
add_dependencies(GTest::Main gmock)
add_dependencies(GMock::GMock gmock)
add_dependencies(GMock::Main gmock)
endif()
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GTest DEFAULT_MSG GTEST_LIBRARY GTEST_INCLUDE_DIR GTEST_MAIN_LIBRARY)
find_package_handle_standard_args(GMock DEFAULT_MSG GMOCK_LIBRARY GMOCK_INCLUDE_DIR GMOCK_MAIN_LIBRARY)
include(CMakeFindDependencyMacro)
find_dependency(Threads)
set_target_properties(GTest::GTest PROPERTIES
INTERFACE_LINK_LIBRARIES "Threads::Threads"
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
IMPORTED_LOCATION "${GTEST_LIBRARY}"
)
if(GTEST_INCLUDE_DIR)
set_target_properties(GTest::GTest PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIR}"
INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIR}"
)
endif()
set_target_properties(GTest::Main PROPERTIES
INTERFACE_LINK_LIBRARIES "GTest::GTest"
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
IMPORTED_LOCATION "${GTEST_MAIN_LIBRARY}")
set_target_properties(GMock::GMock PROPERTIES
INTERFACE_LINK_LIBRARIES "Threads::Threads"
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
IMPORTED_LOCATION "${GMOCK_LIBRARY}")
if(GMOCK_INCLUDE_DIR)
set_target_properties(GMock::GMock PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${GMOCK_INCLUDE_DIR}"
INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${GMOCK_INCLUDE_DIR}"
)
if(GMOCK_VER VERSION_LESS "1.7")
# GMock 1.6 still has GTest as an external link-time dependency,
# so just specify it on the link interface.
set_property(TARGET GMock::GMock APPEND PROPERTY
INTERFACE_LINK_LIBRARIES GTest::GTest)
elseif(GTEST_INCLUDE_DIR)
# GMock 1.7 and beyond doesn't have it as a link-time dependency anymore,
# so merge it's compile-time interface (include dirs) with ours.
set_property(TARGET GMock::GMock APPEND PROPERTY
INTERFACE_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIR}")
set_property(TARGET GMock::GMock APPEND PROPERTY
INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIR}")
endif()
endif()
set_target_properties(GMock::Main PROPERTIES
INTERFACE_LINK_LIBRARIES "GMock::GMock"
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
IMPORTED_LOCATION "${GMOCK_MAIN_LIBRARY}")
if(GTEST_FOUND)
set(GTEST_INCLUDE_DIRS ${GTEST_INCLUDE_DIR})
set(GTEST_LIBRARIES GTest::GTest)
set(GTEST_MAIN_LIBRARIES GTest::Main)
set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES})
if(VERBOSE)
message(STATUS "GTest includes: ${GTEST_INCLUDE_DIRS}")
message(STATUS "GTest libs: ${GTEST_BOTH_LIBRARIES}")
endif()
endif()
if(GMOCK_FOUND)
set(GMOCK_INCLUDE_DIRS ${GMOCK_INCLUDE_DIR})
set(GMOCK_LIBRARIES GMock::GMock)
set(GMOCK_MAIN_LIBRARIES GMock::Main)
set(GMOCK_BOTH_LIBRARIES ${GMOCK_LIBRARIES} ${GMOCK_MAIN_LIBRARIES})
if(VERBOSE)
message(STATUS "GMock includes: ${GMOCK_INCLUDE_DIRS}")
message(STATUS "GMock libs: ${GMOCK_BOTH_LIBRARIES}")
endif()
endif()

@ -85,7 +85,11 @@ add_component_dir (esmterrain
)
add_component_dir (misc
utf8stream stringops resourcehelpers rng debugging messageformatparser
utf8stream stringops resourcehelpers rng messageformatparser
)
add_component_dir (debug
debugging debuglog
)
IF(NOT WIN32 AND NOT APPLE)
@ -243,6 +247,11 @@ if (UNIX AND NOT APPLE)
target_link_libraries(components ${CMAKE_THREAD_LIBS_INIT})
endif()
if (BUILD_WITH_CODE_COVERAGE)
add_definitions(--coverage)
target_link_libraries(components gcov)
endif()
# Make the variable accessible for other subdirectories
set(COMPONENT_FILES ${COMPONENT_FILES} PARENT_SCOPE)

@ -0,0 +1,34 @@
#ifndef OPENMW_COMPONENTS_BULLETHELPERS_PROCESSTRIANGLECALLBACK_H
#define OPENMW_COMPONENTS_BULLETHELPERS_PROCESSTRIANGLECALLBACK_H
#include <BulletCollision/CollisionShapes/btTriangleCallback.h>
#include <type_traits>
namespace BulletHelpers
{
template <class Impl>
class ProcessTriangleCallback : public btTriangleCallback
{
public:
ProcessTriangleCallback(Impl impl)
: mImpl(std::move(impl))
{}
void processTriangle(btVector3* triangle, int partId, int triangleIndex) override final
{
return mImpl(triangle, partId, triangleIndex);
}
private:
Impl mImpl;
};
template <class Impl>
ProcessTriangleCallback<typename std::decay<Impl>::type> makeProcessTriangleCallback(Impl&& impl)
{
return ProcessTriangleCallback<typename std::decay<Impl>::type>(std::forward<Impl>(impl));
}
}
#endif

@ -14,7 +14,7 @@
#include <stdbool.h>
#include <sys/ptrace.h>
#include <iostream>
#include <components/debug/debuglog.hpp>
#include <boost/filesystem/fstream.hpp>
@ -185,7 +185,7 @@ static void gdb_info(pid_t pid)
if (close(fd) == 0)
remove(respfile);
else
std::cerr << "Warning: can not close and remove file '" << respfile << "': " << std::strerror(errno) << std::endl;
Log(Debug::Warning) << "Warning: can not close and remove file '" << respfile << "': " << std::strerror(errno);
}
printf("!!! Could not create gdb command file\n");
}
@ -517,8 +517,9 @@ void crashCatcherInstall(int argc, char **argv, const std::string &crashLogPath)
int s[5] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGABRT };
if (crashCatcherInstallHandlers(argc, argv, 5, s, crashLogPath.c_str(), NULL) == -1)
{
std::cerr << "Installing crash handler failed" << std::endl;
} else
std::cout << "Crash handler installed" << std::endl;
Log(Debug::Warning) << "Installing crash handler failed";
}
else
Log(Debug::Info) << "Crash handler installed";
}
}

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

Loading…
Cancel
Save