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 | |