wowlib 0.0.0
Read & write World of Warcraft client files — a C++26 core
Loading...
Searching...
No Matches
codec.hpp
Go to the documentation of this file.
1#pragma once
2
23
24#include <cstddef>
25#include <cstdint>
26#include <span>
27#include <vector>
28
30
33 inline constexpr std::size_t AlphaDim = 64;
35 inline constexpr std::size_t AlphaTexels = AlphaDim * AlphaDim;
37 inline constexpr std::size_t Alpha4BitBytes = AlphaTexels / 2;
39 inline constexpr std::size_t ShadowBytes = AlphaTexels / 8;
40
45 protected:
50 static void _fixLastRowCol(std::span<std::uint8_t> map) {
51 for (std::size_t r = 0; r < AlphaDim; ++r) map[r * AlphaDim + 63] = map[r * AlphaDim + 62];
52 for (std::size_t c = 0; c < AlphaDim; ++c) map[63 * AlphaDim + c] = map[62 * AlphaDim + c];
53 }
54 };
55
61 public:
63 explicit AlphaMapCodec(AlphaFormat format) noexcept : _format{format} {}
64
72 [[nodiscard]]
73 std::vector<std::uint8_t> decode(std::span<const std::byte> src, bool compressed, bool fixEdges) const {
74 std::vector<std::uint8_t> map;
75 if (compressed) decodeRle(src, map);
76 else if (_format == AlphaFormat::Highres8Bit) decode8Bit(src, map);
77 else decode4Bit(src, map);
78 if (fixEdges) _fixLastRowCol(map);
79 return map;
80 }
81
87 void encode(std::span<const std::uint8_t> map, bool compressed, std::vector<std::byte>& out) const {
88 if (compressed) encodeRle(map, out);
89 else if (_format == AlphaFormat::Highres8Bit) encode8Bit(map, out);
90 else encode4Bit(map, out);
91 }
92
93 protected:
97 void decode4Bit(std::span<const std::byte> src, std::vector<std::uint8_t>& out) const {
98 out.resize(AlphaTexels);
99 for (std::size_t i = 0; i < Alpha4BitBytes && i < src.size(); ++i) {
100 const auto b = std::to_integer<std::uint8_t>(src[i]);
101 out[2 * i] = static_cast<std::uint8_t>((b & 0x0F) * 0x11);
102 out[2 * i + 1] = static_cast<std::uint8_t>((b >> 4) * 0x11);
103 }
104 }
105
109 void decode8Bit(std::span<const std::byte> src, std::vector<std::uint8_t>& out) const {
110 out.resize(AlphaTexels);
111 for (std::size_t i = 0; i < AlphaTexels && i < src.size(); ++i) out[i] = std::to_integer<std::uint8_t>(src[i]);
112 }
113
118 void decodeRle(std::span<const std::byte> src, std::vector<std::uint8_t>& out) const {
119 out.clear();
120 out.reserve(AlphaTexels);
121 std::size_t p = 0;
122 while (out.size() < AlphaTexels && p < src.size()) {
123 const auto control = std::to_integer<std::uint8_t>(src[p++]);
124 const std::size_t count = control & 0x7F;
125 if (control & 0x80) // fill
126 {
127 if (p >= src.size()) break;
128 const auto value = std::to_integer<std::uint8_t>(src[p++]);
129 for (std::size_t k = 0; k < count && out.size() < AlphaTexels; ++k) out.push_back(value);
130 }
131 else // copy
132 {
133 for (std::size_t k = 0; k < count && out.size() < AlphaTexels && p < src.size(); ++k) out.push_back(
134 std::to_integer<std::uint8_t>(src[p++]));
135 }
136 }
137 out.resize(AlphaTexels);
138 }
139
143 void encode4Bit(std::span<const std::uint8_t> map, std::vector<std::byte>& out) const {
144 for (std::size_t i = 0; i < Alpha4BitBytes; ++i) {
145 const auto lo = static_cast<std::uint8_t>(map[2 * i] >> 4);
146 const auto hi = static_cast<std::uint8_t>(map[2 * i + 1] >> 4);
147 out.push_back(static_cast<std::byte>(lo | (hi << 4)));
148 }
149 }
150
154 void encode8Bit(std::span<const std::uint8_t> map, std::vector<std::byte>& out) const {
155 for (std::uint8_t v : map) out.push_back(static_cast<std::byte>(v));
156 }
157
164 void encodeRle(std::span<const std::uint8_t> map, std::vector<std::byte>& out) const {
165 for (std::size_t row = 0; row < AlphaDim; ++row) {
166 const std::uint8_t* r = map.data() + row * AlphaDim;
167 std::size_t i = 0;
168 std::size_t copyStart = AlphaDim + 1; // "none"
169 const auto flushCopy = [&](std::size_t end) {
170 if (copyStart > AlphaDim) return;
171 out.push_back(static_cast<std::byte>(end - copyStart));
172 // copy, count
173 for (std::size_t k = copyStart; k < end; ++k) out.push_back(static_cast<std::byte>(r[k]));
174 copyStart = AlphaDim + 1;
175 };
176 while (i < AlphaDim) {
177 std::size_t run = 1;
178 while (i + run < AlphaDim && r[i + run] == r[i]) ++run;
179 if (run >= 3) {
180 flushCopy(i);
181 out.push_back(static_cast<std::byte>(0x80 | run)); // fill
182 out.push_back(static_cast<std::byte>(r[i]));
183 i += run;
184 }
185 else {
186 if (copyStart > AlphaDim) copyStart = i;
187 ++i;
188 }
189 }
190 flushCopy(AlphaDim);
191 }
192 }
193
194 private:
196 AlphaFormat _format;
197 };
198
204 public:
209 [[nodiscard]]
210 std::vector<std::uint8_t> decode(std::span<const std::byte> src, bool fixEdges) const {
211 std::vector<std::uint8_t> map(AlphaTexels, 0);
212 for (std::size_t i = 0; i < AlphaTexels && i / 8 < src.size(); ++i) {
213 const auto b = std::to_integer<std::uint8_t>(src[i / 8]);
214 map[i] = (b >> (i % 8)) & 1;
215 }
216 if (fixEdges) _fixLastRowCol(map);
217 return map;
218 }
219
223 void encode(std::span<const std::uint8_t> map, std::vector<std::byte>& out) const {
224 for (std::size_t byte = 0; byte < ShadowBytes; ++byte) {
225 std::uint8_t packed = 0;
226 for (std::size_t bit = 0; bit < 8; ++bit)
227 if (map[byte * 8 + bit] & 1) packed |= static_cast<std::uint8_t>(1 << bit);
228 out.push_back(static_cast<std::byte>(packed));
229 }
230 }
231 };
232}
ADT version grids, layout pivots and the alpha-format context.
void encodeRle(std::span< const std::uint8_t > map, std::vector< std::byte > &out) const
RLE-encode 4096 texels one row at a time (runs cannot span rows).
Definition codec.hpp:164
std::vector< std::uint8_t > decode(std::span< const std::byte > src, bool compressed, bool fixEdges) const
Decode one layer's on-disk alpha bytes to the 4096-texel edit surface.
Definition codec.hpp:73
void decode8Bit(std::span< const std::byte > src, std::vector< std::uint8_t > &out) const
Decode a 4096-byte 8-bit map (a straight copy).
Definition codec.hpp:109
void encode4Bit(std::span< const std::uint8_t > map, std::vector< std::byte > &out) const
Encode 4096 texels to a 2048-byte 4-bit map (texel >> 4).
Definition codec.hpp:143
void decode4Bit(std::span< const std::byte > src, std::vector< std::uint8_t > &out) const
Decode a 2048-byte 4-bit map to 4096 texels (nibble * 0x11, LSB first).
Definition codec.hpp:97
void decodeRle(std::span< const std::byte > src, std::vector< std::uint8_t > &out) const
Decode a Blizzard RLE map (8-bit) to 4096 texels.
Definition codec.hpp:118
void encode8Bit(std::span< const std::uint8_t > map, std::vector< std::byte > &out) const
Encode 4096 texels to a 4096-byte 8-bit map (a straight copy).
Definition codec.hpp:154
void encode(std::span< const std::uint8_t > map, bool compressed, std::vector< std::byte > &out) const
Encode a 4096-texel edit surface to its on-disk alpha bytes, appended to out.
Definition codec.hpp:87
AlphaMapCodec(AlphaFormat format) noexcept
Definition codec.hpp:63
The MCSH shadow-map codec: a 512-byte 1-bit bitmap on disk, a 4096-texel 0/1 surface in memory.
Definition codec.hpp:203
std::vector< std::uint8_t > decode(std::span< const std::byte > src, bool fixEdges) const
Decode a 512-byte 1-bit shadow bitmap to 4096 texels (0/1), LSB first.
Definition codec.hpp:210
void encode(std::span< const std::uint8_t > map, std::vector< std::byte > &out) const
Encode 4096 texels (0/1) to a 512-byte 1-bit bitmap, LSB first.
Definition codec.hpp:223
Shared geometry for the 64x64 terrain map codecs: the last-row/column repair the client applies to "u...
Definition codec.hpp:44
static void _fixLastRowCol(std::span< std::uint8_t > map)
Repair an "unfixed" map in place: the last row and column are ignored on disk and the client copies t...
Definition codec.hpp:50
constexpr std::size_t Alpha4BitBytes
The on-disk size of a 4-bit alpha map (4096 / 2 = 2048 bytes).
Definition codec.hpp:37
constexpr std::size_t AlphaDim
The edge length of the decoded square edit surface (64).
Definition codec.hpp:33
constexpr std::size_t ShadowBytes
The on-disk size of a 1-bit shadow bitmap (4096 / 8 = 512 bytes).
Definition codec.hpp:39
constexpr std::size_t AlphaTexels
The texel count of a decoded map (64 * 64 = 4096).
Definition codec.hpp:35
@ Highres8Bit
4096-byte 8-bit alpha maps (the WDT has adt_has_big_alpha or adt_has_height_texturing).