Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
FrameRate.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "HAL/Platform.h"
6#include "Internationalization/Text.h"
7#include "Math/NumericLimits.h"
8#include "Math/Range.h"
9#include "Math/RangeBound.h"
10#include "Math/UnrealMathUtility.h"
11#include "Misc/ExpressionParserTypes.h"
12#include "Misc/FrameNumber.h"
13#include "Misc/FrameTime.h"
14#include "Templates/ValueOrError.h"
15
16struct FExpressionError;
17
18/**
19 * A frame rate represented as a fraction comprising 2 integers: a numerator (number of frames), and a denominator (per second)
20 */
22{
23 /**
24 * Default construction to a frame rate of 60000 frames per second (0.0166 ms)
25 */
27 : Numerator(60000), Denominator(1)
28 {}
29
30 FFrameRate(uint32 InNumerator, uint32 InDenominator)
31 : Numerator(InNumerator), Denominator(InDenominator)
32 {}
33
34 /**
35 * The numerator of the framerate represented as a number of frames per second (e.g. 60 for 60 fps)
36 */
37 int32 Numerator;
38
39 /**
40 * The denominator of the framerate represented as a number of frames per second (e.g. 1 for 60 fps)
41 */
43
44 /**
45 * Verify that this frame rate is valid to use
46 */
47 bool IsValid() const
48 {
49 return Denominator > 0;
50 }
51
52 /**
53 * Get the decimal representation of this framerate's interval
54 *
55 * @return The time in seconds for a single frame under this frame rate
56 */
57 double AsInterval() const;
58
59 /**
60 * Get the decimal representation of this framerate
61 *
62 * @return The number of frames per second
63 */
64 double AsDecimal() const;
65
66 /**
67 * Convert the specified frame number to a floating-point number of seconds based on this framerate
68 *
69 * @param FrameNumber The frame number to convert
70 * @return The number of seconds that the specified frame number represents
71 */
72 double AsSeconds(FFrameTime FrameNumber) const;
73
74 /**
75 * Convert the specified time in seconds to a frame number by rounding down to the nearest integer.
76 *
77 * @param InTimeSeconds The time to convert in seconds
78 * @return A frame number that represents the supplied time. Rounded down to the nearest integer.
79 */
80 FFrameTime AsFrameTime(double InTimeSeconds) const;
81
82 /**
83 * Convert the specified time in seconds to a frame number by rounding down to the nearest integer.
84 *
85 * @param InTimeSeconds The time to convert in seconds
86 * @return A frame number that represents the supplied time. Rounded down to the nearest integer.
87 */
88 FFrameNumber AsFrameNumber(double InTimeSeconds) const;
89
90 /**
91 * Check whether this frame rate is a multiple of another
92 */
93 bool IsMultipleOf(FFrameRate Other) const;
94
95 /**
96 * Check whether this frame rate is a factor of another
97 */
98 bool IsFactorOf(FFrameRate Other) const;
99
100 /**
101 * Convert the specified time from one framerate to another framerate
102 *
103 * @param SourceTime The frame number to convert
104 * @param SourceRate The source frame rate
105 * @param DestinationRate The destination frame rate
106 * @return A frame time in the destination frame rate
107 */
108 static FFrameTime TransformTime(FFrameTime SourceTime, FFrameRate SourceRate, FFrameRate DestinationRate);
109
110 /**
111 * Snap a time specified in one framerate, to another
112 *
113 * @param SourceTime The frame number to convert
114 * @param SourceRate The source frame rate
115 * @param SnapToRate The destination frame rate
116 * @return A frame time in the destination frame rate
117 */
118 static FFrameTime Snap(FFrameTime SourceTime, FFrameRate SourceRate, FFrameRate SnapToRate);
119
120 /**
121 * Convert this frame rate to a prettified text string.
122 * @note: Does not check against decorated frame rate names in FCommonFrameRates
123 */
125
126 /**
127 * Compute a desirable grid spacing for the specified screen units
128 *
129 * @param PixelsPerSecond The number of pixels representing a second of time
130 * @param OutMajorInterval (Out) The interval in seconds at which to draw major grid lines
131 * @param OutMinorDivisions (Out) The number of divisions to draw between major tick lines
132 * @param MinTickPx (Optional) The smallest size in pixels that is desirable between ticks
133 * @param DesiredMajorTickPx (Optional) The desired size to compute major tick lines from
134 * @return True if a valid grid spacing was computed, false otherwise.
135 */
136 bool ComputeGridSpacing(const float PixelsPerSecond, double& OutMajorInterval, int32& OutMinorDivisions, float MinTickPx = 30.f, float DesiredMajorTickPx = 120.f) const;
137
138 /**
139 * Get the maximum number of seconds representable with this framerate
140 */
141 double MaxSeconds() const;
142
143 /**
144 * Get the reciprocal of this frame rate
145 */
147 {
149 }
150
151 friend inline bool operator==(const FFrameRate& A, const FFrameRate& B)
152 {
154 }
155
156 friend inline bool operator!=(const FFrameRate& A, const FFrameRate& B)
157 {
159 }
160
162 {
164 }
165
167 {
169 }
170
171 friend inline double operator/(FFrameNumber Frame, FFrameRate Rate)
172 {
173 return Rate.AsSeconds(FFrameTime(Frame));
174 }
175
176 friend inline TRange<double> operator/(const TRange<FFrameNumber>& FrameRange, FFrameRate Rate)
177 {
178 TRangeBound<FFrameNumber> LowerBound = FrameRange.GetLowerBound();
179 TRangeBound<FFrameNumber> UpperBound = FrameRange.GetUpperBound();
180
181 return TRange<double>(
182 LowerBound.IsOpen()
183 ? TRangeBound<double>::Open()
184 : LowerBound.IsInclusive()
185 ? TRangeBound<double>::Inclusive(Rate.AsSeconds(LowerBound.GetValue()))
186 : TRangeBound<double>::Inclusive(Rate.AsSeconds(LowerBound.GetValue()+1)),
187
188 UpperBound.IsOpen()
189 ? TRangeBound<double>::Open()
190 : UpperBound.IsInclusive()
191 ? TRangeBound<double>::Exclusive(Rate.AsSeconds(UpperBound.GetValue()+1))
192 : TRangeBound<double>::Exclusive(Rate.AsSeconds(UpperBound.GetValue()))
193 );
194 }
195
196 friend inline double operator/(FFrameTime FrameTime, FFrameRate Rate)
197 {
198 return Rate.AsSeconds(FrameTime);
199 }
200
201 friend inline FFrameTime operator*(double TimeInSeconds, FFrameRate Rate)
202 {
203 return Rate.AsFrameTime(TimeInSeconds);
204 }
205
206 friend inline FFrameTime operator*(float TimeInSeconds, FFrameRate Rate)
207 {
208 return Rate.AsFrameTime(TimeInSeconds);
209 }
210
211 friend FArchive& operator<<(FArchive& Ar, FFrameRate& FrameRate);
212
214};
215
216inline double FFrameRate::AsInterval() const
217{
218 return double(Denominator) / double(Numerator);
219}
220
221inline double FFrameRate::AsDecimal() const
222{
223 return double(Numerator) / double(Denominator);
224}
225
226inline double FFrameRate::AsSeconds(FFrameTime FrameTime) const
227{
228 const int64 IntegerPart = FrameTime.GetFrame().Value * int64(Denominator);
229 const double FloatPart = FrameTime.GetSubFrame() * double(Denominator);
230
231 return (double(IntegerPart) + FloatPart) / Numerator;
232}
233
234inline FFrameTime FFrameRate::AsFrameTime(double TimeInSeconds) const
235{
236 // @todo: sequencer-timecode: proper large number integer multiplication/division before coercion to float ?
237 const double TimeAsFrame = (TimeInSeconds * Numerator) / Denominator;
238 FFrameNumber FrameNumber = static_cast<int32>(FMath::Clamp(FMath::FloorToDouble(TimeAsFrame), static_cast<double>(TNumericLimits<int32>::Min()), static_cast<double>(TNumericLimits<int32>::Max())));
239
240 float SubFrame = static_cast<float>(TimeAsFrame - FMath::FloorToDouble(TimeAsFrame));
241 const int32 TruncatedSubFrame = FMath::TruncToInt(SubFrame);
242 SubFrame -= static_cast<float>(TruncatedSubFrame);
243 FrameNumber.Value += TruncatedSubFrame;
244 if (SubFrame > 0.f)
245 {
246 SubFrame = FMath::Min(SubFrame, FFrameTime::MaxSubframe);
247 }
248
249 return FFrameTime(FrameNumber, SubFrame);
250}
251
252inline FFrameNumber FFrameRate::AsFrameNumber(double TimeInSeconds) const
253{
254 // @todo: sequencer-timecode: proper large number integer multiplication/division before coercion to float ?
255 const double TimeAsFrame = (static_cast<double>(TimeInSeconds) * Numerator) / Denominator;
256 return static_cast<int32>(FMath::Clamp(FMath::FloorToDouble(TimeAsFrame + static_cast<double>(FMath::TruncToInt(static_cast<float>(TimeAsFrame - FMath::FloorToDouble(TimeAsFrame))))), static_cast<double>(TNumericLimits<int32>::Min()), static_cast<double>(TNumericLimits<int32>::Max())));
257}
258
259inline FFrameTime ConvertFrameTime(FFrameTime SourceTime, FFrameRate SourceRate, FFrameRate DestinationRate)
260{
261 if (SourceRate == DestinationRate)
262 {
263 return SourceTime;
264 }
265 //We want NewTime =SourceTime * (DestinationRate/SourceRate);
266 //And want to limit conversions and keep int precision as much as possible
267
268 //@todo: These integers should not need the volatile keyword here, but adding it works around
269 // a compiler bug that results in an uninitialized vector register being used
270 volatile int64 NewNumerator = static_cast<int64>(DestinationRate.Numerator) * SourceRate.Denominator;
271 volatile int64 NewDenominator = static_cast<int64>(DestinationRate.Denominator) * SourceRate.Numerator;
272
273 double NewNumerator_d = double(NewNumerator);
274 double NewDenominator_d = double(NewDenominator);
275 //Now the IntegerPart may have a Float Part, and then the FloatPart may have an IntegerPart,
276 //So we add the extra Float from the IntegerPart to the FloatPart and then add back any extra Integer to IntegerPart
277 int64 IntegerPart = ( (int64)(SourceTime.GetFrame().Value) * NewNumerator ) / NewDenominator;
278 const double IntegerFloatPart = ((double(SourceTime.GetFrame().Value) * double(NewNumerator)) / double(NewDenominator)) - double(IntegerPart);
279 const double FloatPart = ((SourceTime.GetSubFrame() * NewNumerator_d) / NewDenominator_d) + IntegerFloatPart;
280 const double FloatPartFloored = FMath::FloorToDouble(FloatPart);
281 const int64 FloatAsInt = int64(FloatPartFloored);
282 IntegerPart += FloatAsInt;
283 float SubFrame = static_cast<float>(FloatPart - FloatPartFloored);
284 if (SubFrame > 0.f)
285 {
286 SubFrame = FMath::Min(SubFrame, FFrameTime::MaxSubframe);
287 }
288
289 IntegerPart = FMath::Clamp<int64>(IntegerPart,TNumericLimits<int32>::Min(),TNumericLimits<int32>::Max());
290 return FFrameTime(static_cast<int32>(IntegerPart), SubFrame);
291}
292
293inline FFrameTime FFrameRate::TransformTime(FFrameTime SourceTime, FFrameRate SourceRate, FFrameRate DestinationRate)
294{
295 return ConvertFrameTime(SourceTime, SourceRate, DestinationRate);
296}
297
298inline FFrameTime FFrameRate::Snap(FFrameTime SourceTime, FFrameRate SourceRate, FFrameRate SnapToRate)
299{
300 return ConvertFrameTime(ConvertFrameTime(SourceTime, SourceRate, SnapToRate).RoundToFrame(), SnapToRate, SourceRate);
301}
302
303inline bool FFrameRate::IsMultipleOf(FFrameRate Other) const
304{
305 int64 CommonValueA = int64(Numerator) * Other.Denominator;
306 int64 CommonValueB = int64(Other.Numerator) * Denominator;
307
308 return CommonValueA <= CommonValueB && CommonValueB % CommonValueA == 0;
309}
310
311inline bool FFrameRate::IsFactorOf(FFrameRate Other) const
312{
313 return Other.IsMultipleOf(*this);
314}
315
316/**
317 * Attempt to parse a frame rate from a string
318 */
319TValueOrError<FFrameRate, FExpressionError> ParseFrameRate(const TCHAR* FrameRateString);
320
321/**
322 * Common Lex::TryParseString overload for FFrameRate
323 */
324bool TryParseString(FFrameRate& OutFrameRate, const TCHAR* InString);
FFrameTime ConvertFrameTime(FFrameTime SourceTime, FFrameRate SourceRate, FFrameRate DestinationRate)
Definition FrameRate.h:259
TValueOrError< FFrameRate, FExpressionError > ParseFrameRate(const TCHAR *FrameRateString)
bool TryParseString(FFrameRate &OutFrameRate, const TCHAR *InString)
Definition Text.h:357
friend FFrameTime operator*(float TimeInSeconds, FFrameRate Rate)
Definition FrameRate.h:206
double AsDecimal() const
Definition FrameRate.h:221
FFrameNumber AsFrameNumber(double InTimeSeconds) const
Definition FrameRate.h:252
static FFrameTime Snap(FFrameTime SourceTime, FFrameRate SourceRate, FFrameRate SnapToRate)
Definition FrameRate.h:298
int32 Denominator
Definition FrameRate.h:42
friend double operator/(FFrameNumber Frame, FFrameRate Rate)
Definition FrameRate.h:171
bool ComputeGridSpacing(const float PixelsPerSecond, double &OutMajorInterval, int32 &OutMinorDivisions, float MinTickPx=30.f, float DesiredMajorTickPx=120.f) const
static FFrameTime TransformTime(FFrameTime SourceTime, FFrameRate SourceRate, FFrameRate DestinationRate)
Definition FrameRate.h:293
double AsSeconds(FFrameTime FrameNumber) const
Definition FrameRate.h:226
friend FFrameRate operator/(FFrameRate A, FFrameRate B)
Definition FrameRate.h:166
friend bool operator!=(const FFrameRate &A, const FFrameRate &B)
Definition FrameRate.h:156
FText ToPrettyText() const
double MaxSeconds() const
friend bool operator==(const FFrameRate &A, const FFrameRate &B)
Definition FrameRate.h:151
friend double operator/(FFrameTime FrameTime, FFrameRate Rate)
Definition FrameRate.h:196
bool IsValid() const
Definition FrameRate.h:47
int32 Numerator
Definition FrameRate.h:37
friend FFrameTime operator*(double TimeInSeconds, FFrameRate Rate)
Definition FrameRate.h:201
double AsInterval() const
Definition FrameRate.h:216
friend FFrameRate operator*(FFrameRate A, FFrameRate B)
Definition FrameRate.h:161
friend TRange< double > operator/(const TRange< FFrameNumber > &FrameRange, FFrameRate Rate)
Definition FrameRate.h:176
FFrameRate(uint32 InNumerator, uint32 InDenominator)
Definition FrameRate.h:30
bool Serialize(FArchive &Ar)
bool IsMultipleOf(FFrameRate Other) const
Definition FrameRate.h:303
FFrameTime AsFrameTime(double InTimeSeconds) const
Definition FrameRate.h:234
bool IsFactorOf(FFrameRate Other) const
Definition FrameRate.h:311
FFrameRate Reciprocal() const
Definition FrameRate.h:146
FFrameTime(FFrameNumber InFrameNumber, float InSubFrame)
Definition FrameTime.h:241
FFrameNumber RoundToFrame() const
Definition FrameTime.h:270
FORCEINLINE FFrameNumber GetFrame() const
Definition FrameTime.h:51
FORCEINLINE float GetSubFrame() const
Definition FrameTime.h:59
FFrameTime(FFrameNumber InFrameNumber)
Definition FrameTime.h:236
static constexpr NumericType Min()
static constexpr NumericType Max()