Haio 0.2.X
Homebrew Asset IO/CDN
Loading...
Searching...
No Matches
rgba8888.cpp
Go to the documentation of this file.
1#include <haio_convert.hpp>
2
3#include <algorithm>
4#include <cstring>
5#include <limits>
6#include <optional>
7
8#include <Decode.hpp>
9#include <ProcessRGB.hpp>
10
11namespace {
12
13using Haio::Bytes;
14
15int paddedSize(int size) {
16 return (size + 3) & ~3;
17}
18
19size_t blockCount(int width, int height) {
20 return static_cast<size_t>(paddedSize(width) / 4) * static_cast<size_t>(paddedSize(height) / 4);
21}
22
23std::optional<Haio::Error> validateDimensions(int width, int height) {
24 if (width <= 0 || height <= 0) {
25 return Haio::Error{Haio::ErrorCode::InvalidInput, "etc1 images require positive width and height"};
26 }
27 return std::nullopt;
28}
29
30Haio::Result<std::vector<uint32_t>> makePaddedBGRA(Bytes src, Haio::Size size, int paddedWidth, int paddedHeight) {
31 const auto expectedSize = static_cast<size_t>(size.width) * static_cast<size_t>(size.height) * 4;
32 if (src.size() != expectedSize) {
33 return std::unexpected(Haio::Error{Haio::ErrorCode::InvalidInput, "invalid rgba8888 data size for etc1 encode"});
34 }
35
36 std::vector<uint32_t> pixels(static_cast<size_t>(paddedWidth) * static_cast<size_t>(paddedHeight));
37 for (int y = 0; y < paddedHeight; y++) {
38 const int srcY = std::min(y, size.height - 1);
39 for (int x = 0; x < paddedWidth; x++) {
40 const int srcX = std::min(x, size.width - 1);
41 const auto srcOffset = (static_cast<size_t>(srcY) * static_cast<size_t>(size.width) + static_cast<size_t>(srcX)) * 4;
42 const uint8_t bgra[4] = {
43 src[srcOffset + 2],
44 src[srcOffset + 1],
45 src[srcOffset + 0],
46 src[srcOffset + 3]
47 };
48 std::memcpy(&pixels[static_cast<size_t>(y) * static_cast<size_t>(paddedWidth) + static_cast<size_t>(x)], bgra, 4);
49 }
50 }
51 return pixels;
52}
53
54}
55
56namespace Haio::Codecs {
57
58/**
59 * @addtogroup move
60 * @{
61 */
62template <>
63Result<void> Move<Color::ETC1, Color::RGBA8888>(Bytes src, std::span<uint8_t> dst, Size size) {
64 const size_t blocks = blockCount(size.width, size.height);
65 const size_t expectedSize = blocks * 8;
66 if (src.size() != expectedSize) {
67 HAIO_FAIL(InvalidInput, "invalid etc1 data size");
68 }
69
70 const int paddedWidth = paddedSize(size.width);
71 const int paddedHeight = paddedSize(size.height);
72 std::vector<uint64_t> compressed(blocks);
73 std::memcpy(compressed.data(), src.data(), expectedSize);
74
75 std::vector<uint32_t> paddedRGBA(static_cast<size_t>(paddedWidth) * static_cast<size_t>(paddedHeight));
76 DecodeRGB(compressed.data(), paddedRGBA.data(), paddedWidth, paddedHeight);
77
78 std::vector<uint8_t> buffer(static_cast<size_t>(size.width) * static_cast<size_t>(size.height) * 4);
79 for (int y = 0; y < size.height; y++) {
80 for (int x = 0; x < size.width; x++) {
81 const auto srcOffset = static_cast<size_t>(y) * static_cast<size_t>(paddedWidth) + static_cast<size_t>(x);
82 const auto dstOffset = (static_cast<size_t>(y) * static_cast<size_t>(size.width) + static_cast<size_t>(x)) * 4;
83 std::memcpy(buffer.data() + dstOffset, &paddedRGBA[srcOffset], 4);
84 buffer[dstOffset + 3] = 255;
85 }
86 }
87
88
89 std::memcpy(dst.data(), buffer.data(), std::min(dst.size(), buffer.size()));
90 return {};
91}
92/** @} */
93
94/**
95 * @addtogroup convert
96 * @{
97 */
98template <>
100 return convertVia<Color::ETC1, Color::RGBA8888>(std::move(src));
101}
102/** @} */
103
104}
Result< Image< Color::RGBA8888 > > Convert< Color::ETC1, Color::RGBA8888 >(Image< Color::ETC1 > src)
Definition rgba8888.cpp:99
Result< void > Move< Color::ETC1, Color::RGBA8888 >(Bytes src, std::span< uint8_t > dst, Size size)
Definition rgba8888.cpp:63
#define HAIO_FAIL(why, message)
Result< Image< To > > convertVia(Image< From > src)
std::expected< T, Error > Result
std::span< const uint8_t > Bytes