PackOrder.h 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. // zlib open source license
  2. //
  3. // Copyright (c) 2017 to 2023 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. template<typename T> // Accepting uint32_t, U32x4, U32x8...
  90. T packBytes(const T &s0, const T &s1, const T &s2) {
  91. return s0 | ENDIAN_POS_ADDR(s1, 8) | ENDIAN_POS_ADDR(s2, 16);
  92. }
  93. // Using a specified packing order
  94. template<typename T> // Accepting uint32_t, U32x4, U32x8...
  95. T packBytes(const T &s0, const T &s1, const T &s2, const PackOrder &order) {
  96. return ENDIAN_POS_ADDR(s0, order.redOffset)
  97. | ENDIAN_POS_ADDR(s1, order.greenOffset)
  98. | ENDIAN_POS_ADDR(s2, order.blueOffset);
  99. }
  100. // Each input 32-bit element is from 0 to 255. Otherwise, the remainder will leak to other elements.
  101. template<typename T> // Accepting uint32_t, U32x4, U32x8...
  102. T packBytes(const T &s0, const T &s1, const T &s2, const T &s3) {
  103. return s0 | ENDIAN_POS_ADDR(s1, 8) | ENDIAN_POS_ADDR(s2, 16) | ENDIAN_POS_ADDR(s3, 24);
  104. }
  105. // Using a specified packing order
  106. template<typename T> // Accepting uint32_t, U32x4, U32x8...
  107. T packBytes(const T &s0, const T &s1, const T &s2, const T &s3, const PackOrder &order) {
  108. return ENDIAN_POS_ADDR(s0, order.redOffset)
  109. | ENDIAN_POS_ADDR(s1, order.greenOffset)
  110. | ENDIAN_POS_ADDR(s2, order.blueOffset)
  111. | ENDIAN_POS_ADDR(s3, order.alphaOffset);
  112. }
  113. // Pack separate floats into saturated bytes
  114. inline U32x4 floatToSaturatedByte(const F32x4 &s0, const F32x4 &s1, const F32x4 &s2, const F32x4 &s3) {
  115. return packBytes(
  116. truncateToU32(s0.clamp(0.1f, 255.1f)),
  117. truncateToU32(s1.clamp(0.1f, 255.1f)),
  118. truncateToU32(s2.clamp(0.1f, 255.1f)),
  119. truncateToU32(s3.clamp(0.1f, 255.1f))
  120. );
  121. }
  122. inline U32x8 floatToSaturatedByte(const F32x8 &s0, const F32x8 &s1, const F32x8 &s2, const F32x8 &s3) {
  123. return packBytes(
  124. truncateToU32(s0.clamp(0.1f, 255.1f)),
  125. truncateToU32(s1.clamp(0.1f, 255.1f)),
  126. truncateToU32(s2.clamp(0.1f, 255.1f)),
  127. truncateToU32(s3.clamp(0.1f, 255.1f))
  128. );
  129. }
  130. // Using a specified packing order
  131. inline U32x4 floatToSaturatedByte(const F32x4 &s0, const F32x4 &s1, const F32x4 &s2, const F32x4 &s3, const PackOrder &order) {
  132. return packBytes(
  133. truncateToU32(s0.clamp(0.1f, 255.1f)),
  134. truncateToU32(s1.clamp(0.1f, 255.1f)),
  135. truncateToU32(s2.clamp(0.1f, 255.1f)),
  136. truncateToU32(s3.clamp(0.1f, 255.1f)),
  137. order
  138. );
  139. }
  140. inline U32x8 floatToSaturatedByte(const F32x8 &s0, const F32x8 &s1, const F32x8 &s2, const F32x8 &s3, const PackOrder &order) {
  141. return packBytes(
  142. truncateToU32(s0.clamp(0.1f, 255.1f)),
  143. truncateToU32(s1.clamp(0.1f, 255.1f)),
  144. truncateToU32(s2.clamp(0.1f, 255.1f)),
  145. truncateToU32(s3.clamp(0.1f, 255.1f)),
  146. order
  147. );
  148. }
  149. template<typename T> // Accepting uint32_t, U32x4, U32x8...
  150. inline T getRed(T color) {
  151. return color & ENDIAN32_BYTE_0;
  152. }
  153. template<typename T> // Accepting uint32_t, U32x4, U32x8...
  154. inline T getRed(T color, const PackOrder &order) {
  155. return ENDIAN_NEG_ADDR(color & order.redMask, order.redOffset);
  156. }
  157. template<typename T> // Accepting uint32_t, U32x4, U32x8...
  158. inline T getGreen(T color) {
  159. return ENDIAN_NEG_ADDR(color & ENDIAN32_BYTE_1, 8);
  160. }
  161. template<typename T> // Accepting uint32_t, U32x4, U32x8...
  162. inline T getGreen(T color, const PackOrder &order) {
  163. return ENDIAN_NEG_ADDR(color & order.greenMask, order.greenOffset);
  164. }
  165. template<typename T> // Accepting uint32_t, U32x4, U32x8...
  166. inline T getBlue(T color) {
  167. return ENDIAN_NEG_ADDR(color & ENDIAN32_BYTE_2, 16);
  168. }
  169. template<typename T> // Accepting uint32_t, U32x4, U32x8...
  170. inline T getBlue(T color, const PackOrder &order) {
  171. return ENDIAN_NEG_ADDR(color & order.blueMask, order.blueOffset);
  172. }
  173. template<typename T> // Accepting uint32_t, U32x4, U32x8...
  174. inline T getAlpha(T color) {
  175. return ENDIAN_NEG_ADDR(color & ENDIAN32_BYTE_3, 24);
  176. }
  177. template<typename T> // Accepting uint32_t, U32x4, U32x8...
  178. inline T getAlpha(T color, const PackOrder &order) {
  179. return ENDIAN_NEG_ADDR(color & order.alphaMask, order.alphaOffset);
  180. }
  181. inline String getName(PackOrderIndex index) {
  182. if (index == PackOrderIndex::RGBA) {
  183. return U"RGBA";
  184. } else if (index == PackOrderIndex::BGRA) {
  185. return U"BGRA";
  186. } else if (index == PackOrderIndex::ARGB) {
  187. return U"ARGB";
  188. } else if (index == PackOrderIndex::ABGR) {
  189. return U"ABGR";
  190. } else {
  191. return U"?";
  192. }
  193. }
  194. inline String& string_toStreamIndented(String& target, const PackOrderIndex& source, const ReadableString& indentation) {
  195. string_append(target, indentation, getName(source));
  196. return target;
  197. }
  198. inline String& string_toStreamIndented(String& target, const PackOrder& source, const ReadableString& indentation) {
  199. string_append(target, indentation, getName(source.packOrderIndex));
  200. return target;
  201. }
  202. }
  203. #endif