MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
PixelStorage.cpp
Go to the documentation of this file.
1#include "PixelStorage.hpp"
2
4
5namespace MayaFlux::Kakshya {
6
7namespace {
8
9 float decode_half(uint16_t h)
10 {
11 const uint32_t sign = static_cast<uint32_t>(h & 0x8000U) << 16;
12 const uint32_t exp = (h >> 10) & 0x1FU;
13 const uint32_t mant = h & 0x3FFU;
14
15 uint32_t bits {};
16
17 if (exp == 0) {
18 if (mant == 0) {
19 bits = sign;
20 } else {
21 uint32_t e = 0;
22 uint32_t m = mant;
23 while ((m & 0x400U) == 0) {
24 m <<= 1;
25 ++e;
26 }
27 m &= 0x3FFU;
28 bits = sign | ((113U - e) << 23) | (m << 13);
29 }
30 } else if (exp == 0x1FU) {
31 bits = sign | 0x7F800000U | (mant << 13);
32 } else {
33 bits = sign | ((exp - 15U + 127U) << 23) | (mant << 13);
34 }
35
36 float out {};
37 std::memcpy(&out, &bits, sizeof(out));
38 return out;
39 }
40
41 uint16_t encode_half(float f)
42 {
43 uint32_t bits {};
44 std::memcpy(&bits, &f, sizeof(bits));
45
46 const auto sign = static_cast<uint16_t>((bits >> 16) & 0x8000U);
47 const int32_t exp = static_cast<int32_t>((bits >> 23) & 0xFFU) - 127 + 15;
48 uint32_t mant = bits & 0x7FFFFFU;
49
50 if (exp >= 0x1F)
51 return static_cast<uint16_t>(sign | 0x7C00U);
52
53 if (exp <= 0) {
54 if (exp < -10)
55 return sign;
56 mant |= 0x800000U;
57 return static_cast<uint16_t>(sign | (mant >> static_cast<uint32_t>(14 - exp)));
58 }
59
60 return static_cast<uint16_t>(
61 sign | (static_cast<uint32_t>(exp) << 10) | (mant >> 13));
62 }
63
64} // namespace
65
67
68size_t storage_element_size(ImageFormat format)
69{
70 switch (format) {
71 case ImageFormat::R8:
72 case ImageFormat::RG8:
73 case ImageFormat::RGB8:
74 case ImageFormat::RGBA8:
75 case ImageFormat::RGBA8_SRGB:
76 case ImageFormat::BGRA8:
77 case ImageFormat::BGRA8_SRGB:
78 case ImageFormat::DEPTH24:
79 case ImageFormat::DEPTH24_STENCIL8:
80 return 1;
81
82 case ImageFormat::R16:
83 case ImageFormat::RG16:
84 case ImageFormat::RGBA16:
85 case ImageFormat::R16F:
86 case ImageFormat::RG16F:
87 case ImageFormat::RGBA16F:
88 case ImageFormat::DEPTH16:
89 return 2;
90
91 case ImageFormat::R32F:
92 case ImageFormat::RG32F:
93 case ImageFormat::RGBA32F:
94 case ImageFormat::DEPTH32F:
95 return 4;
96
97 default:
98 return 1;
99 }
100}
101
102bool is_float_format(ImageFormat format)
103{
104 switch (format) {
105 case ImageFormat::R16F:
106 case ImageFormat::RG16F:
107 case ImageFormat::RGBA16F:
108 case ImageFormat::R32F:
109 case ImageFormat::RG32F:
110 case ImageFormat::RGBA32F:
111 case ImageFormat::DEPTH32F:
112 return true;
113 default:
114 return false;
115 }
116}
117
118DataVariant make_empty_storage(ImageFormat format, size_t element_count)
119{
120 switch (storage_element_size(format)) {
121 case 2:
122 return std::vector<uint16_t>(element_count, 0U);
123 case 4:
124 return std::vector<float>(element_count, 0.0F);
125 default:
126 return std::vector<uint8_t>(element_count, 0U);
127 }
128}
129
131 ImageFormat format,
132 const std::optional<DataDimension::ValueRange>& range,
133 size_t elem_index)
134{
135 return std::visit(
136 [&](const auto& vec) -> double {
137 using T = typename std::decay_t<decltype(vec)>::value_type;
138
139 if constexpr (std::is_same_v<T, uint8_t>
140 || std::is_same_v<T, uint16_t>
141 || std::is_same_v<T, float>) {
142
143 if (elem_index >= vec.size())
144 return 0.0;
145
146 double raw {};
147 double type_max = 1.0;
148
149 if constexpr (std::is_same_v<T, uint8_t>) {
150 raw = static_cast<double>(vec[elem_index]);
151 type_max = 255.0;
152 } else if constexpr (std::is_same_v<T, uint16_t>) {
153 if (is_float_format(format)) {
154 raw = static_cast<double>(decode_half(vec[elem_index]));
155 } else {
156 raw = static_cast<double>(vec[elem_index]);
157 type_max = 65535.0;
158 }
159 } else {
160 raw = static_cast<double>(vec[elem_index]);
161 }
162
163 if (!range)
164 return raw / type_max;
165
166 if (range->invalid && raw == *range->invalid)
167 return std::numeric_limits<double>::quiet_NaN();
168
169 const double span = range->max - range->min;
170 if (span <= 0.0)
171 return 0.0;
172
173 return std::clamp((raw - range->min) / span, 0.0, 1.0);
174 } else {
175 return 0.0;
176 }
177 },
178 v);
179}
180
181double read_normalized_at(const DataVariant& v, ImageFormat format, size_t elem_index)
182{
183 return read_normalized_at(v, format, std::nullopt, elem_index);
184}
185
187 ImageFormat format,
188 const std::optional<DataDimension::ValueRange>& range,
189 size_t elem_index,
190 double value)
191{
192 std::visit(
193 [&](auto& vec) {
194 using T = typename std::decay_t<decltype(vec)>::value_type;
195
196 if constexpr (std::is_same_v<T, uint8_t>
197 || std::is_same_v<T, uint16_t>
198 || std::is_same_v<T, float>) {
199
200 if (elem_index >= vec.size())
201 return;
202
203 double raw {};
204
205 if (range) {
206 if (std::isnan(value)) {
207 if (!range->invalid)
208 return;
209 raw = *range->invalid;
210 } else {
211 raw = range->min
212 + std::clamp(value, 0.0, 1.0) * (range->max - range->min);
213 }
214 } else if constexpr (std::is_same_v<T, uint8_t>) {
215 raw = std::clamp(value * 255.0, 0.0, 255.0);
216 } else if constexpr (std::is_same_v<T, uint16_t>) {
217 raw = is_float_format(format)
218 ? value
219 : std::clamp(value * 65535.0, 0.0, 65535.0);
220 } else {
221 raw = value;
222 }
223
224 if constexpr (std::is_same_v<T, uint8_t>) {
225 vec[elem_index] = static_cast<uint8_t>(std::clamp(raw, 0.0, 255.0));
226 } else if constexpr (std::is_same_v<T, uint16_t>) {
227 if (is_float_format(format)) {
228 vec[elem_index] = encode_half(static_cast<float>(raw));
229 } else {
230 vec[elem_index] = static_cast<uint16_t>(std::clamp(raw, 0.0, 65535.0));
231 }
232 } else {
233 vec[elem_index] = static_cast<float>(raw);
234 }
235 }
236 },
237 v);
238}
239
240void write_normalized_at(DataVariant& v, ImageFormat format,
241 size_t elem_index, double value)
242{
243 write_normalized_at(v, format, std::nullopt, elem_index, value);
244}
245
246bool format_has_variant_storage(ImageFormat format)
247{
248 const uint32_t channels = Portal::Graphics::TextureLoom::get_channel_count(format);
249 return channels > 0
250 && storage_element_size(format) * channels
252}
253
254bool is_depth_format(ImageFormat format)
255{
256 switch (format) {
257 case ImageFormat::DEPTH16:
258 case ImageFormat::DEPTH24:
259 case ImageFormat::DEPTH32F:
260 case ImageFormat::DEPTH24_STENCIL8:
261 return true;
262 default:
263 return false;
264 }
265}
266
267} // namespace MayaFlux::Kakshya
uint32_t h
Definition InkPress.cpp:28
float value
static size_t get_bytes_per_pixel(ImageFormat format)
Get bytes per pixel for a format.
static uint32_t get_channel_count(ImageFormat format)
Get the number of color channels for a given format.
void write_normalized_at(DataVariant &v, ImageFormat format, const std::optional< DataDimension::ValueRange > &range, size_t elem_index, double value)
std::variant< std::vector< double >, std::vector< float >, std::vector< uint8_t >, std::vector< uint16_t >, std::vector< uint32_t >, std::vector< std::complex< float > >, std::vector< std::complex< double > >, std::vector< glm::vec2 >, std::vector< glm::vec3 >, std::vector< glm::vec4 >, std::vector< glm::mat4 > > DataVariant
Multi-type data storage for different precision needs.
Definition NDData.hpp:102
bool is_depth_format(ImageFormat format)
size_t storage_element_size(ImageFormat format)
bool format_has_variant_storage(ImageFormat format)
DataVariant make_empty_storage(ImageFormat format, size_t element_count)
double read_normalized_at(const DataVariant &v, ImageFormat format, const std::optional< DataDimension::ValueRange > &range, size_t elem_index)
bool is_float_format(ImageFormat format)
ImageFormat
User-friendly image format enum.