PackOrder.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. // zlib open source license
  2. //
  3. // Copyright (c) 2017 to 2019 David Forsgren Piuva
  4. //
  5. // This software is provided 'as-is', without any express or implied
  6. // warranty. In no event will the authors be held liable for any damages
  7. // arising from the use of this software.
  8. //
  9. // Permission is granted to anyone to use this software for any purpose,
  10. // including commercial applications, and to alter it and redistribute it
  11. // freely, subject to the following restrictions:
  12. //
  13. // 1. The origin of this software must not be misrepresented; you must not
  14. // claim that you wrote the original software. If you use this software
  15. // in a product, an acknowledgment in the product documentation would be
  16. // appreciated but is not required.
  17. //
  18. // 2. Altered source versions must be plainly marked as such, and must not be
  19. // misrepresented as being the original software.
  20. //
  21. // 3. This notice may not be removed or altered from any source
  22. // distribution.
  23. #ifndef DFPSR_IMAGE_PACK_ORDER
  24. #define DFPSR_IMAGE_PACK_ORDER
  25. #include <stdint.h>
  26. #include "../api/types.h"
  27. #include "../base/simd.h"
  28. #include "../base/endian.h"
  29. #include "../api/stringAPI.h"
  30. namespace dsr {
  31. // See types.h for the definition of PackOrderIndex
  32. struct PackOrder {
  33. public:
  34. // The index that it was constructed from
  35. PackOrderIndex packOrderIndex;
  36. // Byte array indices for each channel
  37. // Indices are the locations of each color, not which color that holds each location
  38. // Example:
  39. // The indices for ARGB are (1, 2, 3, 0)
  40. // Because red is second at byte[1], green is third byte[2], blue is last in byte[3] and alpha is first in byte[0]
  41. int redIndex, greenIndex, blueIndex, alphaIndex;
  42. // Pre-multipled bit offsets
  43. int redOffset, greenOffset, blueOffset, alphaOffset;
  44. uint32_t redMask, greenMask, blueMask, alphaMask;
  45. private:
  46. PackOrder(PackOrderIndex packOrderIndex, int redIndex, int greenIndex, int blueIndex, int alphaIndex) :
  47. packOrderIndex(packOrderIndex),
  48. redIndex(redIndex), greenIndex(greenIndex), blueIndex(blueIndex), alphaIndex(alphaIndex),
  49. redOffset(redIndex * 8), greenOffset(greenIndex * 8), blueOffset(blueIndex * 8), alphaOffset(alphaIndex * 8),
  50. redMask(ENDIAN_POS_ADDR(ENDIAN32_BYTE_0, this->redOffset)),
  51. greenMask(ENDIAN_POS_ADDR(ENDIAN32_BYTE_0, this->greenOffset)),
  52. blueMask(ENDIAN_POS_ADDR(ENDIAN32_BYTE_0, this->blueOffset)),
  53. alphaMask(ENDIAN_POS_ADDR(ENDIAN32_BYTE_0, this->alphaOffset)) {}
  54. public:
  55. // Constructors
  56. PackOrder() :
  57. packOrderIndex(PackOrderIndex::RGBA),
  58. redIndex(0), greenIndex(1), blueIndex(2), alphaIndex(3),
  59. redOffset(0), greenOffset(8), blueOffset(16), alphaOffset(24),
  60. redMask(ENDIAN32_BYTE_0), greenMask(ENDIAN32_BYTE_1), blueMask(ENDIAN32_BYTE_2), alphaMask(ENDIAN32_BYTE_3) {}
  61. static PackOrder getPackOrder(PackOrderIndex index) {
  62. if (index == PackOrderIndex::RGBA) {
  63. return PackOrder(index, 0, 1, 2, 3);
  64. } else if (index == PackOrderIndex::BGRA) {
  65. return PackOrder(index, 2, 1, 0, 3);
  66. } else if (index == PackOrderIndex::ARGB) {
  67. return PackOrder(index, 1, 2, 3, 0);
  68. } else if (index == PackOrderIndex::ABGR) {
  69. return PackOrder(index, 3, 2, 1, 0);
  70. } else {
  71. printText("Warning! Unknown packing order index ", index, ". Falling back on RGBA.");
  72. return PackOrder(index, 0, 1, 2, 3);
  73. }
  74. }
  75. uint32_t packRgba(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) const {
  76. uint32_t result;
  77. uint8_t *channels = (uint8_t*)(&result);
  78. channels[this->redIndex] = red;
  79. channels[this->greenIndex] = green;
  80. channels[this->blueIndex] = blue;
  81. channels[this->alphaIndex] = alpha;
  82. return result;
  83. }
  84. };
  85. inline bool operator==(const PackOrder &left, const PackOrder &right) {
  86. return left.packOrderIndex == right.packOrderIndex;
  87. }
  88. // Each input 32-bit element is from 0 to 255. Otherwise, the remainder will leak to other elements.
  89. inline static U32x4 packBytes(const U32x4 &s0, const U32x4 &s1, const U32x4 &s2) {
  90. return s0 | ENDIAN_POS_ADDR(s1, 8) | ENDIAN_POS_ADDR(s2, 16);
  91. }
  92. // Using a specified packing order
  93. inline U32x4 packBytes(const U32x4 &s0, const U32x4 &s1, const U32x4 &s2, const PackOrder &order) {
  94. return ENDIAN_POS_ADDR(s0, order.redOffset)
  95. | ENDIAN_POS_ADDR(s1, order.greenOffset)
  96. | ENDIAN_POS_ADDR(s2, order.blueOffset);
  97. }
  98. // Each input 32-bit element is from 0 to 255. Otherwise, the remainder will leak to other elements.
  99. inline static U32x4 packBytes(const U32x4 &s0, const U32x4 &s1, const U32x4 &s2, const U32x4 &s3) {
  100. return s0 | ENDIAN_POS_ADDR(s1, 8) | ENDIAN_POS_ADDR(s2, 16) | ENDIAN_POS_ADDR(s3, 24);
  101. }
  102. // Using a specified packing order
  103. inline U32x4 packBytes(const U32x4 &s0, const U32x4 &s1, const U32x4 &s2, const U32x4 &s3, const PackOrder &order) {
  104. return ENDIAN_POS_ADDR(s0, order.redOffset)
  105. | ENDIAN_POS_ADDR(s1, order.greenOffset)
  106. | ENDIAN_POS_ADDR(s2, order.blueOffset)
  107. | ENDIAN_POS_ADDR(s3, order.alphaOffset);
  108. }
  109. // Pack separate floats into saturated bytes
  110. inline static U32x4 floatToSaturatedByte(const F32x4 &s0, const F32x4 &s1, const F32x4 &s2, const F32x4 &s3) {
  111. return packBytes(
  112. truncateToU32(s0.clamp(0.1f, 255.1f)),
  113. truncateToU32(s1.clamp(0.1f, 255.1f)),
  114. truncateToU32(s2.clamp(0.1f, 255.1f)),
  115. truncateToU32(s3.clamp(0.1f, 255.1f))
  116. );
  117. }
  118. // Using a specified packing order
  119. inline U32x4 floatToSaturatedByte(const F32x4 &s0, const F32x4 &s1, const F32x4 &s2, const F32x4 &s3, const PackOrder &order) {
  120. return packBytes(
  121. truncateToU32(s0.clamp(0.1f, 255.1f)),
  122. truncateToU32(s1.clamp(0.1f, 255.1f)),
  123. truncateToU32(s2.clamp(0.1f, 255.1f)),
  124. truncateToU32(s3.clamp(0.1f, 255.1f)),
  125. order
  126. );
  127. }
  128. inline uint32_t getRed(uint32_t color) {
  129. return color & ENDIAN32_BYTE_0;
  130. }
  131. inline uint32_t getRed(uint32_t color, const PackOrder &order) {
  132. return ENDIAN_NEG_ADDR(color & order.redMask, order.redOffset);
  133. }
  134. inline uint32_t getGreen(uint32_t color) {
  135. return ENDIAN_NEG_ADDR(color & ENDIAN32_BYTE_1, 8);
  136. }
  137. inline uint32_t getGreen(uint32_t color, const PackOrder &order) {
  138. return ENDIAN_NEG_ADDR(color & order.greenMask, order.greenOffset);
  139. }
  140. inline uint32_t getBlue(uint32_t color) {
  141. return ENDIAN_NEG_ADDR(color & ENDIAN32_BYTE_2, 16);
  142. }
  143. inline uint32_t getBlue(uint32_t color, const PackOrder &order) {
  144. return ENDIAN_NEG_ADDR(color & order.blueMask, order.blueOffset);
  145. }
  146. inline uint32_t getAlpha(uint32_t color) {
  147. return ENDIAN_NEG_ADDR(color & ENDIAN32_BYTE_3, 24);
  148. }
  149. inline uint32_t getAlpha(uint32_t color, const PackOrder &order) {
  150. return ENDIAN_NEG_ADDR(color & order.alphaMask, order.alphaOffset);
  151. }
  152. inline U32x4 getRed(const U32x4 &color) {
  153. return color & ENDIAN32_BYTE_0;
  154. }
  155. inline U32x4 getRed(const U32x4 &color, const PackOrder &order) {
  156. return ENDIAN_NEG_ADDR(color & order.redMask, order.redOffset);
  157. }
  158. inline U32x4 getGreen(const U32x4 &color) {
  159. return ENDIAN_NEG_ADDR(color & ENDIAN32_BYTE_1, 8);
  160. }
  161. inline U32x4 getGreen(const U32x4 &color, const PackOrder &order) {
  162. return ENDIAN_NEG_ADDR(color & order.greenMask, order.greenOffset);
  163. }
  164. inline U32x4 getBlue(const U32x4 &color) {
  165. return ENDIAN_NEG_ADDR(color & ENDIAN32_BYTE_2, 16);
  166. }
  167. inline U32x4 getBlue(const U32x4 &color, const PackOrder &order) {
  168. return ENDIAN_NEG_ADDR(color & order.blueMask, order.blueOffset);
  169. }
  170. inline U32x4 getAlpha(const U32x4 &color) {
  171. return ENDIAN_NEG_ADDR(color & ENDIAN32_BYTE_3, 24);
  172. }
  173. inline U32x4 getAlpha(const U32x4 &color, const PackOrder &order) {
  174. return ENDIAN_NEG_ADDR(color & order.alphaMask, order.alphaOffset);
  175. }
  176. inline String getName(PackOrderIndex index) {
  177. if (index == PackOrderIndex::RGBA) {
  178. return U"RGBA";
  179. } else if (index == PackOrderIndex::BGRA) {
  180. return U"BGRA";
  181. } else if (index == PackOrderIndex::ARGB) {
  182. return U"ARGB";
  183. } else if (index == PackOrderIndex::ABGR) {
  184. return U"ABGR";
  185. } else {
  186. return U"?";
  187. }
  188. }
  189. inline String& string_toStreamIndented(String& target, const PackOrderIndex& source, const ReadableString& indentation) {
  190. string_append(target, indentation, getName(source));
  191. return target;
  192. }
  193. inline String& string_toStreamIndented(String& target, const PackOrder& source, const ReadableString& indentation) {
  194. string_append(target, indentation, getName(source.packOrderIndex));
  195. return target;
  196. }
  197. }
  198. #endif