Engine initialization and main loop
Before a Urho3D application can enter its main loop, the Engine subsystem object must be created and initialized by calling its Initialize() function. Parameters sent in a VariantMap can be used to direct how the Engine initializes itself and the subsystems. One way to configure the parameters is to parse them from the command line like the Urho3DPlayer application does: this is accomplished by the helper function ParseParameters().
The full list of supported parameters, their datatypes and default values: (also defined as constants in Engine/EngineDefs.h)
- Headless (bool) Headless mode enable. Default false.
- LogLevel (int) Log verbosity level. Default LOG_INFO in release builds and LOG_DEBUG in debug builds.
- LogQuiet (bool) Log quiet mode, ie. to not write warning/info/debug log entries into standard output. Default false.
- LogName (string) Log filename. Default "Urho3D.log".
- FrameLimiter (bool) Whether to cap maximum framerate to 200 (desktop) or 60 (Android/iOS.) Default true.
- WorkerThreads (bool) Whether to create worker threads for the WorkQueue subsystem according to available CPU cores. Default true.
- EventProfiler (bool) Whether to create the EventProfiler subsystem. Default true.
- ResourcePrefixPaths (string) A semicolon-separated list of resource prefix paths to use. If not specified then the default prefix path is set to executable path. The resource prefix paths can also be defined using URHO3D_PREFIX_PATH env-var. When both are defined, the paths set by -pp takes higher precedence.
- ResourcePaths (string) A semicolon-separated list of resource paths to use. If corresponding packages (ie. Data.pak for Data directory) exist they will be used instead. Default "Data;CoreData".
- ResourcePackages (string) A semicolon-separated list of resource packages to use. Default empty.
- AutoloadPaths (string) A semicolon-separated list of autoload paths to use. Any resource packages and subdirectories inside an autoload path will be added to the resource system. Default "Autoload".
- ExternalWindow (void ptr) External window handle to use instead of creating an application window. Default null.
- WindowIcon (string) Window icon image resource name. Default empty (use application default icon.)
- WindowTitle (string) Window title. Default "Urho3D".
- WindowWidth (int) Window horizontal dimension. Default 0 (use desktop resolution, or 1024 in windowed mode.)
- WindowHeight (int) Window vertical dimension. Default 0 (use desktop resolution, or 768 in windowed mode.)
- WindowPositionX (int) Window horizontal position. Default center to screen.
- WindowPositionY (int) Window vertical position. Default center to screen.
- FullScreen (bool) Whether to create a full-screen window. Default true.
- Borderless (bool) Whether to create the window as borderless. Default false.
- WindowResizable (bool) Whether window is resizable. Default false.
- HighDPI (bool) Whether window is high DPI. Default true. Currently only supported by Apple platforms (OSX, iOS, and tvOS).
- TripleBuffer (bool) Whether to use triple-buffering. Default false.
- VSync (bool) Whether to wait for vertical sync when presenting rendering window contents. Default false.
- FlushGPU (bool) Whether to flush GPU command buffer each frame (Direct3D9) or limit the amount of buffered frames (Direct3D11) for less input latency. Ineffective on OpenGL. Default false.
- ForceGL2 (bool) When true, forces OpenGL 2 use even if OpenGL 3 is available. No effect on Direct3D or mobile builds. Default false.
- Multisample (int) Hardware multisampling level. Default 1 (no multisampling.)
- Orientations (string) Space-separated list of allowed orientations. Effective only on iOS. All possible values are "LandscapeLeft", "LandscapeRight", "Portrait" and "PortraitUpsideDown". Default "LandscapeLeft LandscapeRight".
- Monitor (int) Monitor number to use. 0 is the default (primary) monitor.
- RefreshRate (int) Monitor refresh rate in Hz to use.
- DumpShaders (string) Filename to dump used shader variations to for precaching.
- RenderPath (string) Default renderpath resource name. Default empty, which causes forward rendering (bin/CoreData/RenderPaths/Forward.xml) to be used.
- Shadows (bool) Shadow rendering enable. Default true.
- LowQualityShadows (bool) Low-quality (1 sample) shadow mode. Default false.
- MaterialQuality (int) Material quality level. Default 2 (high)
- TextureQuality (int) Texture quality level. Default 2 (high)
- TextureFilterMode (int) Texture default filter mode. Default 2 (trilinear)
- TextureAnisotropy (int) Texture anisotropy level. Default 4. This has only effect for anisotropically filtered textures.
- Sound (bool) Sound enable. Default true.
- SoundBuffer (int) Sound buffer length in milliseconds. Default 100.
- SoundMixRate (int) Sound output frequency in Hz. Default 44100.
- SoundStereo (bool) Stereo sound output mode. Default true.
- SoundInterpolation (bool) Interpolated sound output mode to improve quality. Default true.
- TouchEmulation (bool) Touch emulation on desktop platform. Default false.
- ShaderCacheDir (string) Shader binary cache directory for Direct3D. Default "urho3d/shadercache" within the user's application preferences directory.
- PackageCacheDir (string) Package cache directory for Network subsystem. Not specified by default.
The main loop iteration (also called a frame) is driven by the Engine. In contrast it is the program's (for example Urho3DPlayer) responsibility to continuously loop this iteration by calling RunFrame(). This function calls in turn the Time subsystem's BeginFrame() and EndFrame() functions, and sends various update events in between. The event order is:
- E_BEGINFRAME: signals the beginning of the new frame. Input and Network react to this to check for operating system window messages and arrived network packets.
- E_UPDATE: application-wide logic update event. By default each update-enabled Scene reacts to this and triggers the scene update (more on this below.)
- E_POSTUPDATE: application-wide logic post-update event. The UI subsystem updates its logic here.
- E_RENDERUPDATE: Renderer updates its viewports here to prepare for rendering, and the UI generates render commands necessary to render the user interface.
- E_POSTRENDERUPDATE: by default nothing hooks to this. This can be used to implement logic that requires the rendering views to be up-to-date, for example to do accurate raycasts. Scenes may not be modified at this point; especially scene objects may not be deleted or crashes may occur.
- E_ENDFRAME: signals the end of the frame. Before this, rendering the frame and measuring the next frame's timestep will have occurred.
The update of each Scene causes further events to be sent:
- E_SCENEUPDATE: variable timestep scene update. This is a good place to implement any scene logic that does not need to happen at a fixed step.
- E_SCENESUBSYSTEMUPDATE: update scene-wide subsystems. Currently only the PhysicsWorld component listens to this, which causes it to step the physics simulation and send the following two events for each simulation step:
- E_PHYSICSPRESTEP: called before the simulation iteration. Happens at a fixed rate (the physics FPS.) If fixed timestep logic updates are needed, this is a good event to listen to.
- E_PHYSICSPOSTSTEP: called after the simulation iteration. Happens at the same rate as E_PHYSICSPRESTEP.
- E_SMOOTHINGUPDATE: update SmoothedTransform components in network client scenes.
- E_SCENEPOSTUPDATE: variable timestep scene post-update. ParticleEmitter and AnimationController update themselves as a response to this event.
Variable timestep logic updates are preferable to fixed timestep, because they are only executed once per frame. In contrast, if the rendering framerate is low, several physics simulation steps will be performed on each frame to keep up the apparent passage of time, and if this also causes a lot of logic code to be executed for each step, the program may bog down further if the CPU can not handle the load. Note that the Engine's minimum FPS, by default 10, sets a hard cap for the timestep to prevent spiraling down to a complete halt; if exceeded, animation and physics will instead appear to slow down.
The application window's state (has input focus, minimized or not) can be queried from the Input subsystem. It can also effect the main loop in the following ways:
- Rendering is always skipped when the window is minimized.
- To avoid spinning the CPU and GPU unnecessarily, it is possible to define a smaller maximum FPS when no input focus. See SetMaxInactiveFps()
- It is also possible to automatically pause update events and audio when the window is minimized. Use SetPauseMinimized() to control this behaviour. By default it is not enabled on desktop, and enabled on mobile devices (Android and iOS.) For singleplayer games this is recommended to avoid unwanted progression while away from the program. However in a multiplayer game this should not be used, as the missing scene updates would likely desync the client with the server.
- On mobile devices the window becoming minimized can mean that it will never become maximized again, in case the OS decides it needs to free memory and kills your program. Therefore you should listen for the E_INPUTFOCUS event from the Input subsystem and immediately save your program state as applicable if the program loses input focus or is minimized.
- On mobile devices it is also unsafe to access or create any graphics resources while the window is minimized (as the graphics context may be destroyed during this time); doing so can crash the program. It is recommended to leave the pause-minimized feature on to ensure you do not have to check for this in your update code.
Note that on iOS calling Exit() is a no-op as there is no officially sanctioned way to manually exit your program. On Android it will cause the activity to manually exit.
The Application class provides a minimal framework for a Urho3D C++ application with a main loop. It has virtual functions Setup(), Start() and Stop() which can be defined by the application subclass. The header file also provides a macro for defining a program entry point, which will instantiate the Context object and then the user-specified application class. A minimal example, which would just display a blank rendering window and exit by pressing ESC: