|
6 | 6 |
|
7 | 7 | #include <cstdint> |
8 | 8 | #include <cstddef> |
| 9 | +#include <cassert> |
9 | 10 |
|
10 | 11 | namespace lwiconv |
11 | 12 | { |
@@ -90,6 +91,7 @@ inline void pixel_to_data(T* pout, const PixelF& p) { |
90 | 91 | /** |
91 | 92 | * \brief Convert buffer from one color format to another |
92 | 93 | * The input and output buffers are assumed to be the same dimensions. |
| 94 | + * in and out must not overlap. |
93 | 95 | * \param in Pointer to the input buffer |
94 | 96 | * \param out Pointer to the output buffer |
95 | 97 | * \param w Width of the image |
@@ -138,4 +140,62 @@ static void convert_generic(const void* in, void* out, int w, int h, int inC, in |
138 | 140 | outConv(pout, inConv(pin, channelDefaults)); |
139 | 141 | } |
140 | 142 |
|
| 143 | +constexpr uint32_t NO_SWIZZLE = 0x00010203; |
| 144 | + |
| 145 | +/** |
| 146 | + * \brief Makes a 32-bit swizzle mask thingy |
| 147 | + * Parameters A B C D indicate where the channel should get its data. |
| 148 | + * So, make_swizzle(3, 2, 1, 0) would turn an RGBA image into ABGR |
| 149 | + */ |
| 150 | +static inline constexpr uint32_t make_swizzle(int a, int b, int c, int d) { |
| 151 | + return (a & 0xFF) << 24 | (b & 0xFF) << 16 | (c & 0xFF) << 8 | (d & 0xFF); |
| 152 | +} |
| 153 | + |
| 154 | +namespace detail { |
| 155 | + |
| 156 | +static inline PixelF swizzle_one(const PixelF& pixel, uint32_t mask) { |
| 157 | + return { pixel.d[(mask >> 24) & 0xFF], pixel.d[(mask >> 16) & 0xFF], pixel.d[(mask >> 8) & 0xFF], pixel.d[mask & 0xFF] }; |
| 158 | +} |
| 159 | + |
| 160 | +} |
| 161 | + |
| 162 | +template<typename T> |
| 163 | +static bool swizzle(T* image, int w, int h, int comps, uint32_t swizzle) { |
| 164 | + assert(comps <= MAX_CHANNELS && comps > 0); |
| 165 | + if (comps <= 0 || comps > MAX_CHANNELS) |
| 166 | + return false; |
| 167 | + |
| 168 | + // Check that swizzle is in bounds too |
| 169 | + for (int i = 0; i < comps; ++i) |
| 170 | + if (((swizzle >> (i*8)) & 0xFF) > comps) |
| 171 | + return false; |
| 172 | + |
| 173 | + using fnInConv = PixelF (*)(const T*, const PixelF&); |
| 174 | + constexpr fnInConv inConvFuncs[MAX_CHANNELS] = { |
| 175 | + detail::pixel_from_data<T, 1>, |
| 176 | + detail::pixel_from_data<T, 2>, |
| 177 | + detail::pixel_from_data<T, 3>, |
| 178 | + detail::pixel_from_data<T, 4>, |
| 179 | + }; |
| 180 | + const fnInConv inConv = inConvFuncs[comps-1]; |
| 181 | + |
| 182 | + using fnOutConv = void (*)(T*, const PixelF&); |
| 183 | + constexpr fnOutConv outConvFuncs[MAX_CHANNELS] = { |
| 184 | + detail::pixel_to_data<T, 1>, |
| 185 | + detail::pixel_to_data<T, 2>, |
| 186 | + detail::pixel_to_data<T, 3>, |
| 187 | + detail::pixel_to_data<T, 4>, |
| 188 | + }; |
| 189 | + const fnOutConv outConv = outConvFuncs[comps-1]; |
| 190 | + |
| 191 | + const size_t stride = comps * sizeof(T); |
| 192 | + for (int m = 0; m < w*h; ++m, image += stride) { |
| 193 | + outConv(image, detail::swizzle_one( |
| 194 | + inConv(image, {0,0,0,0}), swizzle |
| 195 | + )); |
| 196 | + } |
| 197 | + |
| 198 | + return true; |
| 199 | +} |
| 200 | + |
141 | 201 | } // lwiconv |
0 commit comments