1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
|
#pragma once
#include "../Main.h"
#include "Graphics/IGfxDevice.h"
#include "Graphics/IDebugOverlay.h"
#include "AppConfiguration.h"
#include "Base/TimeStamp.h"
#include <memory>
#include <Containers/StringView.h>
#include <Core/ITraceSink.h>
#include <IO/Stream.h>
#if defined(DEATH_TARGET_WINDOWS)
# include <CommonWindows.h>
#endif
using namespace Death;
namespace nCine
{
class FrameTimer;
class SceneNode;
class Viewport;
class ScreenViewport;
class IInputManager;
class IAppEventHandler;
#if defined(WITH_IMGUI)
class ImGuiDrawing;
#endif
/** @brief Delegate type that creates an instance of @ref IAppEventHandler */
using CreateAppEventHandlerDelegate = std::unique_ptr<IAppEventHandler>(*)();
/** @brief Base class for main entry points of nCine applications */
class Application
#if defined(DEATH_TRACE)
: public ITraceSink
#endif
{
public:
/** @brief Rendering settings that can be changed at run-time */
struct RenderingSettings
{
RenderingSettings()
: batchingEnabled(true), batchingWithIndices(false), cullingEnabled(true), minBatchSize(4), maxBatchSize(585) {}
/** @brief Whether batching is enabled */
bool batchingEnabled;
/** @brief Whether using indices for vertex batching */
bool batchingWithIndices;
/** @brief Whether node culling is enabled */
bool cullingEnabled;
/** @brief Minimum size for a batch to be collected */
std::uint32_t minBatchSize;
/** @brief Maximum size for a batch before a forced split */
std::uint32_t maxBatchSize;
};
#if defined(WITH_IMGUI) || defined(DOXYGEN_GENERATING_OUTPUT)
/** @brief GUI settings (for ImGui) that can be changed at run-time */
struct GuiSettings
{
GuiSettings();
/** @brief ImGui drawable node layer */
std::uint16_t imguiLayer;
/**
@brief ImGui viewport
The viewport should mirror the screen dimensions or mouse input would not work. Setting `nullptr` is the same as setting the screen
*/
Viewport* imguiViewport;
};
#endif
/** @brief Timings for profiling */
enum class Timings
{
PreInit,
InitCommon,
AppInit,
BeginFrame,
UpdateVisitDraw,
Update,
PostUpdate,
Visit,
Draw,
ImGui,
EndFrame,
Count
};
/** @{ @name Constants */
/** @brief Can be used in @ref AttachTraceTarget() to attach to a console */
static constexpr char const* ConsoleTarget = "\n";
/** @} */
/** @brief Returns the configuration used to initialize the application */
inline const AppConfiguration& GetAppConfiguration() const { return appCfg_; }
/** @brief Returns the run-time rendering settings */
inline RenderingSettings& GetRenderingSettings() { return renderingSettings_; }
#if defined(WITH_IMGUI) || defined(DOXYGEN_GENERATING_OUTPUT)
/** @brief Returns run-time GUI settings */
inline GuiSettings& GetGuiSettings() { return guiSettings_; }
/** @brief Returns debug overlay settings */
inline IDebugOverlay::DisplaySettings& GetDebugOverlaySettings() { return (debugOverlay_ != nullptr ? debugOverlay_->GetSettings() : debugOverlayNullSettings_); }
#endif
#if defined(NCINE_PROFILING) || defined(DOXYGEN_GENERATING_OUTPUT)
/** @brief Returns all timings */
inline StaticArrayView<(std::int32_t)Timings::Count, const float> GetTimings() const { return timings_; }
#endif
/** @brief Returns the graphics device instance */
inline IGfxDevice& GetGfxDevice() { return *gfxDevice_; }
/** @brief Returns the root of the transformation graph */
inline SceneNode& GetRootNode() { return *rootNode_; }
/** @brief Returns the screen viewport */
Viewport& GetScreenViewport();
/** @brief Returns the input manager instance */
inline IInputManager& GetInputManager() { return *inputManager_; }
/** @brief Returns the total number of frames already rendered */
std::uint32_t GetFrameCount() const;
/** @brief Returns a factor that represents how long the last frame took relative to the desired frame time */
float GetTimeMult() const;
/** @brief Returns the frame timer interface */
const FrameTimer& GetFrameTimer() const;
/** @brief Returns the drawable screen width as an integer number */
inline std::int32_t GetWidth() const { return gfxDevice_->drawableWidth(); }
/** @brief Returns the drawable screen height as an integer number */
inline std::int32_t GetHeight() const { return gfxDevice_->drawableHeight(); }
/** @brief Returns the drawable screen resolution as a `Vector2i` object */
inline Vector2i GetResolution() const { return gfxDevice_->drawableResolution(); }
/** @brief Resizes the screen viewport, if exists */
void ResizeScreenViewport(std::int32_t width, std::int32_t height);
/** @brief Returns whether the application should currently be suspended */
bool ShouldSuspend();
/** @brief Returns the value of the auto-suspension flag (the application will be suspended when it loses focus) */
inline bool GetAutoSuspension() const {
return autoSuspension_;
}
/** @brief Sets the auto-suspension flag value */
inline void SetAutoSuspension(bool autoSuspension) {
autoSuspension_ = autoSuspension;
}
/** @brief Raises the quit flag */
virtual void Quit();
/** @brief Returns the quit flag value */
inline bool ShouldQuit() const {
return shouldQuit_;
}
/** @brief Returns the focus flag value */
inline bool HasFocus() const {
return hasFocus_;
}
/** @brief Returns the path for the application to load data from */
inline const String& GetDataPath() const {
return appCfg_.dataPath();
}
/** @brief Switches PS4 and PS5 controllers to use extended protocol which enables rumble and other features */
virtual bool EnablePlayStationExtendedSupport(bool enable);
/** @brief Returns the username of the logged-in user */
virtual String GetUserName();
/** @brief Opens the specified URL in a default web browser */
virtual bool OpenUrl(StringView url);
/** @brief Returns `true` if screen (software) keyboard is supported and @ref ShowScreenKeyboard() should succeed */
virtual bool CanShowScreenKeyboard();
/** @brief Toggles the screen (software) keyboard */
virtual bool ToggleScreenKeyboard();
/** @brief Shows the screen (software) keyboard */
virtual bool ShowScreenKeyboard();
/** @brief Hides the screen (software) keyboard */
virtual bool HideScreenKeyboard();
/** @brief Adds the specified target as a sink for tracing */
void AttachTraceTarget(Containers::StringView targetPath);
protected:
#ifndef DOXYGEN_GENERATING_OUTPUT
AppConfiguration appCfg_;
RenderingSettings renderingSettings_;
bool isSuspended_;
bool autoSuspension_;
bool hasFocus_;
bool shouldQuit_;
#if defined(WITH_IMGUI)
GuiSettings guiSettings_;
IDebugOverlay::DisplaySettings debugOverlayNullSettings_;
#endif
#if defined(NCINE_PROFILING)
float timings_[(std::int32_t)Timings::Count];
#endif
#if defined(DEATH_TARGET_WINDOWS)
HANDLE _waitableTimer;
#endif
TimeStamp profileStartTime_;
std::unique_ptr<FrameTimer> frameTimer_;
std::unique_ptr<IGfxDevice> gfxDevice_;
std::unique_ptr<SceneNode> rootNode_;
std::unique_ptr<ScreenViewport> screenViewport_;
std::unique_ptr<IInputManager> inputManager_;
std::unique_ptr<IAppEventHandler> appEventHandler_;
#if defined(WITH_IMGUI)
std::unique_ptr<IDebugOverlay> debugOverlay_;
std::unique_ptr<ImGuiDrawing> imguiDrawing_;
#endif
#endif
Application();
~Application();
/** @brief Must be called as early as possible during the application startup */
void PreInitCommon(std::unique_ptr<IAppEventHandler> appEventHandler);
/** @brief Must be called before giving control to the application */
void InitCommon();
/** @brief Processes a single step of the game loop and renders a frame */
void Step();
/** @brief Must be called before exiting to shut down the application */
void ShutdownCommon();
/** @brief Called when the application gets suspended */
void Suspend();
/** @brief Called when the application resumes execution */
void Resume();
/** @brief Sets the focus flag */
virtual void SetFocus(bool hasFocus);
#if defined(DEATH_TRACE)
// ITraceSink interface
void OnTraceReceived(TraceLevel level, std::uint64_t timestamp, StringView threadId, StringView functionName, StringView content) override;
void OnTraceFlushed() override;
#endif
private:
Application(const Application&) = delete;
Application& operator=(const Application&) = delete;
friend class MainApplication;
#if defined(DEATH_TARGET_ANDROID)
friend class AndroidApplication;
#endif
#if defined(DEATH_TARGET_EMSCRIPTEN)
friend class IGfxDevice;
#endif
friend class Viewport;
#if defined(DEATH_TRACE)
void InitializeTrace();
void ShutdownTrace();
# if !defined(DEATH_TARGET_EMSCRIPTEN)
void AppendLogFileHeader(IO::Stream& s);
# endif
# if defined(DEATH_TARGET_WINDOWS) && !defined(DEATH_TARGET_WINDOWS_RT)
bool CreateTraceConsole(StringView title, bool& hasVirtualTerminal);
void DestroyTraceConsole();
# endif
#endif
};
extern Application& theApplication();
}
|