Haio 0.2.X
Homebrew Asset IO/CDN
Loading...
Searching...
No Matches
etc1.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 */
62/** lossy: four by four blocks, and the dimensions round up to whole blocks */
63template <>
64Result<void> Move<Color::RGBA8888, Color::ETC1>(Bytes src, std::span<uint8_t> dst, Size size) {
65 const int paddedWidth = paddedSize(size.width);
66 const int paddedHeight = paddedSize(size.height);
67 const size_t blocks = blockCount(size.width, size.height);
68 if (blocks > std::numeric_limits<uint32_t>::max()) {
69 HAIO_FAIL(InvalidInput, "etc1 image is too large");
70 }
71
72 HAIO_TRY(pixels, makePaddedBGRA(src, size, paddedWidth, paddedHeight));
73 std::vector<uint64_t> compressed(blocks);
74
75 CompressEtc1RgbDither(
76 pixels.data(),
77 compressed.data(),
78 static_cast<uint32_t>(blocks),
79 static_cast<size_t>(paddedWidth)
80 );
81
82 std::memcpy(dst.data(), compressed.data(), std::min(dst.size(), blocks * 8));
83 return {};
84}
85/** @} */
86
87/**
88 * @addtogroup convert
89 * @{
90 */
91template <>
93 return convertVia<Color::RGBA8888, Color::ETC1>(std::move(src));
94}
95/** @} */
96
97}
Result< Image< Color::ETC1 > > Convert< Color::RGBA8888, Color::ETC1 >(Image< Color::RGBA8888 > src)
Definition etc1.cpp:92
Result< void > Move< Color::RGBA8888, Color::ETC1 >(Bytes src, std::span< uint8_t > dst, Size size)
Definition etc1.cpp:64
#define HAIO_TRY(name, expr)
#define HAIO_FAIL(why, message)
Result< Image< To > > convertVia(Image< From > src)
std::expected< T, Error > Result
std::span< const uint8_t > Bytes