Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
PackedVector.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreTypes.h"
6#include "Math/NumericLimits.h"
7#include "Math/UnrealMathUtility.h"
8#include "Math/Color.h"
9#include "Templates/TypeCompatibleBytes.h"
10
11/**
12 * 3 component vector corresponding to DXGI_FORMAT_R11G11B10_FLOAT.
13 * Conversion code from XMFLOAT3PK in DirectXPackedVector.h
14 */
16{
17public:
18 union
19 {
20 struct
21 {
22 uint32_t xm : 6; // x-mantissa
23 uint32_t xe : 5; // x-exponent
24 uint32_t ym : 6; // y-mantissa
25 uint32_t ye : 5; // y-exponent
26 uint32_t zm : 5; // z-mantissa
27 uint32_t ze : 5; // z-exponent
28 };
29 uint32_t v;
30 };
31
33
34 explicit FFloat3Packed(const FLinearColor& Src);
35
37};
38
39
41{
42 uint32 IValue[4];
43 IValue[0] = *(uint32*)&Src.R;
44 IValue[1] = *(uint32*)&Src.G;
45 IValue[2] = *(uint32*)&Src.B;
46 IValue[3] = *(uint32*)&Src.A;
47
48 uint32 Result[3];
49
50 // X & Y Channels (5-bit exponent, 6-bit mantissa)
51 for (uint32 j=0; j < 2; ++j)
52 {
53 uint32 Sign = IValue[j] & 0x80000000;
54 uint32 I = IValue[j] & 0x7FFFFFFF;
55
56 if ((I & 0x7F800000) == 0x7F800000)
57 {
58 // INF or NAN
59 Result[j] = 0x7c0;
60 if (( I & 0x7FFFFF ) != 0)
61 {
62 Result[j] = 0x7c0 | (((I>>17)|(I>>11)|(I>>6)|(I))&0x3f);
63 }
64 else if ( Sign )
65 {
66 // -INF is clamped to 0 since 3PK is positive only
67 Result[j] = 0;
68 }
69 }
70 else if ( Sign )
71 {
72 // 3PK is positive only, so clamp to zero
73 Result[j] = 0;
74 }
75 else if (I > 0x477E0000U)
76 {
77 // The number is too large to be represented as a float11, set to max
78 Result[j] = 0x7BF;
79 }
80 else
81 {
82 if (I < 0x38800000U)
83 {
84 // The number is too small to be represented as a normalized float11
85 // Convert it to a denormalized value.
86 uint32 Shift = 113U - (I >> 23U);
87 I = (0x800000U | (I & 0x7FFFFFU)) >> Shift;
88 }
89 else
90 {
91 // Rebias the exponent to represent the value as a normalized float11
92 I += 0xC8000000U;
93 }
94
95 Result[j] = ((I + 0xFFFFU + ((I >> 17U) & 1U)) >> 17U)&0x7ffU;
96 }
97 }
98
99 // Z Channel (5-bit exponent, 5-bit mantissa)
100 uint32 Sign = IValue[2] & 0x80000000;
101 uint32 I = IValue[2] & 0x7FFFFFFF;
102
103 if ((I & 0x7F800000) == 0x7F800000)
104 {
105 // INF or NAN
106 Result[2] = 0x3e0;
107 if ( I & 0x7FFFFF )
108 {
109 Result[2] = 0x3e0 | (((I>>18)|(I>>13)|(I>>3)|(I))&0x1f);
110 }
111 else if ( Sign )
112 {
113 // -INF is clamped to 0 since 3PK is positive only
114 Result[2] = 0;
115 }
116 }
117 else if ( Sign )
118 {
119 // 3PK is positive only, so clamp to zero
120 Result[2] = 0;
121 }
122 else if (I > 0x477C0000U)
123 {
124 // The number is too large to be represented as a float10, set to max
125 Result[2] = 0x3df;
126 }
127 else
128 {
129 if (I < 0x38800000U)
130 {
131 // The number is too small to be represented as a normalized float10
132 // Convert it to a denormalized value.
133 uint32 Shift = 113U - (I >> 23U);
134 I = (0x800000U | (I & 0x7FFFFFU)) >> Shift;
135 }
136 else
137 {
138 // Rebias the exponent to represent the value as a normalized float10
139 I += 0xC8000000U;
140 }
141
142 Result[2] = ((I + 0x1FFFFU + ((I >> 18U) & 1U)) >> 18U)&0x3ffU;
143 }
144
145 // Pack Result into memory
146 v = (Result[0] & 0x7ff)
147 | ( (Result[1] & 0x7ff) << 11 )
148 | ( (Result[2] & 0x3ff) << 22 );
149}
150
152{
153 uint32 Result[4];
154 uint32 Mantissa;
155 uint32 Exponent;
156
157 const FFloat3Packed* pSource = this;
158
159 // X Channel (6-bit mantissa)
160 Mantissa = pSource->xm;
161
162 if ( pSource->xe == 0x1f ) // INF or NAN
163 {
164 Result[0] = 0x7f800000 | (pSource->xm << 17);
165 }
166 else
167 {
168 if ( pSource->xe != 0 ) // The value is normalized
169 {
170 Exponent = pSource->xe;
171 }
172 else if (Mantissa != 0) // The value is denormalized
173 {
174 // Normalize the value in the resulting float
175 Exponent = 1;
176
177 do
178 {
179 Exponent--;
180 Mantissa <<= 1;
181 } while ((Mantissa & 0x40) == 0);
182
183 Mantissa &= 0x3F;
184 }
185 else // The value is zero
186 {
187 Exponent = (uint32)-112;
188 }
189
190 Result[0] = ((Exponent + 112) << 23) | (Mantissa << 17);
191 }
192
193 // Y Channel (6-bit mantissa)
194 Mantissa = pSource->ym;
195
196 if ( pSource->ye == 0x1f ) // INF or NAN
197 {
198 Result[1] = 0x7f800000 | (pSource->ym << 17);
199 }
200 else
201 {
202 if ( pSource->ye != 0 ) // The value is normalized
203 {
204 Exponent = pSource->ye;
205 }
206 else if (Mantissa != 0) // The value is denormalized
207 {
208 // Normalize the value in the resulting float
209 Exponent = 1;
210
211 do
212 {
213 Exponent--;
214 Mantissa <<= 1;
215 } while ((Mantissa & 0x40) == 0);
216
217 Mantissa &= 0x3F;
218 }
219 else // The value is zero
220 {
221 Exponent = (uint32)-112;
222 }
223
224 Result[1] = ((Exponent + 112) << 23) | (Mantissa << 17);
225 }
226
227 // Z Channel (5-bit mantissa)
228 Mantissa = pSource->zm;
229
230 if ( pSource->ze == 0x1f ) // INF or NAN
231 {
232 Result[2] = 0x7f800000 | (pSource->zm << 17);
233 }
234 else
235 {
236 if ( pSource->ze != 0 ) // The value is normalized
237 {
238 Exponent = pSource->ze;
239 }
240 else if (Mantissa != 0) // The value is denormalized
241 {
242 // Normalize the value in the resulting float
243 Exponent = 1;
244
245 do
246 {
247 Exponent--;
248 Mantissa <<= 1;
249 } while ((Mantissa & 0x20) == 0);
250
251 Mantissa &= 0x1F;
252 }
253 else // The value is zero
254 {
255 Exponent = (uint32)-112;
256 }
257
258 Result[2] = ((Exponent + 112) << 23) | (Mantissa << 18);
259 }
260
261 FLinearColor ResultColor;
262 ResultColor.R = *(float*)&Result[0];
263 ResultColor.G = *(float*)&Result[1];
264 ResultColor.B = *(float*)&Result[2];
265 ResultColor.A = 0;
266 return ResultColor;
267}
268
269/**
270 * 4 component vector corresponding to PF_R8G8B8A8_SNORM.
271 * This differs from FColor which is BGRA.
272 */
274{
275public:
276 union
277 {
278 struct
279 {
280 int8 R;
281 int8 G;
282 int8 B;
283 int8 A;
284 };
285 uint32 Packed;
286 };
287
289
290 explicit FFixedRGBASigned8(const FLinearColor& Src);
291
293};
294
296{
297 const float Scale = MAX_int8;
298 R = (int8)FMath::Clamp<int32>(FMath::RoundToInt(Src.R * Scale), MIN_int8, MAX_int8);
299 G = (int8)FMath::Clamp<int32>(FMath::RoundToInt(Src.G * Scale), MIN_int8, MAX_int8);
300 B = (int8)FMath::Clamp<int32>(FMath::RoundToInt(Src.B * Scale), MIN_int8, MAX_int8);
301 A = (int8)FMath::Clamp<int32>(FMath::RoundToInt(Src.A * Scale), MIN_int8, MAX_int8);
302}
303
305{
306 const float Scale = 1.0f / MAX_int8;
307 return FLinearColor(R * Scale, G * Scale, B * Scale, A * Scale);
308}
309
310/**
311 * 3 component vector corresponding to PF_R9G9B9EXP5.
312 */
314{
315public:
316
317 union
318 {
319 struct
320 {
321 uint32 RMantissa : 9;
322 uint32 GMantissa : 9;
323 uint32 BMantissa : 9;
324 uint32 SharedExponent : 5;
325 };
327 };
328
330
331 explicit FFloat3PackedSE(const FLinearColor& Src);
332 explicit FFloat3PackedSE(uint32 InEncodedValue) : EncodedValue(InEncodedValue) {}
333
335};
336
338{
339
340 //s=sign, e = exponent, m = mantissa
341 //32 bit floating point:
342 // s:e:m 1:8:23
343 // if e > 0 float = (-1)^sign X 2^(e-127) X (1.0 + m)
344 // if e == 0 && m!= 0 float = (-1)^sign X 2^(-126) X (0.0 + m) (subnormal)
345 // if e == 0xff && m==0 float = (-1)^sign X infinity
346 // if e == 0xff && m!=0 NaN
347 //
348 struct PackedFloat
349 {
350 union
351 {
352 struct
353 {
354 uint32_t m : 23;
355 uint32_t e : 8;
356 uint32_t s : 1;
357 };
358 float v;
359 };
360 bool IsSubnormal() { return (e == 0 && m != 0 ); }
361 uint32 Mantissa() { return m + (IsSubnormal() ? 0 : (1 << 23) ); }
362 int32 Exponent() { return e - 127; }
363 bool IsInfinity() { return (e == 0xff) && (m == 0); }
364 bool IsNaN() { return (e == 0xff) && (m != 0); }
365 };
366
367 PackedFloat RGBPacked[3];
368 RGBPacked[0] = BitCast<PackedFloat, float>(Src.R);
369 RGBPacked[1] = BitCast<PackedFloat, float>(Src.G);
370 RGBPacked[2] = BitCast<PackedFloat, float>(Src.B);
371
372 uint32 Mantissas[3];
373 int32 Exponents[3];
374
375 for (uint32 i = 0; i < 3; ++i)
376 {
377 Mantissas[i] = RGBPacked[i].Mantissa();
378 Exponents[i] = RGBPacked[i].Exponent();
379
380 // 9995 uses (0.0 + m) instead of floating point's (1.0 + m) , so let's fix that here.
381 if (!RGBPacked[i].IsSubnormal()) //don't need to fix subnormal (it is already 0.m based)
382 {
383 // example 2^2 X 1.5 ---> 2^3 X 0.75. Exponent++, and mantissa/=2
384 Exponents[i]++;
385 Mantissas[i] /= 2;
386 }
387 if ( (Exponents[i] < -15 && RGBPacked[i].v != 0.0f) || (RGBPacked[i].v < 0.0f) || RGBPacked[i].IsNaN()) //underflow or negative or NaN
388 {
389 //As per DirectX implementation, underflow or negative or NaN clamp to a lowest possible exponent and mantissa
390 Exponents[i] = -15;
391 Mantissas[i] = 0;
392 }
393 else if (Exponents[i] > 15) //overflow or infinity
394 {
395 Exponents[i] = 16; //Match behavior of XMStoreFloat3SE
396 Mantissas[i] = 0x7fffff; //as close to 1 as possible
397 }
398 }
399
400 //exponent now guaranteed to be from -15 to +15
401 int32 NewExponent = FMath::Max<int32>(Exponents[0], FMath::Max<int32>(Exponents[1], Exponents[2]));
402
403 for (uint32 i = 0; i < 3; ++i)
404 {
405 Mantissas[i] = (Mantissas[i] >> ((uint32)(NewExponent - Exponents[i]))); // this can conceivably go to zero if the diff between max and min Exponents > 8 !
406 //Mantissa is still 23 bits Need to make it 9 bit
407 Mantissas[i] = Mantissas[i] >> (23 - 9); // now 9 bit
408 }
409
410 check( Mantissas[0] < (1 << 23) && Mantissas[1] < (1 << 23) && Mantissas[2] < (1 << 23) );
411
412 EncodedValue = (((NewExponent + 15) & 0x01f) << (9 + 9 + 9)) |
413 ((Mantissas[2] & 0x1ff) << (0 + 9 + 9)) |
414 ((Mantissas[1] & 0x1ff) << (0 + 0 + 9)) |
415 ((Mantissas[0] & 0x1ff) << (0 + 0 + 0)) ;
416
417}
418
420{
421 int32 SharedExponent8Bits = 0x33800000 + (SharedExponent << 23);
422 float Scale = BitCast<float, int32>(SharedExponent8Bits);
423
424 return FLinearColor( Scale * float(RMantissa), Scale * float(GMantissa), Scale * float(BMantissa),1.0f );
425}
#define check(expr)
#define MIN_int8
#define MAX_int8
#define FORCEINLINE
Definition Platform.h:644
FFixedRGBASigned8(const FLinearColor &Src)
FLinearColor ToLinearColor() const
FFloat3Packed(const FLinearColor &Src)
FLinearColor ToLinearColor() const
FFloat3PackedSE(uint32 InEncodedValue)
FFloat3PackedSE(const FLinearColor &Src)
FLinearColor ToLinearColor() const
constexpr FORCEINLINE FLinearColor(float InR, float InG, float InB, float InA=1.0f)
Definition Color.h:128