// Copyright (c) 2008-2023 the Urho3D project // License: MIT #include "../Precompiled.h" #include "../Audio/Audio.h" #include "../Core/Context.h" #include "../Core/CoreEvents.h" #include "../Core/EventProfiler.h" #include "../Core/ProcessUtils.h" #include "../Core/WorkQueue.h" #include "../Engine/Console.h" #include "../Engine/DebugHud.h" #include "../Engine/Engine.h" #include "../Engine/EngineDefs.h" #include "../Graphics/Graphics.h" #include "../Graphics/Renderer.h" #include "../Input/Input.h" #include "../IO/FileSystem.h" #include "../IO/Log.h" #include "../IO/PackageFile.h" #ifdef URHO3D_IK #include "../IK/IK.h" #endif #ifdef URHO3D_NAVIGATION #include "../Navigation/NavigationMesh.h" #endif #ifdef URHO3D_NETWORK #include "../Network/Network.h" #endif #ifdef URHO3D_DATABASE #include "../Database/Database.h" #endif #ifdef URHO3D_PHYSICS #include "../Physics/PhysicsWorld.h" #include "../Physics/RaycastVehicle.h" #endif #ifdef URHO3D_PHYSICS2D #include "../Physics2D/Physics2D.h" #endif #include "../Resource/ResourceCache.h" #include "../Resource/Localization.h" #include "../Scene/Scene.h" #include "../Scene/SceneEvents.h" #include "../UI/UI.h" #ifdef URHO3D_URHO2D #include "../Urho2D/Urho2D.h" #endif #if defined(__EMSCRIPTEN__) && defined(URHO3D_TESTING) #include #endif #include "../DebugNew.h" #if defined(_MSC_VER) && defined(_DEBUG) // From dbgint.h #define nNoMansLandSize 4 typedef struct _CrtMemBlockHeader { struct _CrtMemBlockHeader* pBlockHeaderNext; struct _CrtMemBlockHeader* pBlockHeaderPrev; char* szFileName; int nLine; size_t nDataSize; int nBlockUse; long lRequest; unsigned char gap[nNoMansLandSize]; } _CrtMemBlockHeader; #endif namespace Urho3D { extern const char* logLevelPrefixes[]; Engine::Engine(Context* context) : Object(context), timeStep_(0.0f), timeStepSmoothing_(2), minFps_(10), #if defined(IOS) || defined(TVOS) || defined(__ANDROID__) || defined(__arm__) || defined(__aarch64__) maxFps_(60), maxInactiveFps_(10), pauseMinimized_(true), #else maxFps_(200), maxInactiveFps_(60), pauseMinimized_(false), #endif #ifdef URHO3D_TESTING timeOut_(0), #endif autoExit_(true), initialized_(false), exiting_(false), headless_(false), audioPaused_(false) { // Register self as a subsystem context_->RegisterSubsystem(this); // Create subsystems which do not depend on engine initialization or startup parameters context_->RegisterSubsystem(new Time(context_)); context_->RegisterSubsystem(new WorkQueue(context_)); #ifdef URHO3D_PROFILING context_->RegisterSubsystem(new Profiler(context_)); #endif context_->RegisterSubsystem(new FileSystem(context_)); #ifdef URHO3D_LOGGING context_->RegisterSubsystem(new Log(context_)); #endif context_->RegisterSubsystem(new ResourceCache(context_)); context_->RegisterSubsystem(new Localization(context_)); #ifdef URHO3D_NETWORK context_->RegisterSubsystem(new Network(context_)); #endif #ifdef URHO3D_DATABASE context_->RegisterSubsystem(new Database(context_)); #endif context_->RegisterSubsystem(new Input(context_)); context_->RegisterSubsystem(new Audio(context_)); context_->RegisterSubsystem(new UI(context_)); // Register object factories for libraries which are not automatically registered along with subsystem creation RegisterSceneLibrary(context_); #ifdef URHO3D_IK RegisterIKLibrary(context_); #endif #ifdef URHO3D_PHYSICS RegisterPhysicsLibrary(context_); #endif #ifdef URHO3D_PHYSICS2D RegisterPhysics2DLibrary(context_); #endif #ifdef URHO3D_NAVIGATION RegisterNavigationLibrary(context_); #endif SubscribeToEvent(E_EXITREQUESTED, URHO3D_HANDLER(Engine, HandleExitRequested)); } Engine::~Engine() = default; bool Engine::Initialize(const VariantMap& parameters) { if (initialized_) return true; URHO3D_PROFILE(InitEngine); // Set headless mode headless_ = GetParameter(parameters, EP_HEADLESS, false).GetBool(); // Detect GAPI even in headless mode // https://github.com/urho3d/Urho3D/issues/3040 GAPI gapi = GAPI_NONE; // Try to set any possible graphics API as default #ifdef URHO3D_OPENGL gapi = GAPI_OPENGL; #endif #ifdef URHO3D_D3D11 gapi = GAPI_D3D11; #endif // Use command line parameters #ifdef URHO3D_OPENGL bool gapi_gl = GetParameter(parameters, EP_OPENGL, false).GetBool(); if (gapi_gl) gapi = GAPI_OPENGL; #endif #ifdef URHO3D_D3D11 bool gapi_d3d11 = GetParameter(parameters, EP_DIRECT3D11, false).GetBool(); if (gapi_d3d11) gapi = GAPI_D3D11; #endif if (gapi == GAPI_NONE) { URHO3D_LOGERROR("Graphics API not selected"); return false; } // Register the rest of the subsystems if (!headless_) { context_->RegisterSubsystem(new Graphics(context_, gapi)); context_->RegisterSubsystem(new Renderer(context_)); } else { Graphics::SetGAPI(gapi); // https://github.com/urho3d/Urho3D/issues/3040 // Register graphics library objects explicitly in headless mode to allow them to work without using actual GPU resources RegisterGraphicsLibrary(context_); } #ifdef URHO3D_URHO2D // 2D graphics library is dependent on 3D graphics library RegisterUrho2DLibrary(context_); #endif // Start logging auto* log = GetSubsystem(); if (log) { if (HasParameter(parameters, EP_LOG_LEVEL)) log->SetLevel(GetParameter(parameters, EP_LOG_LEVEL).GetI32()); log->SetQuiet(GetParameter(parameters, EP_LOG_QUIET, false).GetBool()); log->Open(GetParameter(parameters, EP_LOG_NAME, "Urho3D.log").GetString()); } // Set maximally accurate low res timer GetSubsystem