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.

169 lines
4.4 KiB

#pragma once
#include <cstdint>
#include <cstring>
#include "engine/palette.h"
#include "utils/attributes.h"
namespace devilution {
enum class BlitType : uint8_t {
Transparent,
Pixels,
Fill
};
struct BlitCommand {
BlitType type;
const uint8_t *srcEnd; // Pointer past the end of the command.
unsigned length; // Number of pixels this command will write.
uint8_t color; // For `BlitType::Pixel` and `BlitType::Fill` only.
};
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void BlitFillDirect(uint8_t *dst, unsigned length, uint8_t color)
{
std::memset(dst, color, length);
}
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void BlitPixelsDirect(uint8_t *DVL_RESTRICT dst, const uint8_t *DVL_RESTRICT src, unsigned length)
{
std::memcpy(dst, src, length);
}
struct BlitDirect {
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void operator()(BlitCommand cmd, uint8_t *DVL_RESTRICT dst, const uint8_t *DVL_RESTRICT src)
{
switch (cmd.type) {
case BlitType::Fill:
BlitFillDirect(dst, cmd.length, cmd.color);
return;
case BlitType::Pixels:
BlitPixelsDirect(dst, src, cmd.length);
return;
case BlitType::Transparent:
return;
}
}
};
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void BlitFillWithMap(uint8_t *dst, unsigned length, uint8_t color, const uint8_t *DVL_RESTRICT colorMap)
{
assert(length != 0);
std::memset(dst, colorMap[color], length);
}
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void BlitPixelsWithMap(uint8_t *DVL_RESTRICT dst, const uint8_t *DVL_RESTRICT src, unsigned length, const uint8_t *DVL_RESTRICT colorMap)
{
assert(length != 0);
const uint8_t *end = src + length;
while (src + 3 < end) {
*dst++ = colorMap[*src++];
*dst++ = colorMap[*src++];
*dst++ = colorMap[*src++];
*dst++ = colorMap[*src++];
}
while (src < end) {
*dst++ = colorMap[*src++];
}
}
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void BlitFillBlended(uint8_t *dst, unsigned length, uint8_t color)
{
assert(length != 0);
const uint8_t *end = dst + length;
const std::array<uint8_t, 256> &tbl = paletteTransparencyLookup[color];
while (dst + 3 < end) {
*dst = tbl[*dst];
++dst;
*dst = tbl[*dst];
++dst;
*dst = tbl[*dst];
++dst;
*dst = tbl[*dst];
++dst;
}
while (dst < end) {
*dst = tbl[*dst];
++dst;
}
}
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void BlitPixelsBlended(uint8_t *DVL_RESTRICT dst, const uint8_t *DVL_RESTRICT src, unsigned length)
{
assert(length != 0);
const uint8_t *end = src + length;
while (src + 3 < end) {
*dst = paletteTransparencyLookup[*dst][*src++];
++dst;
*dst = paletteTransparencyLookup[*dst][*src++];
++dst;
*dst = paletteTransparencyLookup[*dst][*src++];
++dst;
*dst = paletteTransparencyLookup[*dst][*src++];
++dst;
}
while (src < end) {
*dst = paletteTransparencyLookup[*dst][*src++];
++dst;
}
}
struct BlitWithMap {
const uint8_t *DVL_RESTRICT colorMap;
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void operator()(BlitCommand cmd, uint8_t *DVL_RESTRICT dst, const uint8_t *DVL_RESTRICT src) const
{
switch (cmd.type) {
case BlitType::Fill:
BlitFillWithMap(dst, cmd.length, cmd.color, colorMap);
return;
case BlitType::Pixels:
BlitPixelsWithMap(dst, src, cmd.length, colorMap);
return;
case BlitType::Transparent:
return;
}
}
};
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void BlitPixelsBlendedWithMap(uint8_t *DVL_RESTRICT dst, const uint8_t *DVL_RESTRICT src, unsigned length, const uint8_t *DVL_RESTRICT colorMap)
{
assert(length != 0);
const uint8_t *end = src + length;
while (src + 3 < end) {
*dst = paletteTransparencyLookup[*dst][colorMap[*src++]];
++dst;
*dst = paletteTransparencyLookup[*dst][colorMap[*src++]];
++dst;
*dst = paletteTransparencyLookup[*dst][colorMap[*src++]];
++dst;
*dst = paletteTransparencyLookup[*dst][colorMap[*src++]];
++dst;
}
while (src < end) {
*dst = paletteTransparencyLookup[*dst][colorMap[*src++]];
++dst;
}
}
struct BlitBlendedWithMap {
const uint8_t *colorMap;
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void operator()(BlitCommand cmd, uint8_t *DVL_RESTRICT dst, const uint8_t *DVL_RESTRICT src) const
{
switch (cmd.type) {
case BlitType::Fill:
BlitFillBlended(dst, cmd.length, colorMap[cmd.color]);
return;
case BlitType::Pixels:
BlitPixelsBlendedWithMap(dst, src, cmd.length, colorMap);
return;
case BlitType::Transparent:
return;
}
}
};
} // namespace devilution