2010-06-16 12:13:21 +02:00
|
|
|
#include "engine.hpp"
|
2013-01-12 17:52:26 -04:00
|
|
|
|
2023-02-03 01:26:43 +01:00
|
|
|
#include <cerrno>
|
2020-06-25 21:46:07 +02:00
|
|
|
#include <chrono>
|
2023-07-29 12:40:12 +02:00
|
|
|
#include <future>
|
2023-02-03 01:26:43 +01:00
|
|
|
#include <system_error>
|
2015-05-13 15:03:21 +02:00
|
|
|
|
2015-06-03 17:25:18 +02:00
|
|
|
#include <osgDB/WriteFile>
|
2015-04-12 15:34:50 +02:00
|
|
|
#include <osgViewer/ViewerEventHandlers>
|
|
|
|
|
2013-11-16 10:31:46 +01:00
|
|
|
#include <SDL.h>
|
|
|
|
|
2018-08-14 23:05:43 +04:00
|
|
|
#include <components/debug/debuglog.hpp>
|
2018-10-26 15:18:38 +01:00
|
|
|
#include <components/debug/gldebug.hpp>
|
2018-08-14 23:05:43 +04:00
|
|
|
|
2015-04-22 17:58:55 +02:00
|
|
|
#include <components/misc/rng.hpp>
|
2015-03-15 14:07:47 +13:00
|
|
|
|
2015-04-12 15:34:50 +02:00
|
|
|
#include <components/vfs/manager.hpp>
|
|
|
|
#include <components/vfs/registerarchives.hpp>
|
|
|
|
|
2015-05-13 15:03:21 +02:00
|
|
|
#include <components/sdlutil/imagetosurface.hpp>
|
2015-05-13 02:52:04 +02:00
|
|
|
#include <components/sdlutil/sdlgraphicswindow.hpp>
|
|
|
|
|
2015-04-12 15:34:50 +02:00
|
|
|
#include <components/resource/resourcesystem.hpp>
|
2016-02-05 18:51:51 +01:00
|
|
|
#include <components/resource/scenemanager.hpp>
|
2017-02-22 02:18:18 +01:00
|
|
|
#include <components/resource/stats.hpp>
|
2015-04-12 15:34:50 +02:00
|
|
|
|
2013-08-07 13:16:20 -04:00
|
|
|
#include <components/compiler/extensions0.hpp>
|
2013-08-06 20:38:41 -04:00
|
|
|
|
2022-04-04 22:51:23 +02:00
|
|
|
#include <components/stereo/multiview.hpp>
|
|
|
|
#include <components/stereo/stereomanager.hpp>
|
|
|
|
|
2017-02-14 03:37:45 +01:00
|
|
|
#include <components/sceneutil/workqueue.hpp>
|
|
|
|
|
2012-01-21 01:14:35 +01:00
|
|
|
#include <components/files/configurationmanager.hpp>
|
|
|
|
|
2015-07-18 03:01:06 +02:00
|
|
|
#include <components/version/version.hpp>
|
2013-12-05 14:23:39 +01:00
|
|
|
|
2022-10-02 22:38:37 +02:00
|
|
|
#include <components/l10n/manager.hpp>
|
|
|
|
|
2023-07-29 12:40:12 +02:00
|
|
|
#include <components/loadinglistener/asynclistener.hpp>
|
2023-07-19 20:35:00 +02:00
|
|
|
#include <components/loadinglistener/loadinglistener.hpp>
|
|
|
|
|
2021-02-11 18:19:55 +01:00
|
|
|
#include <components/misc/frameratelimiter.hpp>
|
|
|
|
|
2022-04-04 22:51:23 +02:00
|
|
|
#include <components/sceneutil/color.hpp>
|
2021-12-15 22:17:38 +00:00
|
|
|
#include <components/sceneutil/depth.hpp>
|
|
|
|
#include <components/sceneutil/screencapture.hpp>
|
2022-07-24 20:55:03 +02:00
|
|
|
#include <components/sceneutil/unrefqueue.hpp>
|
|
|
|
#include <components/sceneutil/util.hpp>
|
2021-05-24 18:47:23 +02:00
|
|
|
|
2022-05-13 18:58:00 -07:00
|
|
|
#include <components/settings/shadermanager.hpp>
|
2023-05-22 14:23:06 +02:00
|
|
|
#include <components/settings/values.hpp>
|
2022-05-13 18:58:00 -07:00
|
|
|
|
2015-05-03 17:24:35 +02:00
|
|
|
#include "mwinput/inputmanagerimp.hpp"
|
2010-07-03 15:41:20 +02:00
|
|
|
|
2012-08-12 18:11:09 +02:00
|
|
|
#include "mwgui/windowmanagerimp.hpp"
|
2011-10-09 13:12:44 +02:00
|
|
|
|
2020-12-18 23:21:10 +01:00
|
|
|
#include "mwlua/luamanagerimp.hpp"
|
2022-10-06 01:45:45 +02:00
|
|
|
#include "mwlua/worker.hpp"
|
2020-12-18 23:21:10 +01:00
|
|
|
|
2012-11-10 14:31:58 +01:00
|
|
|
#include "mwscript/interpretercontext.hpp"
|
2012-08-08 15:18:55 +02:00
|
|
|
#include "mwscript/scriptmanagerimp.hpp"
|
2010-07-02 09:00:06 +02:00
|
|
|
|
2012-08-09 14:33:21 +02:00
|
|
|
#include "mwsound/soundmanagerimp.hpp"
|
2010-07-03 15:17:02 +02:00
|
|
|
|
2010-08-03 22:06:48 +02:00
|
|
|
#include "mwworld/class.hpp"
|
2023-08-06 14:46:15 +02:00
|
|
|
#include "mwworld/datetimemanager.hpp"
|
2012-07-03 12:30:50 +02:00
|
|
|
#include "mwworld/worldimp.hpp"
|
2010-08-03 13:17:31 +02:00
|
|
|
|
2020-04-20 18:47:14 +02:00
|
|
|
#include "mwrender/vismask.hpp"
|
|
|
|
|
2010-08-03 13:17:31 +02:00
|
|
|
#include "mwclass/classes.hpp"
|
2010-06-16 12:13:21 +02:00
|
|
|
|
2012-08-09 10:35:53 +02:00
|
|
|
#include "mwdialogue/dialoguemanagerimp.hpp"
|
2012-08-09 12:56:03 +02:00
|
|
|
#include "mwdialogue/journalimp.hpp"
|
2014-12-13 02:47:04 +01:00
|
|
|
#include "mwdialogue/scripttest.hpp"
|
2010-08-06 18:01:34 +02:00
|
|
|
|
2012-08-11 17:30:55 +02:00
|
|
|
#include "mwmechanics/mechanicsmanagerimp.hpp"
|
2010-07-26 11:15:38 +02:00
|
|
|
|
2013-11-16 10:31:46 +01:00
|
|
|
#include "mwstate/statemanagerimp.hpp"
|
2012-01-10 00:34:29 -05:00
|
|
|
|
2022-10-06 01:35:39 +02:00
|
|
|
#include "profile.hpp"
|
|
|
|
|
2015-06-12 01:08:58 +02:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
void checkSDLError(int ret)
|
|
|
|
{
|
|
|
|
if (ret != 0)
|
2018-08-14 23:05:43 +04:00
|
|
|
Log(Debug::Error) << "SDL error: " << SDL_GetError();
|
2015-06-12 01:08:58 +02:00
|
|
|
}
|
2020-06-28 01:44:56 +02:00
|
|
|
|
|
|
|
void initStatsHandler(Resource::Profiler& profiler)
|
|
|
|
{
|
|
|
|
const osg::Vec4f textColor(1.f, 1.f, 1.f, 1.f);
|
|
|
|
const osg::Vec4f barColor(1.f, 1.f, 1.f, 1.f);
|
|
|
|
const float multiplier = 1000;
|
|
|
|
const bool average = true;
|
|
|
|
const bool averageInInverseSpace = false;
|
|
|
|
const float maxValue = 10000;
|
|
|
|
|
2022-10-06 01:35:39 +02:00
|
|
|
OMW::forEachUserStatsValue([&](const OMW::UserStats& v) {
|
2020-06-28 01:44:56 +02:00
|
|
|
profiler.addUserStatsLine(v.mLabel, textColor, barColor, v.mTaken, multiplier, average,
|
|
|
|
averageInInverseSpace, v.mBegin, v.mEnd, maxValue);
|
|
|
|
});
|
2020-11-20 13:11:53 +01:00
|
|
|
// the forEachUserStatsValue loop is "run" at compile time, hence the settings manager is not available.
|
|
|
|
// Unconditionnally add the async physics stats, and then remove it at runtime if necessary
|
|
|
|
if (Settings::Manager::getInt("async num threads", "Physics") == 0)
|
|
|
|
profiler.removeUserStatsLine(" -Async");
|
2020-06-28 01:44:56 +02:00
|
|
|
}
|
2021-05-25 01:49:27 +02:00
|
|
|
|
|
|
|
struct ScheduleNonDialogMessageBox
|
|
|
|
{
|
|
|
|
void operator()(std::string message) const
|
|
|
|
{
|
|
|
|
MWBase::Environment::get().getWindowManager()->scheduleMessageBox(
|
|
|
|
std::move(message), MWGui::ShowInDialogueMode_Never);
|
|
|
|
}
|
|
|
|
};
|
2021-05-25 13:58:16 +02:00
|
|
|
|
|
|
|
struct IgnoreString
|
|
|
|
{
|
|
|
|
void operator()(std::string) const {}
|
|
|
|
};
|
2021-12-15 22:17:38 +00:00
|
|
|
|
|
|
|
class IdentifyOpenGLOperation : public osg::GraphicsOperation
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
IdentifyOpenGLOperation()
|
|
|
|
: GraphicsOperation("IdentifyOpenGLOperation", false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator()(osg::GraphicsContext* graphicsContext) override
|
|
|
|
{
|
|
|
|
Log(Debug::Info) << "OpenGL Vendor: " << glGetString(GL_VENDOR);
|
|
|
|
Log(Debug::Info) << "OpenGL Renderer: " << glGetString(GL_RENDERER);
|
|
|
|
Log(Debug::Info) << "OpenGL Version: " << glGetString(GL_VERSION);
|
2022-06-06 22:40:38 +02:00
|
|
|
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &mMaxTextureImageUnits);
|
2021-12-15 22:17:38 +00:00
|
|
|
}
|
2022-06-06 22:40:38 +02:00
|
|
|
|
|
|
|
int getMaxTextureImageUnits() const
|
|
|
|
{
|
|
|
|
if (mMaxTextureImageUnits == 0)
|
|
|
|
throw std::logic_error("mMaxTextureImageUnits is not initialized");
|
|
|
|
return mMaxTextureImageUnits;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
int mMaxTextureImageUnits = 0;
|
2021-12-15 22:17:38 +00:00
|
|
|
};
|
2015-06-12 01:08:58 +02:00
|
|
|
}
|
|
|
|
|
2010-07-02 16:18:25 +02:00
|
|
|
void OMW::Engine::executeLocalScripts()
|
|
|
|
{
|
2022-05-06 17:46:50 +02:00
|
|
|
MWWorld::LocalScripts& localScripts = mWorld->getLocalScripts();
|
2011-10-06 12:29:59 +02:00
|
|
|
|
|
|
|
localScripts.startIteration();
|
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type
The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID
Slowly going through all the changes to make, still hundreds of errors
a lot of functions/structures use std::string or stringview to designate an ID. So it takes time
Continues slowly replacing ids. There are technically more and more compilation errors
I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type
Continue moving forward, changes to the stores
slowly moving along
Starting to see the fruit of those changes.
still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type.
More replacements. Things are starting to get easier
I can see more and more often the issue is that the function is awaiting a RefId, but is given a string
there is less need to go down functions and to fix a long list of them.
Still moving forward, and for the first time error count is going down!
Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably
Cells are back to using string for the name, haven't fixed everything yet. Many other changes
Under the bar of 400 compilation errors.
more good progress <100 compile errors!
More progress
Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string
some more progress on other fronts
Mostly game settings clean
one error opened a lot of other errors. Down to 18, but more will prbably appear
only link errors left??
Fixed link errors
OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
|
|
|
std::pair<ESM::RefId, MWWorld::Ptr> script;
|
2016-02-03 16:09:20 +01:00
|
|
|
while (localScripts.getNext(script))
|
2010-07-02 16:18:25 +02:00
|
|
|
{
|
2011-10-06 12:29:59 +02:00
|
|
|
MWScript::InterpreterContext interpreterContext(&script.second.getRefData().getLocals(), script.second);
|
2022-05-06 17:46:50 +02:00
|
|
|
mScriptManager->run(script.first, interpreterContext);
|
2010-07-02 16:18:25 +02:00
|
|
|
}
|
|
|
|
}
|
2010-07-01 11:49:00 -07:00
|
|
|
|
2017-11-16 17:56:44 +01:00
|
|
|
bool OMW::Engine::frame(float frametime)
|
2010-07-02 17:30:26 +02:00
|
|
|
{
|
2022-10-06 01:56:47 +02:00
|
|
|
const osg::Timer_t frameStart = mViewer->getStartTick();
|
|
|
|
const unsigned int frameNumber = mViewer->getFrameStamp()->getFrameNumber();
|
|
|
|
const osg::Timer* const timer = osg::Timer::instance();
|
|
|
|
osg::Stats* const stats = mViewer->getViewerStats();
|
2011-10-08 10:15:03 +02:00
|
|
|
|
2022-10-06 01:56:47 +02:00
|
|
|
mEnvironment.setFrameDuration(frametime);
|
2017-11-16 17:56:44 +01:00
|
|
|
|
2022-10-06 01:56:47 +02:00
|
|
|
try
|
|
|
|
{
|
2012-04-05 21:16:51 +02:00
|
|
|
// update input
|
2020-06-28 01:44:56 +02:00
|
|
|
{
|
|
|
|
ScopedProfile<UserStatsType::Input> profile(frameStart, frameNumber, *timer, *stats);
|
2022-05-06 17:46:50 +02:00
|
|
|
mInputManager->update(frametime, false);
|
2020-06-28 01:44:56 +02:00
|
|
|
}
|
2012-04-05 21:16:51 +02:00
|
|
|
|
2015-09-04 03:44:14 +02:00
|
|
|
// When the window is minimized, pause the game. Currently this *has* to be here to work around a MyGUI bug.
|
|
|
|
// If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon
|
|
|
|
// changing widget textures (fixed in MyGUI 3.3.2), and destroyed widgets will not be deleted (not fixed yet,
|
|
|
|
// https://github.com/MyGUI/mygui/issues/21)
|
2020-03-31 13:15:26 +04:00
|
|
|
{
|
2020-06-28 01:44:56 +02:00
|
|
|
ScopedProfile<UserStatsType::Sound> profile(frameStart, frameNumber, *timer, *stats);
|
2014-09-03 04:54:07 +02:00
|
|
|
|
2022-05-06 17:46:50 +02:00
|
|
|
if (!mWindowManager->isWindowVisible())
|
2020-06-28 01:44:56 +02:00
|
|
|
{
|
2022-05-06 17:46:50 +02:00
|
|
|
mSoundManager->pausePlayback();
|
2020-06-28 01:44:56 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
2022-05-06 17:46:50 +02:00
|
|
|
mSoundManager->resumePlayback();
|
2020-06-28 01:44:56 +02:00
|
|
|
|
|
|
|
// sound
|
|
|
|
if (mUseSound)
|
2022-05-06 17:46:50 +02:00
|
|
|
mSoundManager->update(frametime);
|
2020-06-28 01:44:56 +02:00
|
|
|
}
|
2010-10-31 12:23:03 -04:00
|
|
|
|
2022-08-05 16:19:57 +00:00
|
|
|
{
|
|
|
|
ScopedProfile<UserStatsType::LuaSyncUpdate> profile(frameStart, frameNumber, *timer, *stats);
|
|
|
|
// Should be called after input manager update and before any change to the game world.
|
|
|
|
// It applies to the game world queued changes from the previous frame.
|
|
|
|
mLuaManager->synchronizedUpdate();
|
|
|
|
}
|
2021-11-17 03:05:50 +01:00
|
|
|
|
2014-01-25 22:20:46 +01:00
|
|
|
// update game state
|
2020-06-28 01:44:56 +02:00
|
|
|
{
|
|
|
|
ScopedProfile<UserStatsType::State> profile(frameStart, frameNumber, *timer, *stats);
|
2022-05-06 17:46:50 +02:00
|
|
|
mStateManager->update(frametime);
|
2020-06-28 01:44:56 +02:00
|
|
|
}
|
2014-01-25 22:20:46 +01:00
|
|
|
|
2023-08-06 16:09:41 +02:00
|
|
|
bool paused = mWorld->getTimeManager()->isPaused();
|
2015-06-14 15:27:33 +02:00
|
|
|
|
2013-12-16 21:02:21 +02:00
|
|
|
{
|
2020-06-28 01:44:56 +02:00
|
|
|
ScopedProfile<UserStatsType::Script> profile(frameStart, frameNumber, *timer, *stats);
|
|
|
|
|
2022-05-06 17:46:50 +02:00
|
|
|
if (mStateManager->getState() != MWBase::StateManager::State_NoGame)
|
2014-06-15 00:09:12 +02:00
|
|
|
{
|
2023-08-06 16:09:41 +02:00
|
|
|
if (!mWindowManager->containsMode(MWGui::GM_MainMenu))
|
2015-02-10 20:25:57 +01:00
|
|
|
{
|
2022-05-06 17:46:50 +02:00
|
|
|
if (mWorld->getScriptsEnabled())
|
2020-06-28 01:44:56 +02:00
|
|
|
{
|
|
|
|
// local scripts
|
|
|
|
executeLocalScripts();
|
2010-07-22 12:46:24 +02:00
|
|
|
|
2020-06-28 01:44:56 +02:00
|
|
|
// global scripts
|
2022-05-06 17:46:50 +02:00
|
|
|
mScriptManager->getGlobalScripts().run();
|
2020-06-28 01:44:56 +02:00
|
|
|
}
|
2010-08-01 10:25:50 +02:00
|
|
|
|
2022-11-06 20:06:45 +01:00
|
|
|
mWorld->getWorldScene().markCellAsUnchanged();
|
2020-06-28 01:44:56 +02:00
|
|
|
}
|
2016-10-13 14:38:35 +02:00
|
|
|
|
2023-08-06 16:09:41 +02:00
|
|
|
if (!paused)
|
2020-06-28 01:44:56 +02:00
|
|
|
{
|
2023-08-06 14:46:15 +02:00
|
|
|
double hours = (frametime * mWorld->getTimeManager()->getGameTimeScale()) / 3600.0;
|
2022-05-06 17:46:50 +02:00
|
|
|
mWorld->advanceTime(hours, true);
|
|
|
|
mWorld->rechargeItems(frametime, true);
|
2020-06-28 01:44:56 +02:00
|
|
|
}
|
2015-08-27 14:20:45 -05:00
|
|
|
}
|
2013-12-16 21:02:21 +02:00
|
|
|
}
|
2010-08-01 10:25:50 +02:00
|
|
|
|
2020-06-28 01:44:56 +02:00
|
|
|
// update mechanics
|
2014-05-16 00:58:12 +02:00
|
|
|
{
|
2020-06-28 01:44:56 +02:00
|
|
|
ScopedProfile<UserStatsType::Mechanics> profile(frameStart, frameNumber, *timer, *stats);
|
2013-11-28 09:33:50 +01:00
|
|
|
|
2022-05-06 17:46:50 +02:00
|
|
|
if (mStateManager->getState() != MWBase::StateManager::State_NoGame)
|
2020-06-28 01:44:56 +02:00
|
|
|
{
|
2023-08-06 16:09:41 +02:00
|
|
|
mMechanicsManager->update(frametime, paused);
|
2020-06-28 01:44:56 +02:00
|
|
|
}
|
|
|
|
|
2022-05-06 17:46:50 +02:00
|
|
|
if (mStateManager->getState() == MWBase::StateManager::State_Running)
|
2020-06-28 01:44:56 +02:00
|
|
|
{
|
2022-05-06 17:46:50 +02:00
|
|
|
MWWorld::Ptr player = mWorld->getPlayerPtr();
|
2023-08-06 16:09:41 +02:00
|
|
|
if (!paused && player.getClass().getCreatureStats(player).isDead())
|
2022-05-06 17:46:50 +02:00
|
|
|
mStateManager->endGame();
|
2020-06-28 01:44:56 +02:00
|
|
|
}
|
2013-11-16 17:46:48 +01:00
|
|
|
}
|
2010-07-22 12:29:23 +02:00
|
|
|
|
2019-01-07 14:27:31 +04:00
|
|
|
// update physics
|
|
|
|
{
|
2020-06-28 01:44:56 +02:00
|
|
|
ScopedProfile<UserStatsType::Physics> profile(frameStart, frameNumber, *timer, *stats);
|
|
|
|
|
2022-05-06 17:46:50 +02:00
|
|
|
if (mStateManager->getState() != MWBase::StateManager::State_NoGame)
|
2020-06-28 01:44:56 +02:00
|
|
|
{
|
2023-08-06 16:09:41 +02:00
|
|
|
mWorld->updatePhysics(frametime, paused, frameStart, frameNumber, *stats);
|
2020-06-28 01:44:56 +02:00
|
|
|
}
|
2019-01-07 14:27:31 +04:00
|
|
|
}
|
|
|
|
|
2012-01-23 14:33:06 +01:00
|
|
|
// update world
|
2014-05-16 00:58:12 +02:00
|
|
|
{
|
2020-06-28 01:44:56 +02:00
|
|
|
ScopedProfile<UserStatsType::World> profile(frameStart, frameNumber, *timer, *stats);
|
|
|
|
|
2022-05-06 17:46:50 +02:00
|
|
|
if (mStateManager->getState() != MWBase::StateManager::State_NoGame)
|
2020-06-28 01:44:56 +02:00
|
|
|
{
|
2023-08-06 16:09:41 +02:00
|
|
|
mWorld->update(frametime, paused);
|
2020-06-28 01:44:56 +02:00
|
|
|
}
|
2014-05-16 00:58:12 +02:00
|
|
|
}
|
2012-01-23 14:33:06 +01:00
|
|
|
|
2012-04-14 17:47:44 +02:00
|
|
|
// update GUI
|
2020-06-28 01:44:56 +02:00
|
|
|
{
|
|
|
|
ScopedProfile<UserStatsType::Gui> profile(frameStart, frameNumber, *timer, *stats);
|
2022-05-06 17:46:50 +02:00
|
|
|
mWindowManager->update(frametime);
|
2020-06-28 01:44:56 +02:00
|
|
|
}
|
2022-10-06 01:56:47 +02:00
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
|
|
|
Log(Debug::Error) << "Error in frame: " << e.what();
|
|
|
|
}
|
2019-01-07 14:27:31 +04:00
|
|
|
|
2022-10-06 01:56:47 +02:00
|
|
|
const bool reportResource = stats->collectStats("resource");
|
2022-07-24 20:55:03 +02:00
|
|
|
|
2022-10-06 01:56:47 +02:00
|
|
|
if (reportResource)
|
|
|
|
stats->setAttribute(frameNumber, "UnrefQueue", mUnrefQueue->getSize());
|
2022-07-24 20:55:03 +02:00
|
|
|
|
2022-10-06 01:56:47 +02:00
|
|
|
mUnrefQueue->flush(*mWorkQueue);
|
2022-07-24 20:55:03 +02:00
|
|
|
|
2022-10-06 01:56:47 +02:00
|
|
|
if (reportResource)
|
|
|
|
{
|
|
|
|
stats->setAttribute(frameNumber, "FrameNumber", frameNumber);
|
2020-05-22 00:11:23 +02:00
|
|
|
|
2022-10-06 01:56:47 +02:00
|
|
|
mResourceSystem->reportStats(frameNumber, stats);
|
2017-02-22 02:18:18 +01:00
|
|
|
|
2022-10-06 01:56:47 +02:00
|
|
|
stats->setAttribute(frameNumber, "WorkQueue", mWorkQueue->getNumItems());
|
|
|
|
stats->setAttribute(frameNumber, "WorkThread", mWorkQueue->getNumActiveThreads());
|
2019-03-17 20:18:53 +03:00
|
|
|
|
2022-10-06 01:56:47 +02:00
|
|
|
mMechanicsManager->reportStats(frameNumber, *stats);
|
|
|
|
mWorld->reportStats(frameNumber, *stats);
|
|
|
|
mLuaManager->reportStats(frameNumber, *stats);
|
2010-09-18 08:39:21 +02:00
|
|
|
}
|
2022-10-06 01:56:47 +02:00
|
|
|
|
|
|
|
mViewer->eventTraversal();
|
|
|
|
mViewer->updateTraversal();
|
|
|
|
|
2010-09-18 08:39:21 +02:00
|
|
|
{
|
2022-10-06 01:56:47 +02:00
|
|
|
ScopedProfile<UserStatsType::WindowManager> profile(frameStart, frameNumber, *timer, *stats);
|
|
|
|
mWorld->updateWindowManager();
|
2010-08-03 20:40:45 +02:00
|
|
|
}
|
2022-10-06 01:56:47 +02:00
|
|
|
|
|
|
|
mLuaWorker->allowUpdate(); // if there is a separate Lua thread, it starts the update now
|
|
|
|
|
|
|
|
mViewer->renderingTraversals();
|
|
|
|
|
|
|
|
mLuaWorker->finishUpdate();
|
|
|
|
|
2017-11-16 17:56:44 +01:00
|
|
|
return true;
|
2010-07-02 17:30:26 +02:00
|
|
|
}
|
|
|
|
|
2012-01-21 01:14:35 +01:00
|
|
|
OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
|
2018-10-09 10:21:12 +04:00
|
|
|
: mWindow(nullptr)
|
2015-05-13 02:52:04 +02:00
|
|
|
, mEncoding(ToUTF8::WINDOWS_1252)
|
2018-08-01 20:18:37 +04:00
|
|
|
, mScreenCaptureOperation(nullptr)
|
2022-04-04 22:51:23 +02:00
|
|
|
, mSelectDepthFormatOperation(new SceneUtil::SelectDepthFormatOperation())
|
|
|
|
, mSelectColorFormatOperation(new SceneUtil::Color::SelectColorFormatOperation())
|
|
|
|
, mStereoManager(nullptr)
|
2013-11-16 11:33:20 +01:00
|
|
|
, mSkipMenu(false)
|
2010-08-18 11:16:15 +02:00
|
|
|
, mUseSound(true)
|
2010-10-06 14:52:53 +02:00
|
|
|
, mCompileAll(false)
|
2014-12-13 02:47:04 +01:00
|
|
|
, mCompileAllDialogue(false)
|
2014-02-02 14:09:59 +01:00
|
|
|
, mWarningsMode(1)
|
2012-07-30 11:43:28 +02:00
|
|
|
, mScriptConsoleMode(false)
|
2013-07-31 18:46:32 +02:00
|
|
|
, mActivationDistanceOverride(-1)
|
2013-11-29 20:06:54 +01:00
|
|
|
, mGrab(true)
|
2019-03-19 09:12:31 +04:00
|
|
|
, mRandomSeed(0)
|
2015-04-25 13:37:42 -05:00
|
|
|
, mScriptBlacklistUse(true)
|
2014-09-01 11:55:12 +02:00
|
|
|
, mNewGame(false)
|
2015-05-23 22:44:00 +02:00
|
|
|
, mCfgMgr(configurationManager)
|
2022-07-02 23:25:51 +04:00
|
|
|
, mGlMaxTextureImageUnits(0)
|
2010-08-01 10:25:50 +02:00
|
|
|
{
|
2020-03-14 22:24:36 +04:00
|
|
|
SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0"); // We use only gamepads
|
|
|
|
|
|
|
|
Uint32 flags
|
|
|
|
= SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE | SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK | SDL_INIT_SENSOR;
|
2013-01-13 21:32:45 -04:00
|
|
|
if (SDL_WasInit(flags) == 0)
|
|
|
|
{
|
2014-01-11 11:00:34 +01:00
|
|
|
SDL_SetMainReady();
|
2013-01-13 21:32:45 -04:00
|
|
|
if (SDL_Init(flags) != 0)
|
2013-06-23 16:45:23 -07:00
|
|
|
{
|
|
|
|
throw std::runtime_error("Could not initialize SDL! " + std::string(SDL_GetError()));
|
|
|
|
}
|
2013-01-13 21:32:45 -04:00
|
|
|
}
|
2010-06-27 16:44:15 -07:00
|
|
|
}
|
2010-06-16 12:13:21 +02:00
|
|
|
|
2010-07-02 13:12:05 +02:00
|
|
|
OMW::Engine::~Engine()
|
|
|
|
{
|
2021-07-11 14:43:52 +02:00
|
|
|
if (mScreenCaptureOperation != nullptr)
|
|
|
|
mScreenCaptureOperation->stop();
|
2021-05-25 13:44:40 +02:00
|
|
|
|
2022-05-06 17:46:50 +02:00
|
|
|
mMechanicsManager = nullptr;
|
|
|
|
mDialogueManager = nullptr;
|
|
|
|
mJournal = nullptr;
|
|
|
|
mScriptManager = nullptr;
|
|
|
|
mWindowManager = nullptr;
|
|
|
|
mWorld = nullptr;
|
2022-05-21 17:00:02 +02:00
|
|
|
mStereoManager = nullptr;
|
2022-05-06 17:46:50 +02:00
|
|
|
mSoundManager = nullptr;
|
|
|
|
mInputManager = nullptr;
|
|
|
|
mStateManager = nullptr;
|
2022-10-06 01:56:47 +02:00
|
|
|
mLuaWorker = nullptr;
|
2022-05-06 17:46:50 +02:00
|
|
|
mLuaManager = nullptr;
|
2022-10-02 22:38:37 +02:00
|
|
|
mL10nManager = nullptr;
|
2022-05-06 17:46:50 +02:00
|
|
|
|
2018-10-09 10:21:12 +04:00
|
|
|
mScriptContext = nullptr;
|
2015-05-13 03:36:20 +02:00
|
|
|
|
2022-07-24 20:55:03 +02:00
|
|
|
mUnrefQueue = nullptr;
|
2018-10-09 10:21:12 +04:00
|
|
|
mWorkQueue = nullptr;
|
2017-02-14 03:37:45 +01:00
|
|
|
|
2018-10-09 10:21:12 +04:00
|
|
|
mViewer = nullptr;
|
2015-05-13 02:52:04 +02:00
|
|
|
|
2019-05-06 17:07:22 +04:00
|
|
|
mResourceSystem.reset();
|
|
|
|
|
2019-02-17 12:07:14 +04:00
|
|
|
mEncoder = nullptr;
|
|
|
|
|
2015-05-15 19:34:18 +02:00
|
|
|
if (mWindow)
|
|
|
|
{
|
|
|
|
SDL_DestroyWindow(mWindow);
|
2018-10-09 10:21:12 +04:00
|
|
|
mWindow = nullptr;
|
2015-05-15 19:34:18 +02:00
|
|
|
}
|
2015-05-13 02:52:04 +02:00
|
|
|
|
2013-01-13 21:32:45 -04:00
|
|
|
SDL_Quit();
|
2010-07-02 13:12:05 +02:00
|
|
|
}
|
|
|
|
|
2010-06-16 12:13:21 +02:00
|
|
|
// Set data dir
|
|
|
|
|
2011-09-02 22:45:21 +02:00
|
|
|
void OMW::Engine::setDataDirs(const Files::PathContainer& dataDirs)
|
2010-06-16 12:13:21 +02:00
|
|
|
{
|
2012-01-29 20:27:03 +01:00
|
|
|
mDataDirs = dataDirs;
|
2022-06-19 13:28:33 +02:00
|
|
|
mDataDirs.insert(mDataDirs.begin(), mResDir / "vfs");
|
2023-05-31 23:11:03 +02:00
|
|
|
mFileCollections = Files::Collections(mDataDirs);
|
2010-06-16 12:13:21 +02:00
|
|
|
}
|
|
|
|
|
2013-03-09 21:08:08 +01:00
|
|
|
// Add BSA archive
|
|
|
|
void OMW::Engine::addArchive(const std::string& archive)
|
|
|
|
{
|
|
|
|
mArchives.push_back(archive);
|
|
|
|
}
|
|
|
|
|
2011-01-04 01:34:55 +01:00
|
|
|
// Set resource dir
|
2022-06-08 23:25:50 +02:00
|
|
|
void OMW::Engine::setResourceDir(const std::filesystem::path& parResDir)
|
2011-01-04 01:34:55 +01:00
|
|
|
{
|
2014-05-21 15:39:58 +04:00
|
|
|
mResDir = parResDir;
|
2011-01-04 01:34:55 +01:00
|
|
|
}
|
|
|
|
|
2017-08-06 15:03:48 +02:00
|
|
|
// Set start cell name
|
2010-06-16 12:13:21 +02:00
|
|
|
void OMW::Engine::setCell(const std::string& cellName)
|
|
|
|
{
|
2023-01-19 17:31:45 +01:00
|
|
|
mCellName = cellName;
|
2010-06-16 12:13:21 +02:00
|
|
|
}
|
|
|
|
|
2013-09-29 09:11:57 +02:00
|
|
|
void OMW::Engine::addContentFile(const std::string& file)
|
2010-06-16 12:13:21 +02:00
|
|
|
{
|
2014-01-27 13:27:42 +01:00
|
|
|
mContentFiles.push_back(file);
|
2010-06-16 12:13:21 +02:00
|
|
|
}
|
|
|
|
|
2020-01-12 11:42:47 +04:00
|
|
|
void OMW::Engine::addGroundcoverFile(const std::string& file)
|
|
|
|
{
|
|
|
|
mGroundcoverFiles.emplace_back(file);
|
|
|
|
}
|
|
|
|
|
2014-09-01 11:55:12 +02:00
|
|
|
void OMW::Engine::setSkipMenu(bool skipMenu, bool newGame)
|
2010-07-04 16:00:32 +02:00
|
|
|
{
|
2013-11-16 11:33:20 +01:00
|
|
|
mSkipMenu = skipMenu;
|
2014-09-01 11:55:12 +02:00
|
|
|
mNewGame = newGame;
|
2010-07-04 16:00:32 +02:00
|
|
|
}
|
|
|
|
|
2022-05-22 02:47:58 +02:00
|
|
|
void OMW::Engine::createWindow()
|
2013-01-08 09:45:01 -08:00
|
|
|
{
|
2022-05-22 02:47:58 +02:00
|
|
|
int screen = Settings::Manager::getInt("screen", "Video");
|
|
|
|
int width = Settings::Manager::getInt("resolution x", "Video");
|
|
|
|
int height = Settings::Manager::getInt("resolution y", "Video");
|
2022-05-03 22:50:31 -07:00
|
|
|
Settings::WindowMode windowMode
|
|
|
|
= static_cast<Settings::WindowMode>(Settings::Manager::getInt("window mode", "Video"));
|
2022-05-22 02:47:58 +02:00
|
|
|
bool windowBorder = Settings::Manager::getBool("window border", "Video");
|
2023-02-26 13:19:58 +04:00
|
|
|
int vsync = Settings::Manager::getInt("vsync mode", "Video");
|
2022-05-22 02:47:58 +02:00
|
|
|
unsigned int antialiasing = std::max(0, Settings::Manager::getInt("antialiasing", "Video"));
|
2015-05-13 02:52:04 +02:00
|
|
|
|
|
|
|
int pos_x = SDL_WINDOWPOS_CENTERED_DISPLAY(screen), pos_y = SDL_WINDOWPOS_CENTERED_DISPLAY(screen);
|
|
|
|
|
2022-05-08 22:56:35 -07:00
|
|
|
if (windowMode == Settings::WindowMode::Fullscreen || windowMode == Settings::WindowMode::WindowedFullscreen)
|
2015-05-13 02:52:04 +02:00
|
|
|
{
|
|
|
|
pos_x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(screen);
|
|
|
|
pos_y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(screen);
|
|
|
|
}
|
2013-11-16 10:31:46 +01:00
|
|
|
|
2022-09-12 08:18:08 +00:00
|
|
|
Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI;
|
2022-05-03 22:50:31 -07:00
|
|
|
if (windowMode == Settings::WindowMode::Fullscreen)
|
2015-05-13 02:52:04 +02:00
|
|
|
flags |= SDL_WINDOW_FULLSCREEN;
|
2022-05-08 22:56:35 -07:00
|
|
|
else if (windowMode == Settings::WindowMode::WindowedFullscreen)
|
2022-05-03 22:50:31 -07:00
|
|
|
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
2015-05-13 02:52:04 +02:00
|
|
|
|
2021-11-07 20:01:07 -08:00
|
|
|
// Allows for Windows snapping features to properly work in borderless window
|
|
|
|
SDL_SetHint("SDL_BORDERLESS_WINDOWED_STYLE", "1");
|
|
|
|
SDL_SetHint("SDL_BORDERLESS_RESIZABLE_STYLE", "1");
|
|
|
|
|
2015-05-13 02:52:04 +02:00
|
|
|
if (!windowBorder)
|
|
|
|
flags |= SDL_WINDOW_BORDERLESS;
|
2013-01-13 21:32:45 -04:00
|
|
|
|
2014-03-27 04:15:47 +01:00
|
|
|
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS,
|
2022-05-22 02:47:58 +02:00
|
|
|
Settings::Manager::getBool("minimize on focus loss", "Video") ? "1" : "0");
|
2014-03-27 04:15:47 +01:00
|
|
|
|
2015-06-12 01:08:58 +02:00
|
|
|
checkSDLError(SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8));
|
|
|
|
checkSDLError(SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8));
|
|
|
|
checkSDLError(SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8));
|
|
|
|
checkSDLError(SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0));
|
|
|
|
checkSDLError(SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24));
|
2020-09-19 23:30:34 +01:00
|
|
|
if (Debug::shouldDebugOpenGL())
|
|
|
|
checkSDLError(SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG));
|
2015-06-12 00:12:12 +02:00
|
|
|
|
2015-05-13 02:52:04 +02:00
|
|
|
if (antialiasing > 0)
|
|
|
|
{
|
2015-06-12 01:08:58 +02:00
|
|
|
checkSDLError(SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1));
|
|
|
|
checkSDLError(SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antialiasing));
|
2015-05-13 02:52:04 +02:00
|
|
|
}
|
|
|
|
|
2020-09-20 12:22:31 +00:00
|
|
|
osg::ref_ptr<SDLUtil::GraphicsWindowSDL2> graphicsWindow;
|
|
|
|
while (!graphicsWindow || !graphicsWindow->valid())
|
2015-05-13 02:52:04 +02:00
|
|
|
{
|
2020-09-20 12:22:31 +00:00
|
|
|
while (!mWindow)
|
2015-06-05 02:53:10 +02:00
|
|
|
{
|
2020-09-20 12:22:31 +00:00
|
|
|
mWindow = SDL_CreateWindow("OpenMW", pos_x, pos_y, width, height, flags);
|
|
|
|
if (!mWindow)
|
2015-06-05 02:53:10 +02:00
|
|
|
{
|
2020-09-20 12:22:31 +00:00
|
|
|
// Try with a lower AA
|
|
|
|
if (antialiasing > 0)
|
|
|
|
{
|
|
|
|
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));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::stringstream error;
|
|
|
|
error << "Failed to create SDL window: " << SDL_GetError();
|
|
|
|
throw std::runtime_error(error.str());
|
|
|
|
}
|
2015-06-05 02:53:10 +02:00
|
|
|
}
|
|
|
|
}
|
2015-05-13 02:52:04 +02:00
|
|
|
|
2022-09-12 08:18:08 +00:00
|
|
|
// Since we use physical resolution internally, we have to create the window with scaled resolution,
|
|
|
|
// but we can't get the scale before the window exists, so instead we have to resize aftewards.
|
|
|
|
int w, h;
|
|
|
|
SDL_GetWindowSize(mWindow, &w, &h);
|
|
|
|
int dw, dh;
|
|
|
|
SDL_GL_GetDrawableSize(mWindow, &dw, &dh);
|
|
|
|
if (dw != w || dh != h)
|
|
|
|
{
|
|
|
|
SDL_SetWindowSize(mWindow, width / (dw / w), height / (dh / h));
|
|
|
|
}
|
|
|
|
|
2020-09-20 12:22:31 +00:00
|
|
|
setWindowIcon();
|
|
|
|
|
|
|
|
osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
|
|
|
|
SDL_GetWindowPosition(mWindow, &traits->x, &traits->y);
|
2022-09-12 08:18:08 +00:00
|
|
|
SDL_GL_GetDrawableSize(mWindow, &traits->width, &traits->height);
|
2020-09-20 12:22:31 +00:00
|
|
|
traits->windowName = SDL_GetWindowTitle(mWindow);
|
|
|
|
traits->windowDecoration = !(SDL_GetWindowFlags(mWindow) & SDL_WINDOW_BORDERLESS);
|
|
|
|
traits->screenNum = SDL_GetWindowDisplayIndex(mWindow);
|
2023-02-26 13:19:58 +04:00
|
|
|
traits->vsync = 0;
|
2020-09-20 12:22:31 +00:00
|
|
|
traits->inheritedWindowData = new SDLUtil::GraphicsWindowSDL2::WindowData(mWindow);
|
|
|
|
|
2023-02-26 13:19:58 +04:00
|
|
|
graphicsWindow = new SDLUtil::GraphicsWindowSDL2(traits, vsync);
|
2020-09-20 12:22:31 +00:00
|
|
|
if (!graphicsWindow->valid())
|
|
|
|
throw std::runtime_error("Failed to create GraphicsContext");
|
|
|
|
|
|
|
|
if (traits->samples < antialiasing)
|
|
|
|
{
|
|
|
|
Log(Debug::Warning) << "Warning: Framebuffer MSAA level is only " << traits->samples << "x instead of "
|
|
|
|
<< antialiasing << "x. Trying " << antialiasing / 2 << "x instead.";
|
|
|
|
graphicsWindow->closeImplementation();
|
|
|
|
SDL_DestroyWindow(mWindow);
|
|
|
|
mWindow = nullptr;
|
|
|
|
antialiasing /= 2;
|
|
|
|
Settings::Manager::setInt("antialiasing", "Video", antialiasing);
|
|
|
|
checkSDLError(SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antialiasing));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (traits->red < 8)
|
|
|
|
Log(Debug::Warning) << "Warning: Framebuffer only has a " << traits->red << " bit red channel.";
|
|
|
|
if (traits->green < 8)
|
|
|
|
Log(Debug::Warning) << "Warning: Framebuffer only has a " << traits->green << " bit green channel.";
|
|
|
|
if (traits->blue < 8)
|
|
|
|
Log(Debug::Warning) << "Warning: Framebuffer only has a " << traits->blue << " bit blue channel.";
|
2021-01-09 14:44:15 +00:00
|
|
|
if (traits->depth < 24)
|
|
|
|
Log(Debug::Warning) << "Warning: Framebuffer only has " << traits->depth << " bits of depth precision.";
|
2020-09-20 12:22:31 +00:00
|
|
|
|
|
|
|
traits->alpha = 0; // set to 0 to stop ScreenCaptureHandler reading the alpha channel
|
|
|
|
}
|
2015-05-13 02:52:04 +02:00
|
|
|
|
|
|
|
osg::ref_ptr<osg::Camera> camera = mViewer->getCamera();
|
2015-05-13 15:08:47 +02:00
|
|
|
camera->setGraphicsContext(graphicsWindow);
|
2020-09-20 12:22:31 +00:00
|
|
|
camera->setViewport(0, 0, graphicsWindow->getTraits()->width, graphicsWindow->getTraits()->height);
|
2015-05-13 02:52:04 +02:00
|
|
|
|
2021-12-15 22:17:38 +00:00
|
|
|
osg::ref_ptr<SceneUtil::OperationSequence> realizeOperations = new SceneUtil::OperationSequence(false);
|
|
|
|
mViewer->setRealizeOperation(realizeOperations);
|
2022-06-06 22:40:38 +02:00
|
|
|
osg::ref_ptr<IdentifyOpenGLOperation> identifyOp = new IdentifyOpenGLOperation();
|
|
|
|
realizeOperations->add(identifyOp);
|
2021-12-15 22:17:38 +00:00
|
|
|
|
2020-09-19 23:30:34 +01:00
|
|
|
if (Debug::shouldDebugOpenGL())
|
2021-12-15 22:17:38 +00:00
|
|
|
realizeOperations->add(new Debug::EnableGLDebugOperation());
|
2018-10-25 00:07:01 +01:00
|
|
|
|
2022-04-04 22:51:23 +02:00
|
|
|
realizeOperations->add(mSelectDepthFormatOperation);
|
|
|
|
realizeOperations->add(mSelectColorFormatOperation);
|
|
|
|
|
|
|
|
if (Stereo::getStereo())
|
2022-09-28 23:50:47 +02:00
|
|
|
realizeOperations->add(new Stereo::InitializeStereoOperation());
|
2022-04-04 22:51:23 +02:00
|
|
|
|
2015-05-13 02:52:04 +02:00
|
|
|
mViewer->realize();
|
2022-06-06 22:40:38 +02:00
|
|
|
mGlMaxTextureImageUnits = identifyOp->getMaxTextureImageUnits();
|
2017-02-22 01:49:54 +01:00
|
|
|
|
2020-09-20 12:22:31 +00:00
|
|
|
mViewer->getEventQueue()->getCurrentEventState()->setWindowRectangle(
|
|
|
|
0, 0, graphicsWindow->getTraits()->width, graphicsWindow->getTraits()->height);
|
2015-05-13 02:52:04 +02:00
|
|
|
}
|
|
|
|
|
2015-05-13 15:03:21 +02:00
|
|
|
void OMW::Engine::setWindowIcon()
|
|
|
|
{
|
2022-05-25 18:29:02 +00:00
|
|
|
std::ifstream windowIconStream;
|
2022-06-19 13:28:33 +02:00
|
|
|
const auto windowIcon = mResDir / "openmw.png";
|
2015-07-17 21:41:53 -05:00
|
|
|
windowIconStream.open(windowIcon, std::ios_base::in | std::ios_base::binary);
|
2015-05-13 15:03:21 +02:00
|
|
|
if (windowIconStream.fail())
|
2022-07-03 00:02:29 +02:00
|
|
|
Log(Debug::Error) << "Error: Failed to open " << windowIcon;
|
2015-05-13 15:03:21 +02:00
|
|
|
osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png");
|
2015-06-05 02:57:31 +02:00
|
|
|
if (!reader)
|
|
|
|
{
|
2018-08-14 23:05:43 +04:00
|
|
|
Log(Debug::Error) << "Error: Failed to read window icon, no png readerwriter found";
|
2015-06-05 02:57:31 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-05-13 15:03:21 +02:00
|
|
|
osgDB::ReaderWriter::ReadResult result = reader->readImage(windowIconStream);
|
|
|
|
if (!result.success())
|
2022-07-03 00:02:29 +02:00
|
|
|
Log(Debug::Error) << "Error: Failed to read " << windowIcon << ": " << result.message() << " code "
|
|
|
|
<< result.status();
|
2015-05-13 15:03:21 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
osg::ref_ptr<osg::Image> image = result.getImage();
|
2018-06-16 12:12:32 +02:00
|
|
|
auto surface = SDLUtil::imageToSurface(image, true);
|
|
|
|
SDL_SetWindowIcon(mWindow, surface.get());
|
2015-05-13 15:03:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-22 02:47:58 +02:00
|
|
|
void OMW::Engine::prepareEngine()
|
2015-05-13 02:52:04 +02:00
|
|
|
{
|
2022-05-06 17:46:50 +02:00
|
|
|
mStateManager = std::make_unique<MWState::StateManager>(mCfgMgr.getUserDataPath() / "saves", mContentFiles);
|
|
|
|
mEnvironment.setStateManager(*mStateManager);
|
2015-05-13 02:52:04 +02:00
|
|
|
|
2022-09-25 21:19:03 +02:00
|
|
|
bool stereoEnabled
|
|
|
|
= Settings::Manager::getBool("stereo enabled", "Stereo") || osg::DisplaySettings::instance().get()->getStereo();
|
|
|
|
mStereoManager = std::make_unique<Stereo::Manager>(mViewer, stereoEnabled);
|
2015-05-13 02:52:04 +02:00
|
|
|
|
2022-04-04 22:51:23 +02:00
|
|
|
osg::ref_ptr<osg::Group> rootNode(new osg::Group);
|
2015-04-24 23:30:30 +02:00
|
|
|
mViewer->setSceneData(rootNode);
|
2015-04-12 15:34:50 +02:00
|
|
|
|
2022-05-22 02:47:58 +02:00
|
|
|
createWindow();
|
2022-04-04 22:51:23 +02:00
|
|
|
|
2023-05-31 23:11:03 +02:00
|
|
|
mVFS = std::make_unique<VFS::Manager>();
|
2015-04-12 15:34:50 +02:00
|
|
|
|
|
|
|
VFS::registerArchives(mVFS.get(), mFileCollections, mArchives, true);
|
|
|
|
|
2022-01-29 23:21:39 +02:00
|
|
|
mResourceSystem = std::make_unique<Resource::ResourceSystem>(mVFS.get());
|
2022-06-06 22:40:38 +02:00
|
|
|
mResourceSystem->getSceneManager()->getShaderManager().setMaxTextureUnits(mGlMaxTextureImageUnits);
|
2016-02-05 23:21:54 +01:00
|
|
|
mResourceSystem->getSceneManager()->setUnRefImageDataAfterApply(
|
|
|
|
false); // keep to Off for now to allow better state sharing
|
2023-07-03 23:47:53 +02:00
|
|
|
mResourceSystem->getSceneManager()->setFilterSettings(Settings::general().mTextureMagFilter,
|
|
|
|
Settings::general().mTextureMinFilter, Settings::general().mTextureMipmap, Settings::general().mAnisotropy);
|
2022-05-06 17:46:50 +02:00
|
|
|
mEnvironment.setResourceSystem(*mResourceSystem);
|
2013-08-27 15:48:13 +02:00
|
|
|
|
2023-05-22 14:23:06 +02:00
|
|
|
mWorkQueue = new SceneUtil::WorkQueue(Settings::cells().mPreloadNumThreads);
|
2022-07-24 20:55:03 +02:00
|
|
|
mUnrefQueue = std::make_unique<SceneUtil::UnrefQueue>();
|
2017-02-14 03:37:45 +01:00
|
|
|
|
2021-05-24 19:27:09 +02:00
|
|
|
mScreenCaptureOperation = new SceneUtil::AsyncScreenCaptureOperation(mWorkQueue,
|
|
|
|
new SceneUtil::WriteScreenshotToFileOperation(mCfgMgr.getScreenshotPath(),
|
2023-07-03 23:47:53 +02:00
|
|
|
Settings::general().mScreenshotFormat,
|
|
|
|
Settings::general().mNotifyOnSavedScreenshot
|
2021-07-11 13:22:26 +02:00
|
|
|
? std::function<void(std::string)>(ScheduleNonDialogMessageBox{})
|
|
|
|
: std::function<void(std::string)>(IgnoreString{})));
|
2021-05-24 19:27:09 +02:00
|
|
|
|
|
|
|
mScreenCaptureHandler = new osgViewer::ScreenCaptureHandler(mScreenCaptureOperation);
|
|
|
|
|
|
|
|
mViewer->addEventHandler(mScreenCaptureHandler);
|
|
|
|
|
2022-10-02 22:38:37 +02:00
|
|
|
mL10nManager = std::make_unique<l10n::Manager>(mVFS.get());
|
2023-07-03 23:47:53 +02:00
|
|
|
mL10nManager->setPreferredLocales(Settings::general().mPreferredLocales, Settings::general().mGmstOverridesL10n);
|
2022-10-02 22:38:37 +02:00
|
|
|
mEnvironment.setL10nManager(*mL10nManager);
|
|
|
|
|
2022-06-19 13:28:33 +02:00
|
|
|
mLuaManager = std::make_unique<MWLua::LuaManager>(mVFS.get(), mResDir / "lua_libs");
|
2022-05-06 17:46:50 +02:00
|
|
|
mEnvironment.setLuaManager(*mLuaManager);
|
2020-12-18 23:21:10 +01:00
|
|
|
|
2013-08-27 15:48:13 +02:00
|
|
|
// Create input and UI first to set up a bootstrapping environment for
|
|
|
|
// showing a loading screen and keeping the window responsive while doing so
|
|
|
|
|
2022-06-19 13:28:33 +02:00
|
|
|
const auto keybinderUser = mCfgMgr.getUserConfigPath() / "input_v3.xml";
|
2022-05-25 18:29:02 +00:00
|
|
|
bool keybinderUserExists = std::filesystem::exists(keybinderUser);
|
2015-01-24 16:44:17 -06:00
|
|
|
if (!keybinderUserExists)
|
|
|
|
{
|
2022-06-19 13:28:33 +02:00
|
|
|
const auto input2 = (mCfgMgr.getUserConfigPath() / "input_v2.xml");
|
2022-05-25 18:29:02 +00:00
|
|
|
if (std::filesystem::exists(input2))
|
|
|
|
{
|
2022-06-19 13:28:33 +02:00
|
|
|
keybinderUserExists = std::filesystem::copy_file(input2, keybinderUser);
|
2022-07-03 00:02:29 +02:00
|
|
|
Log(Debug::Info) << "Loading keybindings file: " << keybinderUser;
|
2015-01-26 12:50:44 -06:00
|
|
|
}
|
2015-01-24 16:44:17 -06:00
|
|
|
}
|
2019-10-30 15:22:24 +04:00
|
|
|
else
|
2022-07-03 00:02:29 +02:00
|
|
|
Log(Debug::Info) << "Loading keybindings file: " << keybinderUser;
|
2015-01-19 18:55:17 -06:00
|
|
|
|
2022-06-19 13:28:33 +02:00
|
|
|
const auto userdefault = mCfgMgr.getUserConfigPath() / "gamecontrollerdb.txt";
|
|
|
|
const auto localdefault = mCfgMgr.getLocalPath() / "gamecontrollerdb.txt";
|
|
|
|
const auto globaldefault = mCfgMgr.getGlobalPath() / "gamecontrollerdb.txt";
|
2019-08-03 19:55:58 +00:00
|
|
|
|
2022-06-19 13:28:33 +02:00
|
|
|
std::filesystem::path userGameControllerdb;
|
2022-05-25 18:29:02 +00:00
|
|
|
if (std::filesystem::exists(userdefault))
|
2019-08-03 19:55:58 +00:00
|
|
|
userGameControllerdb = userdefault;
|
|
|
|
|
2022-06-19 13:28:33 +02:00
|
|
|
std::filesystem::path gameControllerdb;
|
2022-05-25 18:29:02 +00:00
|
|
|
if (std::filesystem::exists(localdefault))
|
2015-01-19 18:55:17 -06:00
|
|
|
gameControllerdb = localdefault;
|
2022-05-25 18:29:02 +00:00
|
|
|
else if (std::filesystem::exists(globaldefault))
|
2015-01-19 18:55:17 -06:00
|
|
|
gameControllerdb = globaldefault;
|
2022-05-04 22:33:39 +02:00
|
|
|
// else if it doesn't exist, pass in an empty string
|
2015-01-19 18:55:17 -06:00
|
|
|
|
2021-07-22 15:55:30 -07:00
|
|
|
// gui needs our shaders path before everything else
|
2022-06-19 13:28:33 +02:00
|
|
|
mResourceSystem->getSceneManager()->setShaderPath(mResDir / "shaders");
|
2021-07-22 15:55:30 -07:00
|
|
|
|
|
|
|
osg::ref_ptr<osg::GLExtensions> exts = osg::GLExtensions::Get(0, false);
|
|
|
|
bool shadersSupported = exts && (exts->glslLanguageVersion >= 1.2f);
|
|
|
|
|
2021-11-06 04:38:43 -07:00
|
|
|
#if OSG_VERSION_LESS_THAN(3, 6, 6)
|
|
|
|
// hack fix for https://github.com/openscenegraph/OpenSceneGraph/issues/1028
|
|
|
|
if (exts)
|
|
|
|
exts->glRenderbufferStorageMultisampleCoverageNV = nullptr;
|
|
|
|
#endif
|
|
|
|
|
2015-04-24 21:55:30 +02:00
|
|
|
osg::ref_ptr<osg::Group> guiRoot = new osg::Group;
|
2017-02-02 21:46:25 +01:00
|
|
|
guiRoot->setName("GUI Root");
|
2020-04-20 18:47:14 +02:00
|
|
|
guiRoot->setNodeMask(MWRender::Mask_GUI);
|
2022-04-04 22:51:23 +02:00
|
|
|
mStereoManager->disableStereoForNode(guiRoot);
|
2015-04-24 21:55:30 +02:00
|
|
|
rootNode->addChild(guiRoot);
|
2022-01-29 23:21:39 +02:00
|
|
|
|
2022-05-06 17:46:50 +02:00
|
|
|
mWindowManager = std::make_unique<MWGui::WindowManager>(mWindow, mViewer, guiRoot, mResourceSystem.get(),
|
2022-07-18 10:40:03 +04:00
|
|
|
mWorkQueue.get(), mCfgMgr.getLogPath(), mScriptConsoleMode, mTranslationDataStorage, mEncoding,
|
2023-02-10 11:54:45 +00:00
|
|
|
Version::getOpenmwVersionDescription(mResDir), shadersSupported, mCfgMgr);
|
2022-05-06 17:46:50 +02:00
|
|
|
mEnvironment.setWindowManager(*mWindowManager);
|
2013-08-27 15:48:13 +02:00
|
|
|
|
2022-05-06 17:46:50 +02:00
|
|
|
mInputManager = std::make_unique<MWInput::InputManager>(mWindow, mViewer, mScreenCaptureHandler,
|
|
|
|
mScreenCaptureOperation, keybinderUser, keybinderUserExists, userGameControllerdb, gameControllerdb, mGrab);
|
|
|
|
mEnvironment.setInputManager(*mInputManager);
|
2020-04-16 17:31:20 +04:00
|
|
|
|
2014-03-27 04:15:47 +01:00
|
|
|
// Create sound system
|
2022-05-06 17:46:50 +02:00
|
|
|
mSoundManager = std::make_unique<MWSound::SoundManager>(mVFS.get(), mUseSound);
|
|
|
|
mEnvironment.setSoundManager(*mSoundManager);
|
2014-03-27 04:15:47 +01:00
|
|
|
|
2023-07-19 20:35:00 +02:00
|
|
|
// Create the world
|
|
|
|
mWorld = std::make_unique<MWWorld::World>(
|
|
|
|
mResourceSystem.get(), mActivationDistanceOverride, mCellName, mCfgMgr.getUserDataPath());
|
|
|
|
|
2023-07-29 12:40:12 +02:00
|
|
|
Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
|
|
|
Loading::AsyncListener asyncListener(*listener);
|
|
|
|
auto dataLoading = std::async(std::launch::async,
|
|
|
|
[&] { mWorld->loadData(mFileCollections, mContentFiles, mGroundcoverFiles, mEncoder.get(), &asyncListener); });
|
2023-07-19 20:35:00 +02:00
|
|
|
|
2014-03-27 19:59:33 +01:00
|
|
|
if (!mSkipMenu)
|
|
|
|
{
|
2022-08-28 17:20:49 +02:00
|
|
|
std::string_view logo = Fallback::Map::getString("Movies_Company_Logo");
|
2014-03-27 19:59:33 +01:00
|
|
|
if (!logo.empty())
|
2022-05-06 17:46:50 +02:00
|
|
|
mWindowManager->playVideo(logo, true);
|
2014-03-27 19:59:33 +01:00
|
|
|
}
|
2014-03-27 04:15:47 +01:00
|
|
|
|
2023-07-19 20:35:00 +02:00
|
|
|
listener->loadingOn();
|
2023-07-29 12:40:12 +02:00
|
|
|
{
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
while (dataLoading.wait_for(50ms) != std::future_status::ready)
|
|
|
|
asyncListener.update();
|
2023-08-08 23:41:39 +02:00
|
|
|
dataLoading.get();
|
2023-07-29 12:40:12 +02:00
|
|
|
}
|
2023-07-19 20:35:00 +02:00
|
|
|
listener->loadingOff();
|
|
|
|
|
|
|
|
mWorld->init(mViewer, rootNode, mWorkQueue.get(), *mUnrefQueue);
|
2022-05-06 17:46:50 +02:00
|
|
|
mWorld->setupPlayer();
|
2022-05-11 16:37:16 +03:00
|
|
|
mWorld->setRandomSeed(mRandomSeed);
|
2022-05-06 17:46:50 +02:00
|
|
|
mEnvironment.setWorld(*mWorld);
|
2022-11-06 17:57:01 +01:00
|
|
|
mEnvironment.setWorldModel(mWorld->getWorldModel());
|
|
|
|
mEnvironment.setWorldScene(mWorld->getWorldScene());
|
2023-04-20 21:07:53 +02:00
|
|
|
mEnvironment.setESMStore(mWorld->getStore());
|
2013-08-27 15:48:13 +02:00
|
|
|
|
2023-03-12 00:34:17 +01:00
|
|
|
const MWWorld::Store<ESM::GameSetting>* gmst = &mWorld->getStore().get<ESM::GameSetting>();
|
2023-04-05 22:47:15 +02:00
|
|
|
mL10nManager->setGmstLoader(
|
|
|
|
[gmst, misses = std::set<std::string, std::less<>>()](std::string_view gmstName) mutable {
|
|
|
|
const ESM::GameSetting* res = gmst->search(gmstName);
|
|
|
|
if (res && res->mValue.getType() == ESM::VT_String)
|
|
|
|
return res->mValue.getString();
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (misses.count(gmstName) == 0)
|
|
|
|
{
|
|
|
|
misses.emplace(gmstName);
|
|
|
|
Log(Debug::Error) << "GMST " << gmstName << " not found";
|
|
|
|
}
|
|
|
|
return std::string("GMST:") + std::string(gmstName);
|
|
|
|
}
|
|
|
|
});
|
2023-03-12 00:34:17 +01:00
|
|
|
|
2022-05-06 17:46:50 +02:00
|
|
|
mWindowManager->setStore(mWorld->getStore());
|
|
|
|
mWindowManager->initUI();
|
2011-02-27 00:50:08 +01:00
|
|
|
|
2012-12-23 23:23:24 +04:00
|
|
|
// Load translation data
|
2022-05-22 01:47:06 +02:00
|
|
|
mTranslationDataStorage.setEncoder(mEncoder.get());
|
2022-06-19 13:28:33 +02:00
|
|
|
for (auto& mContentFile : mContentFiles)
|
|
|
|
mTranslationDataStorage.loadTranslationData(mFileCollections, mContentFile);
|
2012-12-23 23:23:24 +04:00
|
|
|
|
2013-11-16 10:31:46 +01:00
|
|
|
Compiler::registerExtensions(mExtensions);
|
2010-07-07 18:48:06 +02:00
|
|
|
|
2010-07-26 11:15:38 +02:00
|
|
|
// Create script system
|
2022-05-22 01:47:06 +02:00
|
|
|
mScriptContext = std::make_unique<MWScript::CompilerContext>(MWScript::CompilerContext::Type_Full);
|
2010-07-03 12:12:13 +02:00
|
|
|
mScriptContext->setExtensions(&mExtensions);
|
2010-07-02 17:21:27 +02:00
|
|
|
|
2022-05-06 17:46:50 +02:00
|
|
|
mScriptManager = std::make_unique<MWScript::ScriptManager>(mWorld->getStore(), *mScriptContext, mWarningsMode,
|
2022-12-01 20:02:39 +01:00
|
|
|
mScriptBlacklistUse ? mScriptBlacklist : std::vector<ESM::RefId>());
|
2022-05-06 17:46:50 +02:00
|
|
|
mEnvironment.setScriptManager(*mScriptManager);
|
2010-08-01 10:25:50 +02:00
|
|
|
|
2010-07-26 11:15:38 +02:00
|
|
|
// Create game mechanics system
|
2022-05-06 17:46:50 +02:00
|
|
|
mMechanicsManager = std::make_unique<MWMechanics::MechanicsManager>();
|
|
|
|
mEnvironment.setMechanicsManager(*mMechanicsManager);
|
2010-07-02 17:30:26 +02:00
|
|
|
|
2010-08-06 18:01:34 +02:00
|
|
|
// Create dialog system
|
2022-05-06 17:46:50 +02:00
|
|
|
mJournal = std::make_unique<MWDialogue::Journal>();
|
|
|
|
mEnvironment.setJournal(*mJournal);
|
|
|
|
|
|
|
|
mDialogueManager = std::make_unique<MWDialogue::DialogueManager>(mExtensions, mTranslationDataStorage);
|
|
|
|
mEnvironment.setDialogueManager(*mDialogueManager);
|
2010-08-06 18:01:34 +02:00
|
|
|
|
2010-10-06 14:52:53 +02:00
|
|
|
// scripts
|
|
|
|
if (mCompileAll)
|
|
|
|
{
|
2022-05-06 17:46:50 +02:00
|
|
|
std::pair<int, int> result = mScriptManager->compileAll();
|
2011-10-09 12:05:13 +02:00
|
|
|
if (result.first)
|
|
|
|
Log(Debug::Info) << "compiled " << result.second << " of " << result.first << " scripts ("
|
|
|
|
<< 100 * static_cast<double>(result.second) / result.first << "%)";
|
2010-10-06 14:52:53 +02:00
|
|
|
}
|
2014-12-13 02:47:04 +01:00
|
|
|
if (mCompileAllDialogue)
|
|
|
|
{
|
2014-12-18 10:20:15 +01:00
|
|
|
std::pair<int, int> result = MWDialogue::ScriptTest::compileAll(&mExtensions, mWarningsMode);
|
2014-12-13 02:47:04 +01:00
|
|
|
if (result.first)
|
2022-11-03 20:54:44 +01:00
|
|
|
Log(Debug::Info) << "compiled " << result.second << " of " << result.first << " dialogue scripts ("
|
2014-12-13 02:47:04 +01:00
|
|
|
<< 100 * static_cast<double>(result.second) / result.first << "%)";
|
|
|
|
}
|
2020-12-18 23:21:10 +01:00
|
|
|
|
|
|
|
mLuaManager->init();
|
2022-06-19 13:28:33 +02:00
|
|
|
mLuaManager->loadPermanentStorage(mCfgMgr.getUserConfigPath());
|
2023-08-08 23:41:39 +02:00
|
|
|
|
|
|
|
// starts a separate lua thread if "lua num threads" > 0
|
|
|
|
mLuaWorker = std::make_unique<MWLua::Worker>(*mLuaManager, *mViewer);
|
2013-01-08 09:45:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Initialise and enter main loop.
|
|
|
|
void OMW::Engine::go()
|
|
|
|
{
|
2013-09-29 09:11:57 +02:00
|
|
|
assert(!mContentFiles.empty());
|
2015-04-24 23:30:30 +02:00
|
|
|
|
2018-08-14 23:05:43 +04:00
|
|
|
Log(Debug::Info) << "OSG version: " << osgGetVersion();
|
2019-03-15 19:04:47 +03:00
|
|
|
SDL_version sdlVersion;
|
|
|
|
SDL_GetVersion(&sdlVersion);
|
|
|
|
Log(Debug::Info) << "SDL version: " << (int)sdlVersion.major << "." << (int)sdlVersion.minor << "."
|
|
|
|
<< (int)sdlVersion.patch;
|
2017-02-18 03:15:15 +01:00
|
|
|
|
2019-02-24 22:41:11 +03:00
|
|
|
Misc::Rng::init(mRandomSeed);
|
|
|
|
|
2022-06-19 13:28:33 +02:00
|
|
|
Settings::ShaderManager::get().load(mCfgMgr.getUserConfigPath() / "shaders.yaml");
|
2022-05-13 18:58:00 -07:00
|
|
|
|
2020-12-07 19:04:32 +01:00
|
|
|
MWClass::registerClasses();
|
|
|
|
|
2018-06-28 18:05:00 +04:00
|
|
|
// Create encoder
|
2022-05-22 01:47:06 +02:00
|
|
|
mEncoder = std::make_unique<ToUTF8::Utf8Encoder>(mEncoding);
|
2018-06-28 18:05:00 +04:00
|
|
|
|
|
|
|
// Setup viewer
|
|
|
|
mViewer = new osgViewer::Viewer;
|
|
|
|
mViewer->setReleaseContextAtEndOfFrameHint(false);
|
|
|
|
|
2019-04-22 21:14:51 +04:00
|
|
|
// Do not try to outsmart the OS thread scheduler (see bug #4785).
|
|
|
|
mViewer->setUseConfigureAffinity(false);
|
|
|
|
|
2017-08-30 21:26:30 +00:00
|
|
|
mEnvironment.setFrameRateLimit(Settings::Manager::getFloat("framerate limit", "Video"));
|
|
|
|
|
2022-05-22 02:47:58 +02:00
|
|
|
prepareEngine();
|
2013-01-08 09:45:01 -08:00
|
|
|
|
2022-07-03 00:02:29 +02:00
|
|
|
#ifdef _WIN32
|
2022-08-19 15:55:02 +02:00
|
|
|
const auto* stats_file = _wgetenv(L"OPENMW_OSG_STATS_FILE");
|
2022-07-03 00:02:29 +02:00
|
|
|
#else
|
2022-08-19 15:55:02 +02:00
|
|
|
const auto* stats_file = std::getenv("OPENMW_OSG_STATS_FILE");
|
2022-07-03 00:02:29 +02:00
|
|
|
#endif
|
2022-08-19 15:55:02 +02:00
|
|
|
|
|
|
|
std::filesystem::path path;
|
|
|
|
if (stats_file != nullptr)
|
|
|
|
path = stats_file;
|
|
|
|
|
|
|
|
std::ofstream stats;
|
|
|
|
if (!path.empty())
|
2021-01-27 08:04:33 +00:00
|
|
|
{
|
2022-07-03 00:02:29 +02:00
|
|
|
stats.open(path, std::ios_base::out);
|
2021-01-27 08:04:33 +00:00
|
|
|
if (stats.is_open())
|
2023-02-03 01:26:43 +01:00
|
|
|
Log(Debug::Info) << "OSG stats will be written to: " << path;
|
2021-01-27 08:04:33 +00:00
|
|
|
else
|
2023-02-03 01:26:43 +01:00
|
|
|
Log(Debug::Warning) << "Failed to open file to write OSG stats \"" << path
|
|
|
|
<< "\": " << std::generic_category().message(errno);
|
2021-01-27 08:04:33 +00:00
|
|
|
}
|
|
|
|
|
2018-06-28 18:05:00 +04:00
|
|
|
// Setup profiler
|
2022-07-07 19:34:18 +04:00
|
|
|
osg::ref_ptr<Resource::Profiler> statshandler = new Resource::Profiler(stats.is_open(), mVFS.get());
|
2018-06-28 18:05:00 +04:00
|
|
|
|
2020-06-28 01:44:56 +02:00
|
|
|
initStatsHandler(*statshandler);
|
2018-06-28 18:05:00 +04:00
|
|
|
|
|
|
|
mViewer->addEventHandler(statshandler);
|
|
|
|
|
2022-07-07 19:34:18 +04:00
|
|
|
osg::ref_ptr<Resource::StatsHandler> resourceshandler = new Resource::StatsHandler(stats.is_open(), mVFS.get());
|
2018-06-28 18:05:00 +04:00
|
|
|
mViewer->addEventHandler(resourceshandler);
|
|
|
|
|
2021-01-27 08:04:33 +00:00
|
|
|
if (stats.is_open())
|
|
|
|
Resource::CollectStatistics(mViewer);
|
|
|
|
|
2018-06-28 18:05:00 +04:00
|
|
|
// Start the game
|
2015-01-07 03:03:56 +01:00
|
|
|
if (!mSaveGameFile.empty())
|
|
|
|
{
|
2022-05-06 17:46:50 +02:00
|
|
|
mStateManager->loadGame(mSaveGameFile);
|
2015-01-07 03:03:56 +01:00
|
|
|
}
|
2015-05-07 21:57:02 +02:00
|
|
|
else if (!mSkipMenu)
|
2014-03-27 04:15:47 +01:00
|
|
|
{
|
2015-01-07 03:03:56 +01:00
|
|
|
// start in main menu
|
2022-05-06 17:46:50 +02:00
|
|
|
mWindowManager->pushGuiMode(MWGui::GM_MainMenu);
|
2023-01-21 01:16:08 +03:00
|
|
|
mSoundManager->playPlaylist("Title");
|
2022-08-28 17:20:49 +02:00
|
|
|
std::string_view logo = Fallback::Map::getString("Movies_Morrowind_Logo");
|
2019-03-04 01:31:51 +03:00
|
|
|
if (!logo.empty())
|
2022-08-01 05:00:06 +03:00
|
|
|
mWindowManager->playVideo(logo, /*allowSkipping*/ true, /*overrideSounds*/ false);
|
2014-03-27 04:15:47 +01:00
|
|
|
}
|
2013-11-16 12:22:28 +01:00
|
|
|
else
|
2014-05-20 18:35:17 +02:00
|
|
|
{
|
2022-05-06 17:46:50 +02:00
|
|
|
mStateManager->newGame(!mNewGame);
|
2014-05-20 18:35:17 +02:00
|
|
|
}
|
2014-03-13 13:19:32 +01:00
|
|
|
|
2022-05-06 17:46:50 +02:00
|
|
|
if (!mStartupScript.empty() && mStateManager->getState() == MWState::StateManager::State_Running)
|
2019-02-23 22:39:13 +03:00
|
|
|
{
|
2022-05-06 17:46:50 +02:00
|
|
|
mWindowManager->executeInConsole(mStartupScript);
|
2019-02-23 22:39:13 +03:00
|
|
|
}
|
|
|
|
|
2010-06-16 12:13:21 +02:00
|
|
|
// Start the main rendering loop
|
2023-08-06 16:09:41 +02:00
|
|
|
MWWorld::DateTimeManager& timeManager = *mWorld->getTimeManager();
|
2021-02-11 18:19:55 +01:00
|
|
|
Misc::FrameRateLimiter frameRateLimiter = Misc::makeFrameRateLimiter(mEnvironment.getFrameRateLimit());
|
|
|
|
const std::chrono::steady_clock::duration maxSimulationInterval(std::chrono::milliseconds(200));
|
2022-05-06 17:46:50 +02:00
|
|
|
while (!mViewer->done() && !mStateManager->hasQuitRequest())
|
2015-04-12 15:34:50 +02:00
|
|
|
{
|
2021-02-11 18:19:55 +01:00
|
|
|
const double dt = std::chrono::duration_cast<std::chrono::duration<double>>(
|
|
|
|
std::min(frameRateLimiter.getLastFrameDuration(), maxSimulationInterval))
|
2022-07-03 12:51:28 +00:00
|
|
|
.count()
|
2023-08-06 16:09:41 +02:00
|
|
|
* timeManager.getSimulationTimeScale();
|
2015-04-14 15:55:56 +02:00
|
|
|
|
2023-08-06 16:09:41 +02:00
|
|
|
mViewer->advance(timeManager.getSimulationTime());
|
2015-06-14 15:27:33 +02:00
|
|
|
|
2017-11-16 17:56:44 +01:00
|
|
|
if (!frame(dt))
|
2015-09-04 03:44:14 +02:00
|
|
|
{
|
2020-06-25 21:46:07 +02:00
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
2015-09-07 16:05:51 +02:00
|
|
|
continue;
|
2015-09-04 03:44:14 +02:00
|
|
|
}
|
2023-08-06 16:09:41 +02:00
|
|
|
timeManager.updateIsPaused();
|
|
|
|
if (!timeManager.isPaused())
|
|
|
|
timeManager.setSimulationTime(timeManager.getSimulationTime() + dt);
|
2015-09-07 16:05:51 +02:00
|
|
|
|
2020-05-16 13:45:02 +02:00
|
|
|
if (stats)
|
|
|
|
{
|
2023-02-01 22:01:53 +01:00
|
|
|
constexpr unsigned statsReportDelay = 3;
|
2020-05-16 13:45:02 +02:00
|
|
|
const auto frameNumber = mViewer->getFrameStamp()->getFrameNumber();
|
2023-02-01 22:01:53 +01:00
|
|
|
if (frameNumber >= statsReportDelay)
|
2020-07-11 16:16:44 +02:00
|
|
|
{
|
2023-02-01 22:01:53 +01:00
|
|
|
const unsigned reportFrameNumber = frameNumber - statsReportDelay;
|
|
|
|
mViewer->getViewerStats()->report(stats, reportFrameNumber);
|
2020-07-11 16:16:44 +02:00
|
|
|
osgViewer::Viewer::Cameras cameras;
|
|
|
|
mViewer->getCameras(cameras);
|
|
|
|
for (auto camera : cameras)
|
2023-02-01 22:01:53 +01:00
|
|
|
camera->getStats()->report(stats, reportFrameNumber);
|
2020-07-11 16:16:44 +02:00
|
|
|
}
|
2020-05-16 13:45:02 +02:00
|
|
|
}
|
|
|
|
|
2021-02-11 18:19:55 +01:00
|
|
|
frameRateLimiter.limit();
|
2015-04-12 15:34:50 +02:00
|
|
|
}
|
|
|
|
|
2022-10-06 01:56:47 +02:00
|
|
|
mLuaWorker->join();
|
2020-12-18 23:21:10 +01:00
|
|
|
|
2012-04-01 18:48:37 +02:00
|
|
|
// Save user settings
|
2022-06-19 13:28:33 +02:00
|
|
|
Settings::Manager::saveUser(mCfgMgr.getUserConfigPath() / "settings.cfg");
|
2022-05-13 18:58:00 -07:00
|
|
|
Settings::ShaderManager::get().save();
|
2022-06-19 13:28:33 +02:00
|
|
|
mLuaManager->savePermanentStorage(mCfgMgr.getUserConfigPath());
|
2012-04-01 18:48:37 +02:00
|
|
|
|
2018-08-14 23:05:43 +04:00
|
|
|
Log(Debug::Info) << "Quitting peacefully.";
|
2010-06-16 12:13:21 +02:00
|
|
|
}
|
2010-08-05 13:36:33 +02:00
|
|
|
|
2010-10-06 14:52:53 +02:00
|
|
|
void OMW::Engine::setCompileAll(bool all)
|
|
|
|
{
|
|
|
|
mCompileAll = all;
|
|
|
|
}
|
Added new command line option: "encoding"
Added new command line option: "encoding" which allow to
change font encoding used in game messages.
Currently there are three evailable encodings:
win1250 - Central and Eastern European (languages
that use Latin script, such as Polish,
Czech, Slovak, Hungarian, Slovene, Bosnian,
Croatian, Serbian (Latin script),
Romanian and Albanian)
win1251 - languages that use the Cyrillic alphabet
such as Russian, Bulgarian, Serbian Cyrillic
and others
win1252 - Western European (Latin) - default
Signed-off-by: Lukasz Gromanowski <lgromanowski@gmail.com>
2011-07-17 22:16:50 +02:00
|
|
|
|
2014-12-13 02:47:04 +01:00
|
|
|
void OMW::Engine::setCompileAllDialogue(bool all)
|
|
|
|
{
|
|
|
|
mCompileAllDialogue = all;
|
|
|
|
}
|
Added new command line option: "encoding"
Added new command line option: "encoding" which allow to
change font encoding used in game messages.
Currently there are three evailable encodings:
win1250 - Central and Eastern European (languages
that use Latin script, such as Polish,
Czech, Slovak, Hungarian, Slovene, Bosnian,
Croatian, Serbian (Latin script),
Romanian and Albanian)
win1251 - languages that use the Cyrillic alphabet
such as Russian, Bulgarian, Serbian Cyrillic
and others
win1252 - Western European (Latin) - default
Signed-off-by: Lukasz Gromanowski <lgromanowski@gmail.com>
2011-07-17 22:16:50 +02:00
|
|
|
|
2011-08-19 21:06:09 +02:00
|
|
|
void OMW::Engine::setSoundUsage(bool soundUsage)
|
|
|
|
{
|
|
|
|
mUseSound = soundUsage;
|
|
|
|
}
|
|
|
|
|
2012-12-23 23:23:24 +04:00
|
|
|
void OMW::Engine::setEncoding(const ToUTF8::FromType& encoding)
|
Added new command line option: "encoding"
Added new command line option: "encoding" which allow to
change font encoding used in game messages.
Currently there are three evailable encodings:
win1250 - Central and Eastern European (languages
that use Latin script, such as Polish,
Czech, Slovak, Hungarian, Slovene, Bosnian,
Croatian, Serbian (Latin script),
Romanian and Albanian)
win1251 - languages that use the Cyrillic alphabet
such as Russian, Bulgarian, Serbian Cyrillic
and others
win1252 - Western European (Latin) - default
Signed-off-by: Lukasz Gromanowski <lgromanowski@gmail.com>
2011-07-17 22:16:50 +02:00
|
|
|
{
|
|
|
|
mEncoding = encoding;
|
2011-08-19 21:06:09 +02:00
|
|
|
}
|
2012-04-02 20:47:09 +02:00
|
|
|
|
2012-07-30 11:43:28 +02:00
|
|
|
void OMW::Engine::setScriptConsoleMode(bool enabled)
|
|
|
|
{
|
|
|
|
mScriptConsoleMode = enabled;
|
|
|
|
}
|
2012-07-30 12:37:46 +02:00
|
|
|
|
2023-05-06 13:58:39 +02:00
|
|
|
void OMW::Engine::setStartupScript(const std::filesystem::path& path)
|
2012-07-30 12:37:46 +02:00
|
|
|
{
|
|
|
|
mStartupScript = path;
|
|
|
|
}
|
2013-01-08 19:52:18 -08:00
|
|
|
|
|
|
|
void OMW::Engine::setActivationDistanceOverride(int distance)
|
|
|
|
{
|
|
|
|
mActivationDistanceOverride = distance;
|
2013-08-16 13:01:52 +02:00
|
|
|
}
|
2014-02-02 14:09:59 +01:00
|
|
|
|
|
|
|
void OMW::Engine::setWarningsMode(int mode)
|
|
|
|
{
|
|
|
|
mWarningsMode = mode;
|
2014-02-28 17:23:58 +01:00
|
|
|
}
|
2014-07-21 09:34:10 +02:00
|
|
|
|
2022-12-01 20:02:39 +01:00
|
|
|
void OMW::Engine::setScriptBlacklist(const std::vector<ESM::RefId>& list)
|
2014-07-21 09:34:10 +02:00
|
|
|
{
|
|
|
|
mScriptBlacklist = list;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OMW::Engine::setScriptBlacklistUse(bool use)
|
|
|
|
{
|
|
|
|
mScriptBlacklistUse = use;
|
2014-08-11 20:37:29 +02:00
|
|
|
}
|
|
|
|
|
2022-06-19 13:28:33 +02:00
|
|
|
void OMW::Engine::setSaveGameFile(const std::filesystem::path& savegame)
|
2015-01-07 03:03:56 +01:00
|
|
|
{
|
|
|
|
mSaveGameFile = savegame;
|
|
|
|
}
|
2019-02-24 22:41:11 +03:00
|
|
|
|
|
|
|
void OMW::Engine::setRandomSeed(unsigned int seed)
|
|
|
|
{
|
|
|
|
mRandomSeed = seed;
|
|
|
|
}
|