You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
97 lines
2.5 KiB
97 lines
2.5 KiB
#include "utils/cl2_to_clx.hpp" |
|
|
|
#include <cstring> |
|
|
|
#include "utils/endian.hpp" |
|
|
|
namespace devilution { |
|
|
|
namespace { |
|
|
|
constexpr bool IsCl2Opaque(uint8_t control) |
|
{ |
|
constexpr uint8_t Cl2OpaqueMin = 0x80; |
|
return control >= Cl2OpaqueMin; |
|
} |
|
|
|
constexpr uint8_t GetCl2OpaquePixelsWidth(uint8_t control) |
|
{ |
|
return -static_cast<std::int8_t>(control); |
|
} |
|
|
|
constexpr bool IsCl2OpaqueFill(uint8_t control) |
|
{ |
|
constexpr uint8_t Cl2FillMax = 0xBE; |
|
return control <= Cl2FillMax; |
|
} |
|
|
|
constexpr uint8_t GetCl2OpaqueFillWidth(uint8_t control) |
|
{ |
|
constexpr uint8_t Cl2FillEnd = 0xBF; |
|
return static_cast<int_fast16_t>(Cl2FillEnd - control); |
|
} |
|
|
|
size_t CountCl2FramePixels(const uint8_t *src, const uint8_t *srcEnd) |
|
{ |
|
size_t numPixels = 0; |
|
while (src != srcEnd) { |
|
uint8_t val = *src++; |
|
if (IsCl2Opaque(val)) { |
|
if (IsCl2OpaqueFill(val)) { |
|
numPixels += GetCl2OpaqueFillWidth(val); |
|
++src; |
|
} else { |
|
val = GetCl2OpaquePixelsWidth(val); |
|
numPixels += val; |
|
src += val; |
|
} |
|
} else { |
|
numPixels += val; |
|
} |
|
} |
|
return numPixels; |
|
} |
|
|
|
} // namespace |
|
|
|
uint16_t Cl2ToClx(uint8_t *data, size_t size, PointerOrValue<uint16_t> widthOrWidths) |
|
{ |
|
uint32_t numGroups = 1; |
|
const uint32_t maybeNumFrames = LoadLE32(data); |
|
uint8_t *groupBegin = data; |
|
|
|
// If it is a number of frames, then the last frame offset will be equal to the size of the file. |
|
if (LoadLE32(&data[maybeNumFrames * 4 + 4]) != size) { |
|
// maybeNumFrames is the address of the first group, right after |
|
// the list of group offsets. |
|
numGroups = maybeNumFrames / 4; |
|
} |
|
|
|
for (size_t group = 0; group < numGroups; ++group) { |
|
uint32_t numFrames; |
|
if (numGroups == 1) { |
|
numFrames = maybeNumFrames; |
|
} else { |
|
groupBegin = &data[LoadLE32(&data[group * 4])]; |
|
numFrames = LoadLE32(groupBegin); |
|
} |
|
|
|
uint8_t *frameEnd = &groupBegin[LoadLE32(&groupBegin[4])]; |
|
for (size_t frame = 1; frame <= numFrames; ++frame) { |
|
uint8_t *frameBegin = frameEnd; |
|
frameEnd = &groupBegin[LoadLE32(&groupBegin[4 * (frame + 1)])]; |
|
|
|
constexpr size_t Cl2FrameHeaderSize = 10; |
|
const size_t numPixels = CountCl2FramePixels(frameBegin + Cl2FrameHeaderSize, frameEnd); |
|
|
|
const uint16_t frameWidth = widthOrWidths.HoldsPointer() ? widthOrWidths.AsPointer()[frame - 1] : widthOrWidths.AsValue(); |
|
const uint16_t frameHeight = numPixels / frameWidth; |
|
WriteLE16(&frameBegin[2], frameWidth); |
|
WriteLE16(&frameBegin[4], frameHeight); |
|
memset(&frameBegin[6], 0, 4); |
|
} |
|
} |
|
return numGroups == 1 ? 0 : numGroups; |
|
} |
|
|
|
} // namespace devilution
|
|
|