Gamp v0.0.7-54-gccdc599
Gamp: Graphics, Audio, Multimedia and Processing
Loading...
Searching...
No Matches
PixelFormat.hpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright Gothel Software e.K.
4 *
5 * SPDX-License-Identifier: MIT
6 *
7 * This Source Code Form is subject to the terms of the MIT License
8 * If a copy of the MIT was not distributed with this file,
9 * you can obtain one at https://opensource.org/license/mit/.
10 */
11#ifndef GAMP_RENDER_PIXEL_PIXELFORMAT_HPP_
12#define GAMP_RENDER_PIXEL_PIXELFORMAT_HPP_
13
14#include <bit>
15#include <cstdint>
16#include <cstdlib>
17#include <cstring>
18#include <string_view>
19#include <vector>
20
21#include <jau/basic_types.hpp>
22#include <jau/cpp_lang_util.hpp>
23#include <jau/debug.hpp>
24#include <jau/float_math.hpp>
25#include <jau/int_math.hpp>
26#include <jau/int_types.hpp>
27#include <jau/math/recti.hpp>
28#include <jau/math/vec2i.hpp>
30#include <jau/string_util.hpp>
31#include <jau/enum_util.hpp>
32
33#include <gamp/GampTypes.hpp>
36
38 /** @defgroup Gamp_Pixel Gamp Pixel
39 * Pixel definition and conversion.
40 *
41 * @{
42 */
43
45
46 class PixelFormats; // fwd
47
48 /**
49 * Packed pixel composition, i.e. layout of its components.
50 *
51 * Components are interleaved, i.e. packed.
52 */
53 class PixelFormat {
54 private:
55 friend class PixelFormats;
56
57 jau::nsize_t m_compCount;
58 comparray4_t m_compOrder;
59 u32array4_t m_compMask;
60 u32array4_t m_compBitCount;
61 u32array4_t m_compBitShift;
62 uint32_t m_bitsPerPixel;
63 uint32_t m_bitStride;
64 bool m_uniform;
65 size_t m_hashCode;
66
67 constexpr size_t hashCodeImpl() const noexcept {
68 // 31 * x == (x << 5) - x
69 size_t hash = 31 + m_bitStride;
70 hash = ((hash << 5) - hash) + m_bitsPerPixel;
71 hash = ((hash << 5) - hash) + m_compMask.size();
72 for(size_t i=m_compOrder.size(); i-->0; ) {
73 hash = ((hash << 5) - hash) + number(m_compOrder[i]);
74 }
75 for(size_t i=m_compMask.size(); i-->0; ) {
76 hash = ((hash << 5) - hash) + m_compMask[i];
77 }
78 for(size_t i=m_compOrder.size(); i-->0; ) {
79 hash = ((hash << 5) - hash) + m_compBitShift[i];
80 }
81 return hash;
82 }
83
84 static std::string toHexString(const u32array4_t& bitCount, const u32array4_t& mask, const u32array4_t& shift) {
85 std::string sb("[");
86 size_t l = mask.size();
87 for(size_t i=0; i < l; ++i) {
88 if(i > 0) {
89 sb.append(", ");
90 }
91 sb.append(std::to_string(bitCount[i])).append(": 0x")
92 .append(jau::to_hexstring(mask[i])).append(" << ").append(std::to_string(shift[i]));
93 }
94 return sb.append("]");
95 }
96
97 /**
98 * @param componentOrder CType component type order of all components, see componentBitMask().
99 * @param bpc bits per component
100 * @param bitStride stride bits to next pixel
101 */
102 consteval_cxx20 PixelFormat(jau::nsize_t compCount, const comparray4_t& compOrder,
103 uint32_t bpc, uint32_t bitStride) noexcept
104 : m_compCount(compCount), m_compOrder(compOrder), m_compMask(), m_compBitCount(), m_compBitShift(),
105 m_bitsPerPixel(bpc * compCount), m_bitStride(bitStride),
106 m_uniform(true), m_hashCode(0)
107 {
108 const uint32_t compMask = ( 1 << bpc ) - 1;
109 for(jau::nsize_t i = 0; i<m_compCount; ++i) {
110 m_compMask[i] = compMask;
111 m_compBitShift[i] = bpc * i;
112 m_compBitCount[i] = bpc;
113 }
114 jau::consteval_assert(m_bitStride >= m_bitsPerPixel);
115 m_hashCode = hashCodeImpl();
116 }
117
118 /**
119 * @param componentOrder {@link CType Component type} order of all components, see {@link #componentBitMask()}.
120 * @param componentMask bit-mask of of all components, see {@link #componentBitMask()}.
121 * @param componentBitShift bit-shift of all components, see {@link #componentBitMask()}.
122 * @param bitStride stride bits to next pixel
123 */
124 consteval_cxx20 PixelFormat(jau::nsize_t compCount, const comparray4_t& compOrder,
125 const u32array4_t& componentMask, const u32array4_t& componentBitShift,
126 uint32_t bitStride) noexcept
127 : m_compCount(compCount), m_compOrder(compOrder), m_compMask(componentMask), m_compBitCount(), m_compBitShift(componentBitShift),
128 m_bitsPerPixel(0), m_bitStride(bitStride),
129 m_uniform(true), m_hashCode(0)
130 {
131 uint32_t bpp = 0;
132 bool uniform = true;
133 for(jau::nsize_t i = 0; i<m_compCount; ++i) {
134 const uint32_t cmask = m_compMask[i];
135 const uint32_t bitCount = std::popcount(cmask);
136 bpp += bitCount;
137 m_compBitCount[i] = bitCount;
138 if( i > 0 && uniform ) {
139 uniform = m_compMask[i-1] == cmask;
140 }
141 }
142 m_uniform = uniform;
143 m_bitsPerPixel = bpp;
144 jau::consteval_assert(m_bitStride >= m_bitsPerPixel);
145 m_hashCode = hashCodeImpl();
146 }
147
148 public:
149 std::string toString() const noexcept {
150 return jau::format_string_n(511, "PixelFmt[order %s, stride %u, bpp %u, uni %d, comp %sz: %s]",
151 jau::to_string(m_compOrder).c_str(), m_bitStride, m_bitsPerPixel, (int)m_uniform,
152 m_compMask.size(), toHexString(m_compBitCount, m_compMask, m_compBitShift).c_str());
153 }
154
155 /**
156 * Returns {@code true} if all components are of same bit-size, e.g. {@link PixelFormat#RGBA8888 RGBA8888},
157 * otherwise {@code false}, e.g. {@link PixelFormat#RGBA5551 RGBA5551}
158 */
159 constexpr bool isUniform() const noexcept { return m_uniform; }
160
161 /**
162 * Returns {@code true} if all components are packed, i.e. interleaved, e.g. {@link PixelFormat#RGBA8888 RGBA8888},
163 * otherwise {@code false}.
164 *
165 * Instances of PixelFormat returns {@code true}.
166 */
167 constexpr bool isInterleaved() const noexcept { return true; }
168
169 /** Number of components per pixel, e.g. 3 for {@link PixelFormat#RGBx8888 RGBx8888}. */
170 constexpr jau::nsize_t size() const noexcept { return m_compCount; }
171
172 /** Number of bits per pixel, e.g. 24 bits for {@link PixelFormat#RGBx8888 RGBx8888}. */
173 constexpr uint32_t bitsPerPixel() const noexcept { return m_bitsPerPixel; }
174
175 /**
176 * Bit distance between pixels.
177 *
178 * For packed pixels e.g. 32 bits for {@link PixelFormat#RGBx8888 RGBx8888}.
179 */
180 constexpr uint32_t bitStride() const noexcept { return m_bitStride; }
181
182 /** Number of bytes per pixel, i.e. packed {@link #bitStride()} in bytes, e.g. 4 for {@link PixelFormat#RGBx8888 RGBx8888}. */
183 constexpr uint32_t bytesPerPixel() const noexcept { return (7+m_bitStride)/8; }
184
185 /** Returns the {@link CType Component type} order of all components, see {@link #componentBitMask()}. */
186 constexpr const comparray4_t& order() const noexcept { return m_compOrder; }
187
188 /** Returns first index of given {@link CType} within {@link #componentOrder()}, -1 if not exists. */
189 constexpr uint32_t find(CType s) const noexcept { return pixel::find(s, m_compCount, m_compOrder, false /* mapRGB2Y */); }
190
191 constexpr const u32array4_t& bitMask() const noexcept { return m_compMask; }
192
193 constexpr const u32array4_t& bitCount() const noexcept { return m_compBitCount; }
194
195 constexpr const u32array4_t& bitShift() const noexcept { return m_compBitShift; }
196
197 constexpr uint32_t toU32(uint8_t c1NormI8) const noexcept {
198 return ( c1NormI8 & m_compMask[0] ) << m_compBitShift[0];
199 }
200 constexpr uint32_t toU32(uint8_t c1NormI8, uint8_t c2NormI8, uint8_t c3NormI8) const noexcept {
201 return ( c1NormI8 & m_compMask[0] ) << m_compBitShift[0] |
202 ( c2NormI8 & m_compMask[1] ) << m_compBitShift[1] |
203 ( c3NormI8 & m_compMask[2] ) << m_compBitShift[2] ;
204 }
205 constexpr uint32_t toU32(uint8_t c1NormI8, uint8_t c2NormI8, uint8_t c3NormI8, uint8_t c4NormI8) const noexcept {
206 return ( c1NormI8 & m_compMask[0] ) << m_compBitShift[0] |
207 ( c2NormI8 & m_compMask[1] ) << m_compBitShift[1] |
208 ( c3NormI8 & m_compMask[2] ) << m_compBitShift[2] |
209 ( c4NormI8 & m_compMask[3] ) << m_compBitShift[3] ;
210 }
211 uint32_t toU32(const uint8_t* src) const {
212 if( m_compCount == 1 ) {
213 return toU32(src[0]);
214 } else if( m_compCount == 3 ) {
215 return toU32(src[0], src[1], src[2]);
216 } else if( m_compCount == 4 ) {
217 return toU32(src[0], src[1], src[2], src[3]);
218 } else {
219 throw jau::InternalError("Unhandled format "+toString(), E_FILE_LINE);
220 }
221 }
222
223 constexpr float toFloat(uint32_t v, jau::nsize_t cIdx, bool isShifted) const noexcept {
224 if( isShifted ) {
225 return float( ( v >> m_compBitShift[cIdx] ) & m_compMask[cIdx] ) / float( m_compMask[cIdx] ) ;
226 } else {
227 return float( v & m_compMask[cIdx] ) / float( m_compMask[cIdx] ) ;
228 }
229 }
230 constexpr uint32_t fromFloat(float f, uint32_t cIdx, bool shiftResult) const noexcept {
231 uint32_t v = jau::round_to_uint(f * float(m_compMask[cIdx]));
232 return shiftResult ? v << m_compBitShift[cIdx] : v;
233 }
234
235 constexpr uint32_t defaultValue(uint32_t cIdx, bool shiftResult) const noexcept {
236 uint32_t v = ( CType::A == m_compOrder[cIdx] || CType::Y == m_compOrder[cIdx] )
237 ? m_compMask[cIdx] : 0;
238 return shiftResult ? v << m_compBitShift[cIdx] : v;
239 }
240
241 constexpr size_t hashCode() const noexcept { return m_hashCode; }
242
243 constexpr bool operator==(const PixelFormat& rhs ) const noexcept {
244 if( this == &rhs ) {
245 return true;
246 }
247 if( m_hashCode != rhs.m_hashCode ) {
248 return false;
249 }
250 return m_bitStride == rhs.m_bitStride &&
251 m_bitsPerPixel == rhs.m_bitsPerPixel &&
252 m_compOrder == rhs.m_compOrder &&
253 m_compMask == rhs.m_compMask &&
254 m_compBitShift == rhs.m_compBitShift;
255 }
256 };
257
258 /**
259 * Pixel Rectangle identified by it's {@link #hashCode()}.
260 * <p>
261 * The {@link #getPixels()} are assumed to be immutable.
262 * </p>
263 */
265 public:
266 ~PixelRectangle() noexcept = default;
267
268 /**
269 * <p>
270 * Computes a hash code over:
271 * <ul>
272 * <li>pixelformat</li>
273 * <li>size</li>
274 * <li>stride</li>
275 * <li>isGLOriented</li>
276 * <li>pixels</li>
277 * </ul>
278 * </p>
279 * <p>
280 * The hashCode shall be computed only once with first call
281 * and stored for later retrieval to enhance performance.
282 * </p>
283 * <p>
284 * {@inheritDoc}
285 * </p>
286 */
287 virtual size_t hashCode() const noexcept = 0;
288
289 /** Returns the {@link PixelFormat}. */
290 virtual const PixelFormat& format() const noexcept = 0;
291
292 /** Returns the size, i.e. width and height. */
293 virtual const Point2u32& size() const noexcept = 0;
294
295 /**
296 * Returns stride in byte-size, i.e. byte count from one line to the next.
297 * <p>
298 * Must be >= {@link #getPixelformat()}.{@link PixelFormat#bytesPerPixel() bytesPerPixel()} * {@link #getSize()}.{@link DimensionImmutable#getWidth() getWidth()}.
299 * </p>
300 */
301 virtual uint32_t stride() const noexcept = 0;
302
303 /**
304 * Returns <code>true</code> if the memory is laid out in
305 * OpenGL's coordinate system, <i>origin at bottom left</i>.
306 * Otherwise returns <code>false</code>, i.e. <i>origin at top left</i>.
307 */
308 virtual bool isGLOriented() const noexcept = 0;
309
310 /** Returns the pixels. */
311 virtual const uint8_t* pixels() const noexcept = 0;
312
313 /** Returns the pixels, mutable. */
314 virtual uint8_t* mutablePixels() noexcept = 0;
315
316 virtual std::string toString() const = 0;
317 };
318
319 /**
320 * Generic PixelRectangle implementation
321 */
323 protected:
328 std::vector<uint8_t> m_data;
329 mutable size_t m_hashCode = 0;
331 mutable std::mutex m_mtx;
332
333 size_t pixelHashCode() const noexcept {
334 const size_t byte_width = size_t(m_size.x) * m_pixelformat->bytesPerPixel();
335 size_t hash = 0;
336 for(size_t y=0; y<m_size.y; ++y) {
337 const uint8_t* line = &m_data[y*m_strideInBytes];
338 for(size_t x=0; x<byte_width; ++x) {
339 hash = ((hash << 5) - hash) + line[x];
340 }
341 }
342 return hash;
343 }
344
345 public:
346 /**
347 *
348 * @param pixelformat
349 * @param size
350 * @param strideInBytes stride in byte-size, i.e. byte count from one line to the next.
351 * If not zero, value must be >= <code>width * bytes-per-pixel</code>.
352 * If zero, stride is set to <code>width * bytes-per-pixel</code>.
353 * @param isGLOriented
354 * @throws IllegalArgumentException if <code>strideInBytes</code> is invalid.
355 * @throws IndexOutOfBoundsException if <code>pixels</code> has insufficient bytes left
356 */
357 GenericPixelRect(const PixelFormat& pixelformat, const Point2u32& size, uint32_t strideInBytes, bool isGLOriented)
358 : m_pixelformat(&pixelformat), m_size(size), m_strideInBytes(strideInBytes), m_isGLOriented(isGLOriented),
360 {
361 if( 0 != m_strideInBytes ) {
362 if( m_strideInBytes < pixelformat.bytesPerPixel() * size.x) {
363 throw jau::IllegalArgumentError("Invalid stride "+std::to_string(m_strideInBytes)+
364 ", must be greater than bytesPerPixel "+std::to_string(pixelformat.bytesPerPixel())+
365 " * width "+std::to_string(size.x), E_FILE_LINE);
366 }
367 } else {
368 m_strideInBytes = pixelformat.bytesPerPixel() * size.x;
369 }
370 const size_t capacity = size_t(m_strideInBytes) * m_size.y;
371 m_data.reserve(capacity);
372 m_data.resize(capacity);
373 }
374
375 GenericPixelRect(const GenericPixelRect& o) noexcept = delete; // too expensive
376 GenericPixelRect& operator=(const GenericPixelRect&) noexcept = delete; // too expensive
377
379 : m_pixelformat(o.m_pixelformat), m_size(o.m_size), m_strideInBytes(o.m_strideInBytes), m_isGLOriented(o.m_isGLOriented),
380 m_data(std::move(o.m_data)), m_hashCode(o.m_hashCode), m_hashCodeComputed(o.m_hashCodeComputed.load())
381 { }
383 {
384 m_pixelformat = o.m_pixelformat;
385 m_size = o.m_size;
386 m_strideInBytes = o.m_strideInBytes;
387 m_isGLOriented = o.m_isGLOriented;
388 m_data = std::move(o.m_data);
389 m_hashCode = o.m_hashCode;
390 m_hashCodeComputed = o.m_hashCodeComputed.load();
391 return *this;
392 }
393
394 size_t hashCode() const noexcept override {
395 if( !m_hashCodeComputed ) { // DBL CHECKED OK atomic
396 std::unique_lock<std::mutex> lock(m_mtx);
397 if( !m_hashCodeComputed ) {
398 // 31 * x == (x << 5) - x
399 size_t hash = m_pixelformat->hashCode();
400 hash = ((hash << 5) - hash) + m_size.hashCode();
401 hash = ((hash << 5) - hash) + m_strideInBytes;
402 hash = ((hash << 5) - hash) + ( m_isGLOriented ? 1 : 0);
403 hash = ((hash << 5) - hash) + pixelHashCode();
404 m_hashCode = hash;
405 m_hashCodeComputed = true;
406 }
407 }
408 return m_hashCode;
409 }
410
411 const PixelFormat& format() const noexcept override { return *m_pixelformat; }
412
413 const Point2u32& size() const noexcept override { return m_size; }
414
415 uint32_t stride() const noexcept override { return m_strideInBytes; }
416
417 bool isGLOriented() const noexcept override { return m_isGLOriented; }
418
419 const uint8_t* pixels() const noexcept override { return m_data.data(); }
420 uint8_t* mutablePixels() noexcept override { return m_data.data(); }
421
422 std::string toString() const override {
423 return "PixelRect[obj "+jau::to_hexstring(this)+", "+m_pixelformat->toString()+", "+m_size.toString()+
424 ", stride "+std::to_string(m_strideInBytes)+", isGLOrient "+jau::to_string(m_isGLOriented)+"]";
425 }
426 };
427
428 /**
429 * Basic pixel formats
430 * <p>
431 * Notation follows OpenGL notation, i.e.
432 * name consist of all it's component names
433 * followed by their bit size.
434 * </p>
435 * <p>
436 * Order of component names is from lowest-bit to highest-bit.
437 * </p>
438 * <p>
439 * In case component-size is 1 byte (e.g. OpenGL data-type GL_UNSIGNED_BYTE),
440 * component names are ordered from lowest-byte to highest-byte.
441 * Note that OpenGL applies special interpretation if
442 * data-type is e.g. GL_UNSIGNED_8_8_8_8_REV or GL_UNSIGNED_8_8_8_8_REV.
443 * </p>
444 * <p>
445 * PixelFormat can be converted to OpenGL GLPixelAttributes
446 * via
447 * <pre>
448 * GLPixelAttributes glpa = GLPixelAttributes.convert(PixelFormat pixFmt, GLProfile glp);
449 * </pre>
450 * </p>
451 * <p>
452 * See OpenGL Specification 4.3 - February 14, 2013, Core Profile,
453 * Section 8.4.4 Transfer of Pixel Rectangles, p. 161-174.
454 * </ul>
455 *
456 * </p>
457 */
459 public:
460 /**
461 * Stride is 8 bits, 8 bits per pixel, 1 component of 8 bits.
462 * Compatible with:
463 * <ul>
464 * <li>OpenGL: data-format GL_ALPHA (< GL3), GL_RED (>= GL3), data-type GL_UNSIGNED_BYTE</li>
465 * <li>AWT: <i>none</i></li>
466 * </ul>
467 * </p>
468 */
469 static constexpr PixelFormat LUMINANCE = PixelFormat(1, { CType::Y }, 8, 8);
470
471 /**
472 * Stride is 16 bits, 16 bits per pixel, 3 {@link PixelFormat#isUniform() discrete} components.
473 * <p>
474 * The {@link PixelFormat#isUniform() discrete} {@link PixelFormat#composition components}
475 * are interleaved in the order Low to High:
476 * <ol>
477 * <li>R: 0x1F << 0</li>
478 * <li>G: 0x3F << 5</li>
479 * <li>B: 0x1F << 11</li>
480 * </ol>
481 * </p>
482 * <p>
483 * Compatible with:
484 * <ul>
485 * <li>OpenGL: data-format GL_RGB, data-type GL_UNSIGNED_SHORT_5_6_5_REV</li>
486 * <li>AWT: <i>None</i></li>
487 * </ul>
488 * </p>
489 */
491 { 0x1F, 0x3F, 0x1F },
492 { 0, 5, 5+6 },
493 16 );
494
495 /**
496 * Stride is 16 bits, 16 bits per pixel, 3 {@link PixelFormat#isUniform() discrete} components.
497 * <p>
498 * The {@link PixelFormat#isUniform() discrete} {@link PixelFormat#composition components}
499 * are interleaved in the order Low to High:
500 * <ol>
501 * <li>B: 0x1F << 0</li>
502 * <li>G: 0x3F << 5</li>
503 * <li>R: 0x1F << 11</li>
504 * </ol>
505 * </p>
506 * <p>
507 * Compatible with:
508 * <ul>
509 * <li>OpenGL: data-format GL_RGB, data-type GL_UNSIGNED_SHORT_5_6_5</li>
510 * <li>AWT: <i>None</i></li>
511 * </ul>
512 * </p>
513 */
515 { 0x1F, 0x3F, 0x1F },
516 { 0, 5, 5+6 },
517 16 );
518
519 /**
520 * Stride is 16 bits, 16 bits per pixel, 4 {@link PixelFormat#isUniform() discrete} components.
521 * <p>
522 * The {@link PixelFormat#isUniform() discrete} {@link PixelFormat#composition components}
523 * are interleaved in the order Low to High:
524 * <ol>
525 * <li>R: 0x1F << 0</li>
526 * <li>G: 0x1F << 5</li>
527 * <li>B: 0x1F << 10</li>
528 * <li>A: 0x01 << 15</li>
529 * </ol>
530 * </p>
531 * <p>
532 * Compatible with:
533 * <ul>
534 * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_SHORT_1_5_5_5_REV</li>
535 * <li>AWT: <i>None</i></li>
536 * </ul>
537 * </p>
538 */
540 { 0x1F, 0x1F, 0x1F, 0x01 },
541 { 0, 5, 5+5, 5+5+5 },
542 16 );
543
544 /**
545 * Stride is 16 bits, 16 bits per pixel, 4 {@link PixelFormat#isUniform() discrete} components.
546 * <p>
547 * The {@link PixelFormat#isUniform() discrete} {@link PixelFormat#composition components}
548 * are interleaved in the order Low to High:
549 * <ol>
550 * <li>A: 0x01 << 0</li>
551 * <li>B: 0x1F << 1</li>
552 * <li>G: 0x1F << 6</li>
553 * <li>R: 0x1F << 11</li>
554 * </ol>
555 * </p>
556 * <p>
557 * Compatible with:
558 * <ul>
559 * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_SHORT_5_5_5_1</li>
560 * <li>AWT: <i>None</i></li>
561 * </ul>
562 * </p>
563 */
565 { 0x01, 0x1F, 0x1F, 0x1F },
566 { 0, 1, 1+5, 1+5+5 },
567 16 );
568
569 /**
570 * Stride 24 bits, 24 bits per pixel, 3 {@link PixelFormat#isUniform() uniform} components of 8 bits.
571 * <p>
572 * The {@link PixelFormat#isUniform() uniform} {@link PixelFormat#composition components}
573 * are interleaved in the order Low to High:
574 * <ol>
575 * <li>R: 0xFF << 0</li>
576 * <li>G: 0xFF << 8</li>
577 * <li>B: 0xFF << 16</li>
578 * </ol>
579 * </p>
580 * <p>
581 * Compatible with:
582 * <ul>
583 * <li>OpenGL: data-format GL_RGB, data-type GL_UNSIGNED_BYTE</li>
584 * <li>AWT: <i>None</i></li>
585 * </ul>
586 * </p>
587 */
588 static constexpr PixelFormat RGB888 = PixelFormat(3, { CType::R, CType::G, CType::B }, 8, 24);
589
590 /**
591 * Stride is 24 bits, 24 bits per pixel, 3 {@link PixelFormat#isUniform() uniform} components of of 8 bits.
592 * <p>
593 * The {@link PixelFormat#isUniform() uniform} {@link PixelFormat#composition components}
594 * are interleaved in the order Low to High:
595 * <ol>
596 * <li>B: 0xFF << 0</li>
597 * <li>G: 0xFF << 8</li>
598 * <li>R: 0xFF << 16</li>
599 * </ol>
600 * </p>
601 * <p>
602 * Compatible with:
603 * <ul>
604 * <li>OpenGL: data-format GL_BGR (>= GL2), data-type GL_UNSIGNED_BYTE</li>
605 * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_3BYTE_BGR TYPE_3BYTE_BGR}</li>
606 * </ul>
607 * </p>
608 */
609 static constexpr PixelFormat BGR888 = PixelFormat(3, { CType::B, CType::G, CType::R }, 8, 24);
610
611 /**
612 * Stride is 32 bits, 24 bits per pixel, 3 {@link PixelFormat#isUniform() uniform} components of 8 bits.
613 * <p>
614 * The {@link PixelFormat#isUniform() uniform} {@link PixelFormat#composition components}
615 * are interleaved in the order Low to High:
616 * <ol>
617 * <li>R: 0xFF << 0</li>
618 * <li>G: 0xFF << 8</li>
619 * <li>B: 0xFF << 16</li>
620 * </ol>
621 * </p>
622 * <p>
623 * Compatible with:
624 * <ul>
625 * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_BYTE, with alpha discarded!</li>
626 * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_INT_BGR TYPE_INT_BGR}</li>
627 * </ul>
628 * </p>
629 */
630 static constexpr PixelFormat RGBx8888 = PixelFormat(3, { CType::R, CType::G, CType::B }, 8, 32);
631
632 /**
633 * Stride is 32 bits, 24 bits per pixel, 3 {@link PixelFormat#isUniform() uniform} components of 8 bits.
634 * <p>
635 * The {@link PixelFormat#isUniform() uniform} {@link PixelFormat#composition components}
636 * are interleaved in the order Low to High:
637 * <ol>
638 * <li>B: 0xFF << 0</li>
639 * <li>G: 0xFF << 8</li>
640 * <li>R: 0xFF << 16</li>
641 * </ol>
642 * </p>
643 * <p>
644 * Compatible with:
645 * <ul>
646 * <li>OpenGL: data-format GL_BGRA, data-type GL_UNSIGNED_BYTE - with alpha discarded!</li>
647 * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_INT_RGB TYPE_INT_RGB}</li>
648 * </ul>
649 * </p>
650 */
651 static constexpr PixelFormat BGRx8888 = PixelFormat(3, { CType::B, CType::G, CType::R }, 8, 32);
652
653 /**
654 * Stride is 32 bits, 32 bits per pixel, 4 {@link PixelFormat#isUniform() uniform} components of 8 bits.
655 * <p>
656 * The {@link PixelFormat#isUniform() uniform} {@link PixelFormat#composition components}
657 * are interleaved in the order Low to High:
658 * <ol>
659 * <li>R: 0xFF << 0</li>
660 * <li>G: 0xFF << 8</li>
661 * <li>B: 0xFF << 16</li>
662 * <li>A: 0xFF << 24</li>
663 * </ol>
664 * </p>
665 * <p>
666 * Compatible with:
667 * <ul>
668 * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_BYTE</li>
669 * <li>AWT: <i>None</i></li>
670 * <li>PointerIcon: OSX (NSBitmapImageRep)</li>
671 * <li>Window Icon: OSX (NSBitmapImageRep)</li>
672 * <li>PNGJ: Scanlines</li>
673 * </ul>
674 * </p>
675 */
676 static constexpr PixelFormat RGBA8888 = PixelFormat(4, { CType::R, CType::G, CType::B, CType::A }, 8, 32);
677
678 /**
679 * Stride is 32 bits, 32 bits per pixel, 4 {@link PixelFormat#isUniform() uniform} components of 8 bits.
680 * <p>
681 * The {@link PixelFormat#isUniform() uniform} {@link PixelFormat#composition components}
682 * are interleaved in the order Low to High:
683 * <ol>
684 * <li>A: 0xFF << 0</li>
685 * <li>B: 0xFF << 8</li>
686 * <li>G: 0xFF << 16</li>
687 * <li>R: 0xFF << 24</li>
688 * </ol>
689 * </p>
690 * <p>
691 * Compatible with:
692 * <ul>
693 * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_INT_8_8_8_8</li>
694 * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_4BYTE_ABGR TYPE_4BYTE_ABGR}</li>
695 * </ul>
696 * </p>
697 */
698 static constexpr PixelFormat ABGR8888 = PixelFormat(4, { CType::A, CType::B, CType::G, CType::R }, 8, 32);
699
700 /**
701 * Stride is 32 bits, 32 bits per pixel, 4 {@link PixelFormat#isUniform() uniform} components of 8 bits.
702 * <p>
703 * The {@link PixelFormat#isUniform() uniform} {@link PixelFormat#composition components}
704 * are interleaved in the order Low to High:
705 * <ol>
706 * <li>A: 0xFF << 0</li>
707 * <li>R: 0xFF << 8</li>
708 * <li>G: 0xFF << 16</li>
709 * <li>B: 0xFF << 24</li>
710 * </ol>
711 * </p>
712 * <p>
713 * Compatible with:
714 * <ul>
715 * <li>OpenGL: data-format GL_BGRA, data-type GL_UNSIGNED_INT_8_8_8_8</li>
716 * <li>AWT: <i>None</i></li>
717 * </ul>
718 * </p>
719 */
720 static constexpr PixelFormat ARGB8888 = PixelFormat(4, { CType::A, CType::R, CType::G, CType::B }, 8, 32);
721
722 /**
723 * Stride is 32 bits, 32 bits per pixel, 4 {@link PixelFormat#isUniform() uniform} components of 8 bits.
724 * <p>
725 * The {@link PixelFormat#isUniform() uniform} {@link PixelFormat#composition components}
726 * are interleaved in the order Low to High:
727 * <ol>
728 * <li>B: 0xFF << 0</li>
729 * <li>G: 0xFF << 8</li>
730 * <li>R: 0xFF << 16</li>
731 * <li>A: 0xFF << 24</li>
732 * </ol>
733 * </p>
734 * <p>
735 * Compatible with:
736 * <ul>
737 * <li>OpenGL: data-format GL_BGRA, data-type GL_UNSIGNED_BYTE</li>
738 * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_INT_ARGB TYPE_INT_ARGB}</li>
739 * <li>PointerIcon: X11 (XCURSOR), Win32, AWT</li>
740 * <li>Window Icon: X11, Win32</li>
741 * </ul>
742 * </p>
743 */
744 static constexpr PixelFormat BGRA8888 = PixelFormat(4, { CType::B, CType::G, CType::R, CType::A }, 8, 32);
745
746 static constexpr std::array<const PixelFormat*, 11> formats = { &LUMINANCE, &RGB565, &BGR565,
748
749 /**
750 * Returns the {@link PixelFormat} with reversed components of <code>fmt</code>.
751 * If no reversed {@link PixelFormat} is available, returns <code>fmt</code>.
752 */
753 static const PixelFormat& reverse(const PixelFormat& fmt) noexcept {
754 if( fmt == RGB565 ) {
755 return BGR565;
756 } else if( fmt == BGR565 ) {
757 return RGB565;
758 } else if( fmt == RGBA5551 ) {
759 return ABGR1555;
760 } else if( fmt == ABGR1555 ) {
761 return RGBA5551;
762 } else if( fmt == RGB888 ) {
763 return BGR888;
764 } else if( fmt == BGR888 ) {
765 return RGB888;
766 } else if( fmt == RGBA8888 ) {
767 return ABGR8888;
768 } else if( fmt == ABGR8888 ) {
769 return RGBA8888;
770 } else if( fmt == ARGB8888 ) {
771 return BGRA8888;
772 } else if( fmt == BGRA8888 ) {
773 return ABGR8888;
774 } else {
775 return fmt;
776 }
777 }
778
779 static uint32_t toU32(const PixelFormat& dst_fmt, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
780 if(dst_fmt == LUMINANCE) {
781 const uint8_t l = (uint8_t) ( ( ( ( 0xff & r ) + ( 0xff & g ) + ( 0xff & b ) ) / 3 ) * a );
782 return ( 0xff ) << 24 | ( 0xff & l ) << 16 | ( 0xff & l ) << 8 | ( 0xff & l );
783 } else if(dst_fmt == RGB888) {
784 return ( 0xff ) << 24 | ( 0xff & b ) << 16 | ( 0xff & g ) << 8 | ( 0xff & r );
785 } else if(dst_fmt == BGR888) {
786 return ( 0xff ) << 24 | ( 0xff & r ) << 16 | ( 0xff & g ) << 8 | ( 0xff & b );
787 } else if(dst_fmt == RGBA8888) {
788 return ( 0xff & a ) << 24 | ( 0xff & b ) << 16 | ( 0xff & g ) << 8 | ( 0xff & r );
789 } else if(dst_fmt == ABGR8888) {
790 return ( 0xff & r ) << 24 | ( 0xff & g ) << 16 | ( 0xff & b ) << 8 | ( 0xff & a );
791 } else if(dst_fmt == ARGB8888) {
792 return ( 0xff & b ) << 24 | ( 0xff & g ) << 16 | ( 0xff & r ) << 8 | ( 0xff & a );
793 } else if(dst_fmt == BGRA8888) {
794 return ( 0xff & a ) << 24 | ( 0xff & r ) << 16 | ( 0xff & g ) << 8 | ( 0xff & b );
795 } else {
796 throw jau::InternalError("Unhandled format "+dst_fmt.toString(), E_FILE_LINE);
797 }
798 }
799
800 static uint32_t convertU32(const PixelFormat& dst_fmt, const PixelFormat& src_fmt, const uint8_t* src) {
801 uint8_t r, g, b, a;
802 jau::nsize_t srcOff = 0;
803 if(src_fmt == LUMINANCE) {
804 r = src[srcOff++]; // R
805 g = r; // G
806 b = r; // B
807 a = (uint8_t) 0xff; // A
808 } else if(src_fmt == RGB888) {
809 r = src[srcOff++]; // R
810 g = src[srcOff++]; // G
811 b = src[srcOff++]; // B
812 a = (uint8_t) 0xff; // A
813 } else if(src_fmt == BGR888) {
814 b = src[srcOff++]; // B
815 g = src[srcOff++]; // G
816 r = src[srcOff++]; // R
817 a = (uint8_t) 0xff; // A
818 } else if(src_fmt == RGBA8888) {
819 r = src[srcOff++]; // R
820 g = src[srcOff++]; // G
821 b = src[srcOff++]; // B
822 a = src[srcOff++]; // A
823 } else if(src_fmt == ABGR8888) {
824 a = src[srcOff++]; // A
825 b = src[srcOff++]; // B
826 g = src[srcOff++]; // G
827 r = src[srcOff++]; // R
828 } else if(src_fmt == ARGB8888) {
829 a = src[srcOff++]; // A
830 r = src[srcOff++]; // R
831 g = src[srcOff++]; // G
832 b = src[srcOff++]; // B
833 } else if(src_fmt == BGRA8888) {
834 b = src[srcOff++]; // B
835 g = src[srcOff++]; // G
836 r = src[srcOff++]; // R
837 a = src[srcOff++]; // A
838 } else {
839 throw jau::InternalError("Unhandled format "+dst_fmt.toString(), E_FILE_LINE);
840 }
841 return toU32(dst_fmt, r, g, b, a);
842 }
843
844 static uint32_t convertU32(const PixelFormat& dst_fmt, const PixelFormat& src_fmt, uint32_t src_pixel) {
845 uint8_t r, g, b, a;
846 if( src_fmt == LUMINANCE ) {
847 r = static_cast<uint8_t>(src_pixel); // R
848 g = r; // G
849 b = r; // B
850 a = static_cast<uint8_t>(0xff); // A
851 } else if( src_fmt == RGB888 ) {
852 r = static_cast<uint8_t>(src_pixel); // R
853 g = static_cast<uint8_t>(src_pixel >> 8); // G
854 b = static_cast<uint8_t>(src_pixel >> 16); // B
855 a = static_cast<uint8_t>(0xff); // A
856 } else if( src_fmt == BGR888 ) {
857 b = static_cast<uint8_t>(src_pixel); // B
858 g = static_cast<uint8_t>(src_pixel >> 8); // G
859 r = static_cast<uint8_t>(src_pixel >> 16); // R
860 a = static_cast<uint8_t>(0xff); // A
861 } else if( src_fmt == RGBA8888 ) {
862 r = static_cast<uint8_t>(src_pixel); // R
863 g = static_cast<uint8_t>(src_pixel >> 8); // G
864 b = static_cast<uint8_t>(src_pixel >> 16); // B
865 a = static_cast<uint8_t>(src_pixel >> 24); // A
866 } else if( src_fmt == ABGR8888 ) {
867 a = static_cast<uint8_t>(src_pixel); // A
868 b = static_cast<uint8_t>(src_pixel >> 8); // B
869 g = static_cast<uint8_t>(src_pixel >> 16); // G
870 r = static_cast<uint8_t>(src_pixel >> 24); // R
871 } else if( src_fmt == ARGB8888 ) {
872 a = static_cast<uint8_t>(src_pixel); // A
873 r = static_cast<uint8_t>(src_pixel >> 8); // R
874 g = static_cast<uint8_t>(src_pixel >> 16); // G
875 b = static_cast<uint8_t>(src_pixel >> 24); // B
876 } else if( src_fmt == BGRA8888 ) {
877 b = static_cast<uint8_t>(src_pixel); // B
878 g = static_cast<uint8_t>(src_pixel >> 8); // G
879 r = static_cast<uint8_t>(src_pixel >> 16); // R
880 a = static_cast<uint8_t>(src_pixel >> 24); // A
881 } else {
882 throw jau::InternalError("Unhandled format " + dst_fmt.toString(), E_FILE_LINE);
883 }
884 return toU32(dst_fmt, r, g, b, a);
885 }
886
888 const PixelFormat& destFmt, uint32_t ddestStride, bool isGLOriented) {
889 uint32_t destStride;
890 if( 0 != ddestStride ) {
891 destStride = ddestStride;
892 } else {
893 destStride = destFmt.bytesPerPixel() * src.size().x;
894 }
895 GenericPixelRect dst(destFmt, src.size(), destStride, isGLOriented);
896 // convert(src, dst);
897 convert(src.size(),
898 src.pixels(), src.format(), src.isGLOriented(), src.stride(),
899 dst.mutablePixels(), dst.format(), dst.isGLOriented(), dst.stride());
900 return dst;
901 }
902
903 /**
904 * @param src source PixelRectangle
905 * @param dst destination PixelRectangle
906 */
907 static void convert(const PixelRectangle& src, PixelRectangle& dst)
908 {
909 convert(src.size(),
910 src.pixels(), src.format(), src.isGLOriented(), src.stride(),
911 dst.mutablePixels(), dst.format(), dst.isGLOriented(), dst.stride());
912 }
913
914 /**
915 * @param width width of the to be converted pixel rectangle
916 * @param height height of the to be converted pixel rectangle
917 * @param src_bb {@link ByteBuffer} source
918 * @param src_fmt source {@link PixelFormat}
919 * @param src_glOriented if true, the source memory is laid out in OpenGL's coordinate system, <i>origin at bottom left</i>,
920 * otherwise <i>origin at top left</i>.
921 * @param src_lineStride line stride in byte-size for source, i.e. byte count from one line to the next.
922 * Must be >= {@link PixelFormat.Composition#bytesPerPixel() src_fmt.comp.bytesPerPixel()} * width
923 * or {@code zero} for default stride.
924 * @param dst_bb {@link ByteBuffer} sink
925 * @param dst_fmt destination {@link PixelFormat}
926 * @param dst_glOriented if true, the source memory is laid out in OpenGL's coordinate system, <i>origin at bottom left</i>,
927 * otherwise <i>origin at top left</i>.
928 * @param dst_lineStride line stride in byte-size for destination, i.e. byte count from one line to the next.
929 * Must be >= {@link PixelFormat.Composition#bytesPerPixel() dst_fmt.comp.bytesPerPixel()} * width
930 * or {@code zero} for default stride.
931 *
932 * @throws IllegalStateException
933 * @throws IllegalArgumentException if {@code src_lineStride} or {@code dst_lineStride} is invalid
934 */
935 static void convert(const Point2u32& size,
936 const uint8_t* src_pixels, const PixelFormat& src_fmt, bool src_glOriented, uint32_t src_lineStride,
937 uint8_t* dst_pixels, const PixelFormat& dst_fmt, bool dst_glOriented, uint32_t dst_lineStride) {
938 const uint32_t height = size.y;
939 const uint32_t width = size.x;
940 const uint32_t src_bpp = src_fmt.bytesPerPixel();
941 const uint32_t dst_bpp = dst_fmt.bytesPerPixel();
942 if( src_bpp > 4 ) {
944 }
945 if( dst_bpp > 4 ) {
947 }
948
949 if( 0 != src_lineStride ) {
950 if( src_lineStride < src_bpp * width ) {
952 src_lineStride, src_bpp, width), E_FILE_LINE);
953 }
954 } else {
955 src_lineStride = src_bpp * width;
956 }
957 if( 0 != dst_lineStride ) {
958 if( dst_lineStride < dst_bpp * width ) {
960 dst_lineStride, dst_bpp, width), E_FILE_LINE);
961 }
962 } else {
963 dst_lineStride = dst_bpp * width;
964 }
965
966 // final int src_comp_bitStride = src_comp.bitStride();
967 const uint32_t dst_comp_bitStride = dst_fmt.bitStride();
968 const bool vert_flip = src_glOriented != dst_glOriented;
969 const bool fast_copy = src_fmt == dst_fmt && 0 == dst_comp_bitStride%8;
970 #if 0
971 if( DEBUG_MODE ) {
972 System.err.println("XXX: size "+width+"x"+height+", fast_copy "+fast_copy);
973 System.err.println("XXX: SRC fmt "+src_fmt+", "+src_comp+", stride "+src_lineStride+", isGLOrient "+src_glOriented);
974 System.err.println("XXX: DST fmt "+dst_fmt+", "+dst_comp+", stride "+dst_lineStride+", isGLOrient "+dst_glOriented);
975 }
976 #endif
977
978 if( fast_copy ) {
979 // Fast copy
980 if( !vert_flip && dst_lineStride == src_lineStride ) {
981 std::memcpy(dst_pixels, src_pixels, width*dst_lineStride*height);
982 } else if( vert_flip ) {
983 for(uint32_t y=0; y<height; ++y) {
984 const uint32_t src_off = ( height - 1 - y ) * src_lineStride;
985 const uint32_t dst_off = dst_lineStride*y;
986 std::memcpy(dst_pixels+dst_off, src_pixels+src_off, width*dst_bpp);
987 }
988 } else {
989 for(uint32_t y=0; y<height; ++y) {
990 const uint32_t src_off = y * src_lineStride;
991 const uint32_t dst_off = dst_lineStride*y;
992 std::memcpy(dst_pixels+dst_off, src_pixels+src_off, width*dst_bpp);
993 }
994 }
995 } else {
996 // Conversion
997 ComponentMap cmap(src_fmt.size(), src_fmt.order(), dst_fmt.size(), dst_fmt.order());
998
999 for(uint32_t y=0; y<height; y++) {
1000 const uint32_t src_off = vert_flip ? ( height - 1 - y ) * src_lineStride : y * src_lineStride;
1001 const uint32_t dst_off = dst_lineStride*y;
1002 const uint8_t* src_pos = src_pixels+src_off;
1003 uint8_t* dst_pos = dst_pixels+dst_off;
1004 for(uint32_t x=0; x<width; ++x) {
1005 convert(cmap, dst_fmt, dst_pos, src_fmt, src_pos);
1006 }
1007 // srcBitStream.skip(( src_lineStride * 8 ) - ( src_comp_bitStride * width ));
1008 dstBitStream.skip(( dst_lineStride * 8 ) - ( dst_comp_bitStride * width ));
1009 }
1010 }
1011 }
1012
1013 static void convert(const ComponentMap& cmap,
1014 const PixelFormat dstComp,
1015 uint8_t* dstBitStream,
1016 const PixelFormat& srcComp,
1017 const uint8_t* srcBitStream)
1018 {
1019 const jau::nsize_t sCompCount = srcComp.size();
1020 const jau::nsize_t dCompCount = dstComp.size();
1021 u32array4_t sc; // = new int[sCompCount];
1022 u32array4_t dcDef; // = new int[dCompCount];
1023 const u32array4_t& srcCompBitCount = srcComp.bitCount();
1024 const u32array4_t& srcCompBitMask = srcComp.bitMask();
1025 const u32array4_t& dstCompBitCount = dstComp.bitCount();
1026
1027 // Fill w/ source values
1028 for(jau::nsize_t sIdx=0; sIdx<sCompCount; ++sIdx) {
1029 sc[sIdx] = srcBitStream.readBits31(srcCompBitCount[sIdx]) & srcCompBitMask[sIdx];
1030 }
1031 srcBitStream.skip(srcComp.bitStride() - srcComp.bitsPerPixel());
1032
1033 // Cache missing defaults
1034 for(int i=0; i<dCompCount; i++) {
1035 dcDef[i] = dstComp.defaultValue(i, false);
1036 }
1037
1038 if( 1 == dCompCount &&
1039 PixelFormat.CType::Y == dstComp.componentOrder()[0] &&
1040 cmap.hasSrcRGB
1041 )
1042 {
1043 // RGB[A] -> Y conversion
1044 final int r = sc[cmap.srcRGBA[0]];
1045 final int g = sc[cmap.srcRGBA[1]];
1046 final int b = sc[cmap.srcRGBA[2]];
1047 final float rF = srcComp.toFloat(r, cmap.srcRGBA[0], false);
1048 final float gF = srcComp.toFloat(g, cmap.srcRGBA[1], false);
1049 final float bF = srcComp.toFloat(b, cmap.srcRGBA[2], false);
1050 final int a;
1051 final float aF;
1052 /** if( 0 <= cmap.srcRGBA[3] ) { // disable premultiplied-alpha
1053 a = sc[cmap.srcRGBA[3]];
1054 aF = srcComp.toFloat(a, false, cmap.srcRGBA[3]);
1055 } else */ {
1056 a = 1;
1057 aF = 1f;
1058 }
1059 final float lF = ( rF + gF + bF ) * aF / 3f;
1060 final int v = dstComp.fromFloat(lF, 0, false);
1061
1062 dstBitStream.writeBits31(dstCompBitCount[0], v);
1063 dstBitStream.skip(dstComp.bitStride() - dstComp.bitsPerPixel());
1064 if( DEBUG ) {
1065 if( srcBitStream.position() <= 8*4 ) {
1066 System.err.printf("convert: rgb[a] -> Y: rgb 0x%02X 0x%02X 0x%02X 0x%02X -> %f %f %f %f"+
1067 " -> %f -> dstC 0 0x%08X (%d bits: %s)%n",
1068 r, g, b, a,
1069 rF, gF, bF, aF,
1070 lF, v, dstCompBitCount[0], Bitstream.toBinString(true, v, dstCompBitCount[0])
1071 );
1072 }
1073 }
1074 return;
1075 }
1076
1077 for(int dIdx=0; dIdx<dCompCount; dIdx++) {
1078 int sIdx;
1079 if( 0 <= ( sIdx = cmap.dst2src[dIdx] ) ) {
1080 final float f = srcComp.toFloat(sc[sIdx], sIdx, false);
1081 final int v = dstComp.fromFloat(f, dIdx, false);
1082 dstBitStream.writeBits31(dstCompBitCount[dIdx], v);
1083 if( DEBUG ) {
1084 if( srcBitStream.position() <= 8*4 ) {
1085 System.err.printf("convert: srcC %d: 0x%08X -> %f -> dstC %d 0x%08X (%d bits: %s)%n",
1086 sIdx, sc[sIdx], f, dIdx, v, dstCompBitCount[dIdx], Bitstream.toBinString(true, v, dstCompBitCount[dIdx]));
1087 }
1088 }
1089 } else {
1090 dstBitStream.writeBits31(dstCompBitCount[dIdx], dcDef[dIdx]);
1091 if( DEBUG ) {
1092 if( srcBitStream.position() <= 8*4 ) {
1093 System.err.printf("convert: srcC %d: undef -> dstC %d 0x%08X (%d bits: %s)%n",
1094 sIdx, dIdx, dcDef[dIdx], dstCompBitCount[dIdx], Bitstream.toBinString(true, dcDef[dIdx], dstCompBitCount[dIdx]));
1095 }
1096 }
1097 }
1098 }
1099 dstBitStream.skip(dstComp.bitStride() - dstComp.bitsPerPixel());
1100 return;
1101 }
1102 };
1103
1104
1105 /**@}*/
1106
1107} // namespace gamp::render::pixel
1108
1109#endif /* GAMP_RENDER_PIXEL_PIXELFORMAT_HPP_ */
#define E_FILE_LINE
Generic PixelRectangle implementation.
uint8_t * mutablePixels() noexcept override
Returns the pixels, mutable.
const Point2u32 & size() const noexcept override
Returns the size, i.e.
uint32_t stride() const noexcept override
Returns stride in byte-size, i.e.
const uint8_t * pixels() const noexcept override
Returns the pixels.
size_t hashCode() const noexcept override
GenericPixelRect & operator=(const GenericPixelRect &) noexcept=delete
std::string toString() const override
bool isGLOriented() const noexcept override
Returns true if the memory is laid out in OpenGL's coordinate system, origin at bottom left.
GenericPixelRect(const PixelFormat &pixelformat, const Point2u32 &size, uint32_t strideInBytes, bool isGLOriented)
GenericPixelRect(GenericPixelRect &&o) noexcept
GenericPixelRect(const GenericPixelRect &o) noexcept=delete
size_t pixelHashCode() const noexcept
const PixelFormat & format() const noexcept override
Returns the PixelFormat.
GenericPixelRect & operator=(GenericPixelRect &&o) noexcept
Packed pixel composition, i.e.
constexpr bool operator==(const PixelFormat &rhs) const noexcept
constexpr uint32_t defaultValue(uint32_t cIdx, bool shiftResult) const noexcept
constexpr const u32array4_t & bitMask() const noexcept
constexpr uint32_t bytesPerPixel() const noexcept
Number of bytes per pixel, i.e.
constexpr uint32_t toU32(uint8_t c1NormI8) const noexcept
constexpr float toFloat(uint32_t v, jau::nsize_t cIdx, bool isShifted) const noexcept
constexpr uint32_t toU32(uint8_t c1NormI8, uint8_t c2NormI8, uint8_t c3NormI8, uint8_t c4NormI8) const noexcept
constexpr bool isUniform() const noexcept
Returns true if all components are of same bit-size, e.g.
constexpr uint32_t bitsPerPixel() const noexcept
Number of bits per pixel, e.g.
constexpr const u32array4_t & bitCount() const noexcept
constexpr uint32_t toU32(uint8_t c1NormI8, uint8_t c2NormI8, uint8_t c3NormI8) const noexcept
constexpr size_t hashCode() const noexcept
constexpr const u32array4_t & bitShift() const noexcept
constexpr uint32_t fromFloat(float f, uint32_t cIdx, bool shiftResult) const noexcept
constexpr jau::nsize_t size() const noexcept
Number of components per pixel, e.g.
constexpr const comparray4_t & order() const noexcept
Returns the Component type order of all components, see componentBitMask().
constexpr uint32_t find(CType s) const noexcept
Returns first index of given CType within componentOrder(), -1 if not exists.
uint32_t toU32(const uint8_t *src) const
std::string toString() const noexcept
constexpr bool isInterleaved() const noexcept
Returns true if all components are packed, i.e.
constexpr uint32_t bitStride() const noexcept
Bit distance between pixels.
static constexpr PixelFormat BGR565
Stride is 16 bits, 16 bits per pixel, 3 discrete components.
static GenericPixelRect convert(const PixelRectangle &src, const PixelFormat &destFmt, uint32_t ddestStride, bool isGLOriented)
static constexpr PixelFormat BGR888
Stride is 24 bits, 24 bits per pixel, 3 uniform components of of 8 bits.
static constexpr PixelFormat RGB888
Stride 24 bits, 24 bits per pixel, 3 uniform components of 8 bits.
static constexpr std::array< const PixelFormat *, 11 > formats
static constexpr PixelFormat LUMINANCE
Stride is 8 bits, 8 bits per pixel, 1 component of 8 bits.
static constexpr PixelFormat RGBx8888
Stride is 32 bits, 24 bits per pixel, 3 uniform components of 8 bits.
static constexpr PixelFormat RGB565
Stride is 16 bits, 16 bits per pixel, 3 discrete components.
static void convert(const Point2u32 &size, const uint8_t *src_pixels, const PixelFormat &src_fmt, bool src_glOriented, uint32_t src_lineStride, uint8_t *dst_pixels, const PixelFormat &dst_fmt, bool dst_glOriented, uint32_t dst_lineStride)
static uint32_t convertU32(const PixelFormat &dst_fmt, const PixelFormat &src_fmt, const uint8_t *src)
static uint32_t toU32(const PixelFormat &dst_fmt, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
static constexpr PixelFormat RGBA8888
Stride is 32 bits, 32 bits per pixel, 4 uniform components of 8 bits.
static uint32_t convertU32(const PixelFormat &dst_fmt, const PixelFormat &src_fmt, uint32_t src_pixel)
static constexpr PixelFormat ARGB8888
Stride is 32 bits, 32 bits per pixel, 4 uniform components of 8 bits.
static void convert(const ComponentMap &cmap, const PixelFormat dstComp, uint8_t *dstBitStream, const PixelFormat &srcComp, const uint8_t *srcBitStream)
static constexpr PixelFormat RGBA5551
Stride is 16 bits, 16 bits per pixel, 4 discrete components.
static constexpr PixelFormat BGRx8888
Stride is 32 bits, 24 bits per pixel, 3 uniform components of 8 bits.
static constexpr PixelFormat ABGR1555
Stride is 16 bits, 16 bits per pixel, 4 discrete components.
static void convert(const PixelRectangle &src, PixelRectangle &dst)
static constexpr PixelFormat BGRA8888
Stride is 32 bits, 32 bits per pixel, 4 uniform components of 8 bits.
static constexpr PixelFormat ABGR8888
Stride is 32 bits, 32 bits per pixel, 4 uniform components of 8 bits.
static const PixelFormat & reverse(const PixelFormat &fmt) noexcept
Returns the PixelFormat with reversed components of fmt.
Pixel Rectangle identified by it's hashCode().
virtual size_t hashCode() const noexcept=0
virtual const Point2u32 & size() const noexcept=0
Returns the size, i.e.
virtual std::string toString() const =0
virtual uint32_t stride() const noexcept=0
Returns stride in byte-size, i.e.
virtual const PixelFormat & format() const noexcept=0
Returns the PixelFormat.
virtual bool isGLOriented() const noexcept=0
Returns true if the memory is laid out in OpenGL's coordinate system, origin at bottom left.
virtual const uint8_t * pixels() const noexcept=0
Returns the pixels.
virtual uint8_t * mutablePixels() noexcept=0
Returns the pixels, mutable.
value_type y
Definition vec2i.hpp:64
value_type x
Definition vec2i.hpp:63
ordered_atomic< bool, std::memory_order_seq_cst > sc_atomic_bool
SC atomic integral scalar boolean.
constexpr std::underlying_type_t< E > number(const E v) noexcept
consteval_cxx20 void consteval_assert(bool v)
#define consteval_cxx20
consteval qualifier replacement for C++20 consteval.
constexpr jau::uint_bytes_t< sizeof(T)> round_to_uint(const T v) noexcept
Returns the rounded value cast to unsigned int.
std::array< uint32_t, 4 > u32array4_t
Definition PixelUtil.hpp:58
CType
Component types.
Definition PixelUtil.hpp:37
uint32_t find(CType s, jau::nsize_t poolCount, const comparray4_t &pool, bool mapRGB2Y) noexcept
Returns first index of given CType within pool , npos if not exists.
Definition PixelUtil.hpp:65
std::array< CType, 4 > comparray4_t
Definition PixelUtil.hpp:59
@ Y
Luminance component, e.g.
Definition PixelUtil.hpp:50
@ A
Alpha component.
Definition PixelUtil.hpp:48
@ G
Green component.
Definition PixelUtil.hpp:44
uint_bytes_t< sizeof(unsigned long int)> nsize_t
Natural 'size_t' alternative using uint<XX>_t with xx = sizeof(unsigned long int)*8 as its natural si...
Definition int_types.hpp:85
Point2I< uint32_t > Point2u32
Definition vec2i.hpp:348
constexpr std::string format_string_n(const std::size_t maxStrLen, const std::string_view &format, const Args &...args)
Safely returns a (potentially truncated) string according to snprintf() formatting rules and variable...
std::string to_string(const bit_order_t v) noexcept
Return std::string representation of the given bit_order_t.
STL namespace.
static std::string f(uint32_t v)
static constexpr const bool DEBUG_MODE