| 1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
| 2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
| 3 | #pragma once |
| 4 | |
| 5 | #include "Prerequisites/BsPrerequisitesUtil.h" |
| 6 | #include "Utility/BsModule.h" |
| 7 | |
| 8 | namespace bs |
| 9 | { |
| 10 | /** @addtogroup General |
| 11 | * @{ |
| 12 | */ |
| 13 | |
| 14 | /** |
| 15 | * Manages all time related functionality. |
| 16 | * |
| 17 | * @note Sim thread only unless where specified otherwise. |
| 18 | */ |
| 19 | class BS_UTILITY_EXPORT Time : public Module<Time> |
| 20 | { |
| 21 | public: |
| 22 | Time(); |
| 23 | ~Time(); |
| 24 | |
| 25 | /** |
| 26 | * Gets the time elapsed since application start. Only gets updated once per frame. |
| 27 | * |
| 28 | * @return The time since application start, in seconds. |
| 29 | */ |
| 30 | float getTime() const { return mTimeSinceStart; } |
| 31 | |
| 32 | /** |
| 33 | * Gets the time elapsed since application start. Only gets updated once per frame. |
| 34 | * |
| 35 | * @return The time since application start, in miliseconds. |
| 36 | */ |
| 37 | UINT64 getTimeMs() const { return mTimeSinceStartMs; } |
| 38 | |
| 39 | /** |
| 40 | * Gets the time since last frame was executed. Only gets updated once per frame. |
| 41 | * |
| 42 | * @return Time since last frame was executed, in seconds. |
| 43 | */ |
| 44 | float getFrameDelta() const { return mFrameDelta; } |
| 45 | |
| 46 | /** Returns the step (in seconds) between fixed frame updates. */ |
| 47 | float getFixedFrameDelta() const { return (float)(mFixedStep * MICROSEC_TO_SEC); } |
| 48 | |
| 49 | /** Returns the time (in seconds) the latest frame has started. */ |
| 50 | float getLastFrameTime() const { return (float)(mLastFrameTime * MICROSEC_TO_SEC); } |
| 51 | |
| 52 | /** Returns the time (in seconds) the latest fixed update has started. */ |
| 53 | float getLastFixedUpdateTime() const { return (float)(mLastFixedUpdateTime * MICROSEC_TO_SEC); } |
| 54 | |
| 55 | /** |
| 56 | * Returns the sequential index of the current frame. First frame is 0. |
| 57 | * |
| 58 | * @return The current frame. |
| 59 | * |
| 60 | * @note Thread safe, but only counts sim thread frames. |
| 61 | */ |
| 62 | UINT64 getFrameIdx() const { return mCurrentFrame.load(); } |
| 63 | |
| 64 | /** |
| 65 | * Returns the precise time since application start, in microseconds. Unlike other time methods this is not only |
| 66 | * updated every frame, but will return exact time at the moment it is called. |
| 67 | * |
| 68 | * @return Time in microseconds. |
| 69 | * |
| 70 | * @note |
| 71 | * You will generally only want to use this for performance measurements and similar. Use non-precise methods in |
| 72 | * majority of code as it is useful to keep the time value equal in all methods during a single frame. |
| 73 | */ |
| 74 | UINT64 getTimePrecise() const; |
| 75 | |
| 76 | /** |
| 77 | * Gets the time at which the application was started, counting from system start. |
| 78 | * |
| 79 | * @return The time since system to application start, in milliseconds. |
| 80 | */ |
| 81 | UINT64 getStartTimeMs() const { return mAppStartTime; } |
| 82 | |
| 83 | /** |
| 84 | * Gets the current date and time in textual form. |
| 85 | * |
| 86 | * @param[in] isUTC Outputs the date and time in Coordinated Universal Time, otherwise in local time. |
| 87 | * |
| 88 | * @return A String containing the current date and time. |
| 89 | * |
| 90 | * @note |
| 91 | * Thread safe. |
| 92 | * The output format is [DayOfWeek], [Month] [NumericalDate], [NumericalYear] [HH]::[MM]::[SS]. |
| 93 | */ |
| 94 | String getCurrentDateTimeString(bool isUTC); |
| 95 | |
| 96 | /** |
| 97 | * Gets the current time in textual form |
| 98 | * |
| 99 | * @param[in] isUTC Outputs the time in Coordinated Universal Time, otherwise in local time. |
| 100 | * |
| 101 | * @return A String containing the current time. |
| 102 | * |
| 103 | * @note |
| 104 | * Thread safe. |
| 105 | * The output format is [HH]::[MM]::[SS]. |
| 106 | */ |
| 107 | String getCurrentTimeString(bool isUTC); |
| 108 | |
| 109 | /** |
| 110 | * Gets the date and time where the application has been started in textual form. |
| 111 | * |
| 112 | * @param[in] isUTC Outputs the date and time in Coordinated Universal Time, otherwise in local time. |
| 113 | * |
| 114 | * @return A String containing the application startup date and time. |
| 115 | * |
| 116 | * @note |
| 117 | * Thread safe. |
| 118 | * The output format is [DayOfWeek], [Month] [NumericalDate], [NumericalYear] [HH]::[MM]::[SS]. |
| 119 | */ |
| 120 | String getAppStartUpDateString(bool isUTC); |
| 121 | |
| 122 | /** @name Internal |
| 123 | * @{ |
| 124 | */ |
| 125 | |
| 126 | /** Called every frame. Should only be called by Application. */ |
| 127 | void _update(); |
| 128 | |
| 129 | /** |
| 130 | * Calculates the number of fixed update iterations required and their step size. Values depend on the current |
| 131 | * time and previous calls to _advanceFixedUpdate().; |
| 132 | * |
| 133 | * @param[out] step Duration of the fixed step in microseconds. In most cases this is the same duration as |
| 134 | * the fixed time delta, but in the cases where frame is taking a very long time the step |
| 135 | * might be increased to avoid a large number of fixed updates per frame. |
| 136 | * @return Returns the number of fixed frame updates to execute (each of @p step duration). In most |
| 137 | * cases this will be either 1 or 0, or a larger amount of frames are taking a long time |
| 138 | * to execute (longer than a multiple of fixed frame step). |
| 139 | */ |
| 140 | UINT32 _getFixedUpdateStep(UINT64& step); |
| 141 | |
| 142 | /** |
| 143 | * Advances the fixed update timers by @p step microseconds. Should be called once for each iteration as returned |
| 144 | * by _getFixedUpdateStep(), per frame. |
| 145 | */ |
| 146 | void _advanceFixedUpdate(UINT64 step); |
| 147 | |
| 148 | /** @} */ |
| 149 | |
| 150 | /** Multiply with time in microseconds to get a time in seconds. */ |
| 151 | static const double MICROSEC_TO_SEC; |
| 152 | private: |
| 153 | /** Maximum number of fixed updates that can ever be accumulated. */ |
| 154 | static constexpr UINT32 MAX_ACCUM_FIXED_UPDATES = 200; |
| 155 | |
| 156 | /** Determines how many new fixed updates are regenerated per frame. */ |
| 157 | static constexpr UINT32 NEW_FIXED_UPDATES_PER_FRAME = 4; |
| 158 | |
| 159 | float mFrameDelta = 0.0f; /**< Frame delta in seconds */ |
| 160 | float mTimeSinceStart = 0.0f; /**< Time since start in seconds */ |
| 161 | UINT64 mTimeSinceStartMs = 0u; |
| 162 | bool mFirstFrame = true; |
| 163 | |
| 164 | UINT64 mAppStartTime = 0u; /**< Time the application started, in microseconds */ |
| 165 | UINT64 mLastFrameTime = 0u; /**< Time since last runOneFrame call, In microseconds */ |
| 166 | std::atomic<unsigned long> mCurrentFrame{0UL}; |
| 167 | |
| 168 | // Fixed update |
| 169 | UINT64 mFixedStep = 16666; // 60 times a second in microseconds |
| 170 | UINT64 mLastFixedUpdateTime = 0; |
| 171 | bool mFirstFixedFrame = true; |
| 172 | UINT32 mNumRemainingFixedUpdates = MAX_ACCUM_FIXED_UPDATES; |
| 173 | |
| 174 | std::time_t mAppStartUpDate; |
| 175 | |
| 176 | Timer* mTimer; |
| 177 | }; |
| 178 | |
| 179 | /** Easier way to access the Time module. */ |
| 180 | BS_UTILITY_EXPORT Time& gTime(); |
| 181 | |
| 182 | /** @} */ |
| 183 | } |
| 184 | |