Skip to content
This repository was archived by the owner on Jun 22, 2025. It is now read-only.

Commit 183959d

Browse files
committed
com: Add simple swizzler function
1 parent ab36422 commit 183959d

4 files changed

Lines changed: 112 additions & 0 deletions

File tree

src/common/image.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,8 @@ static bool process_image_internal(void* indata, int comps, int w, int h, ProcFl
306306
T* cur = data + i;
307307
if (flags & PROC_GL_TO_DX_NORM)
308308
cur[1] = FULL_VAL<T> - cur[1]; // Invert green channel
309+
if (flags & PROC_INVERT_ALPHA)
310+
cur[3] = FULL_VAL<T> - cur[3];
309311
}
310312
return true;
311313
}
@@ -401,3 +403,33 @@ size_t imglib::channel_size(ChannelType type) {
401403
return 1;
402404
}
403405
}
406+
407+
bool Image::swizzle(uint32_t mask) {
408+
switch (m_type) {
409+
case ChannelType::UInt8:
410+
return lwiconv::swizzle(static_cast<uint8_t*>(m_data), m_width, m_height, m_comps, mask);
411+
case ChannelType::UInt16:
412+
return lwiconv::swizzle(static_cast<uint16_t*>(m_data), m_width, m_height, m_comps, mask);
413+
case ChannelType::Float:
414+
return lwiconv::swizzle(static_cast<float*>(m_data), m_width, m_height, m_comps, mask);
415+
default:
416+
return false;
417+
}
418+
}
419+
420+
uint32_t imglib::swizzle_from_str(const char* str) {
421+
uint32_t mask = 0;
422+
for (int i = 0; i < lwiconv::MAX_CHANNELS; ++i, ++str) {
423+
if (!*str) break;
424+
int v = 0;
425+
switch (*str) {
426+
case 'r': v = 0; break;
427+
case 'g': v = 1; break;
428+
case 'b': v = 2; break;
429+
case 'a': v = 3; break;
430+
default: return 0xFFFFFFFF;
431+
}
432+
mask |= v << (i*8);
433+
}
434+
return mask;
435+
}

src/common/image.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ namespace imglib
1414
{
1515

1616
constexpr int MAX_CHANNELS = 4;
17+
18+
using lwiconv::make_swizzle;
1719

1820
/**
1921
* Per-channel data type
@@ -48,6 +50,9 @@ namespace imglib
4850

4951
using ProcFlags = uint32_t;
5052
inline constexpr ProcFlags PROC_GL_TO_DX_NORM = (1 << 0);
53+
inline constexpr ProcFlags PROC_INVERT_ALPHA = (1 << 1);
54+
55+
uint32_t swizzle_from_str(const char* str);
5156

5257
/**
5358
* Returns the number of bytes per pixel for the format
@@ -124,6 +129,12 @@ namespace imglib
124129
* @param pdef Default pixel fill for uninitialized pixels
125130
*/
126131
bool convert(ChannelType type, int channels = -1, const lwiconv::PixelF& pdef = {0,0,0,1});
132+
133+
/**
134+
* Perform in-place swizzle of components
135+
* @param mask Swizzle mask. @see lwiconv::make_swizzle
136+
*/
137+
bool swizzle(uint32_t mask);
127138

128139
/**
129140
* Returns the VTF format which matches up to the data we have internally here

src/common/lwiconv.hpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <cstdint>
88
#include <cstddef>
9+
#include <cassert>
910

1011
namespace lwiconv
1112
{
@@ -90,6 +91,7 @@ inline void pixel_to_data(T* pout, const PixelF& p) {
9091
/**
9192
* \brief Convert buffer from one color format to another
9293
* The input and output buffers are assumed to be the same dimensions.
94+
* in and out must not overlap.
9395
* \param in Pointer to the input buffer
9496
* \param out Pointer to the output buffer
9597
* \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
138140
outConv(pout, inConv(pin, channelDefaults));
139141
}
140142

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+
141201
} // lwiconv

src/tests/image_tests.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,12 @@ TEST(ImageTests, Basic8To8)
118118
runTest<uint8_t, uint8_t>(32, 32, 4, 4, {128, 0, 0xFF, 99}, {128, 0, 0xFF, 99});
119119
}
120120

121+
TEST(ImageTests, BasicSwizzle)
122+
{
123+
uint8_t img[4] = {1,2,3,4};
124+
ASSERT_TRUE(swizzle<uint8_t>(img, 1, 1, 4, make_swizzle(3, 2, 1, 0)));
125+
ASSERT_EQ(img[0], 4);
126+
ASSERT_EQ(img[1], 3);
127+
ASSERT_EQ(img[2], 2);
128+
ASSERT_EQ(img[3], 1);
129+
}

0 commit comments

Comments
 (0)