Browse Source

Remove CEL rendering code

We no longer render CEL
pull/4987/head
Gleb Mazovetskiy 4 years ago committed by Anders Jenbo
parent
commit
43a5d91074
  1. 1
      Source/CMakeLists.txt
  2. 10
      Source/engine/load_cel.cpp
  3. 6
      Source/engine/load_cel.hpp
  4. 534
      Source/engine/render/cel_render.cpp
  5. 116
      Source/engine/render/cel_render.hpp
  6. 6
      Source/engine/render/cl2_render.cpp
  7. 105
      Source/engine/render/common_impl.h

1
Source/CMakeLists.txt

@ -110,7 +110,6 @@ set(libdevilutionx_SRCS
engine/trn.cpp
engine/render/automap_render.cpp
engine/render/cel_render.cpp
engine/render/cl2_render.cpp
engine/render/dun_render.cpp
engine/render/pcx_render.cpp

10
Source/engine/load_cel.cpp

@ -10,16 +10,6 @@
namespace devilution {
OwnedCelSprite LoadCel(const char *pszName, uint16_t width)
{
return OwnedCelSprite(LoadFileInMem(pszName), width);
}
OwnedCelSprite LoadCel(const char *pszName, const uint16_t *widths)
{
return OwnedCelSprite(LoadFileInMem(pszName), widths);
}
OwnedCelSprite LoadCelAsCl2(const char *pszName, uint16_t width)
{
size_t size;

6
Source/engine/load_cel.hpp

@ -6,12 +6,6 @@
namespace devilution {
/**
* @brief Loads a Cel sprite and sets its width
*/
OwnedCelSprite LoadCel(const char *pszName, uint16_t width);
OwnedCelSprite LoadCel(const char *pszName, const uint16_t *widths);
OwnedCelSprite LoadCelAsCl2(const char *pszName, uint16_t width);
OwnedCelSprite LoadCelAsCl2(const char *pszName, const uint16_t *widths);

534
Source/engine/render/cel_render.cpp

@ -1,534 +0,0 @@
/**
* @file cel_render.cpp
*
* CEL rendering.
*/
#include "engine/render/cel_render.hpp"
#include <cstdint>
#include <cstring>
#include "engine/cel_header.hpp"
#include "engine/palette.h"
#include "engine/render/common_impl.h"
#include "engine/render/scrollrt.h"
#include "engine/trn.hpp"
#include "options.h"
#include "utils/attributes.h"
namespace devilution {
namespace {
constexpr bool IsCelTransparent(uint8_t control)
{
constexpr uint8_t CelTransparentMin = 0x80;
return control >= CelTransparentMin;
}
constexpr uint8_t GetCelTransparentWidth(uint8_t control)
{
return -static_cast<std::int8_t>(control);
}
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT BlitCommand CelGetBlitCommand(const uint8_t *src)
{
const uint8_t control = *src++;
if (IsCelTransparent(control))
return BlitCommand { BlitType::Transparent, src, GetCelTransparentWidth(control), 0 };
return BlitCommand { BlitType::Pixels, src + control, control, 0 };
}
template <bool North, bool West, bool South, bool East, bool SkipColorIndexZero>
uint8_t *RenderCelOutlinePixelsCheckFirstColumn(
uint8_t *dst, int dstPitch, int dstX,
const uint8_t *src, uint8_t width, uint8_t color)
{
if (dstX == -1) {
RenderOutlineForPixel</*North=*/false, /*West=*/false, /*South=*/false, East, SkipColorIndexZero>(
dst++, dstPitch, *src++, color);
--width;
}
if (width > 0) {
RenderOutlineForPixel<North, /*West=*/false, South, East, SkipColorIndexZero>(dst++, dstPitch, *src++, color);
--width;
}
if (width > 0) {
RenderOutlineForPixels<North, West, South, East, SkipColorIndexZero>(dst, dstPitch, width, src, color);
dst += width;
}
return dst;
}
template <bool North, bool West, bool South, bool East, bool SkipColorIndexZero>
uint8_t *RenderCelOutlinePixelsCheckLastColumn(
uint8_t *dst, int dstPitch, int dstX, int dstW,
const uint8_t *src, uint8_t width, uint8_t color)
{
const bool lastPixel = dstX < dstW && width >= 1;
const bool oobPixel = dstX + width > dstW;
const int numSpecialPixels = (lastPixel ? 1 : 0) + (oobPixel ? 1 : 0);
if (width > numSpecialPixels) {
width -= numSpecialPixels;
RenderOutlineForPixels<North, West, South, East, SkipColorIndexZero>(dst, dstPitch, width, src, color);
src += width;
dst += width;
}
if (lastPixel)
RenderOutlineForPixel<North, West, South, /*East=*/false, SkipColorIndexZero>(dst++, dstPitch, *src++, color);
if (oobPixel)
RenderOutlineForPixel</*North=*/false, West, /*South=*/false, /*East=*/false, SkipColorIndexZero>(dst++, dstPitch, *src++, color);
return dst;
}
template <bool SkipColorIndexZero, bool North, bool West, bool South, bool East, bool CheckFirstColumn, bool CheckLastColumn>
uint8_t *RenderCelOutlinePixels(
uint8_t *dst, int dstPitch, int dstX, int dstW,
const uint8_t *src, uint8_t width, uint8_t color)
{
if (CheckFirstColumn && dstX <= 0) {
return RenderCelOutlinePixelsCheckFirstColumn<North, West, South, East, SkipColorIndexZero>(
dst, dstPitch, dstX, src, width, color);
}
if (CheckLastColumn && dstX + width >= dstW) {
return RenderCelOutlinePixelsCheckLastColumn<North, West, South, East, SkipColorIndexZero>(
dst, dstPitch, dstX, dstW, src, width, color);
}
RenderOutlineForPixels<North, West, South, East, SkipColorIndexZero>(dst, dstPitch, width, src, color);
return dst + width;
}
template <bool SkipColorIndexZero, bool North, bool West, bool South, bool East,
bool ClipWidth = false, bool CheckFirstColumn = false, bool CheckLastColumn = false>
const uint8_t *RenderCelOutlineRowClipped( // NOLINT(readability-function-cognitive-complexity,misc-no-recursion)
const Surface &out, Point position, const uint8_t *src, ClipX clipX, uint8_t color)
{
int_fast16_t remainingWidth = clipX.width;
uint8_t v;
auto *dst = &out[position];
const auto dstPitch = out.pitch();
const auto dstW = out.w();
if (ClipWidth) {
auto remainingLeftClip = clipX.left;
while (remainingLeftClip > 0) {
v = static_cast<uint8_t>(*src++);
if (!IsCelTransparent(v)) {
if (v > remainingLeftClip) {
RenderCelOutlinePixels<SkipColorIndexZero, North, West, South, East, CheckFirstColumn, CheckLastColumn>(
dst, dstPitch, position.x, dstW, src, v - remainingLeftClip, color);
}
src += v;
} else {
v = GetCelTransparentWidth(v);
}
remainingLeftClip -= v;
}
dst -= static_cast<int>(remainingLeftClip);
position.x -= static_cast<int>(remainingLeftClip);
remainingWidth += remainingLeftClip;
}
while (remainingWidth > 0) {
v = static_cast<uint8_t>(*src++);
if (!IsCelTransparent(v)) {
dst = RenderCelOutlinePixels<SkipColorIndexZero, North, West, South, East, CheckFirstColumn, CheckLastColumn>(
dst, dstPitch, position.x, dstW, src,
std::min(remainingWidth, static_cast<int_fast16_t>(v)), color);
src += v;
} else {
v = GetCelTransparentWidth(v);
dst += v;
}
remainingWidth -= v;
position.x += v;
}
src = SkipRestOfLine<CelGetBlitCommand>(src, clipX.right + remainingWidth);
return src;
}
template <bool SkipColorIndexZero>
void RenderCelOutlineClippedY(const Surface &out, Point position, RenderSrcBackwards src, uint8_t color) // NOLINT(readability-function-cognitive-complexity)
{
// Skip the bottom clipped lines.
const auto dstHeight = out.h();
SkipLinesForRenderBackwards<CelGetBlitCommand>(position, src, dstHeight);
if (src.begin == src.end)
return;
const ClipX clipX = { 0, 0, static_cast<decltype(ClipX {}.width)>(src.width) };
if (position.y == dstHeight) {
// After-bottom line - can only draw north.
src.begin = RenderCelOutlineRowClipped<SkipColorIndexZero, /*North=*/true, /*West=*/false, /*South=*/false, /*East=*/false>(
out, position, src.begin, clipX, color);
--position.y;
}
if (src.begin == src.end)
return;
if (position.y + 1 == dstHeight) {
// Bottom line - cannot draw south.
src.begin = RenderCelOutlineRowClipped<SkipColorIndexZero, /*North=*/true, /*West=*/true, /*South=*/false, /*East=*/true>(
out, position, src.begin, clipX, color);
--position.y;
}
while (position.y > 0 && src.begin != src.end) {
src.begin = RenderCelOutlineRowClipped<SkipColorIndexZero, /*North=*/true, /*West=*/true, /*South=*/true, /*East=*/true>(
out, position, src.begin, clipX, color);
--position.y;
}
if (src.begin == src.end)
return;
if (position.y == 0) {
src.begin = RenderCelOutlineRowClipped<SkipColorIndexZero, /*North=*/false, /*West=*/true, /*South=*/true, /*East=*/true>(
out, position, src.begin, clipX, color);
--position.y;
}
if (src.begin == src.end)
return;
if (position.y == -1) {
// Special case: the top of the sprite is 1px below the last line, render just the outline above.
RenderCelOutlineRowClipped<SkipColorIndexZero, /*North=*/false, /*West=*/false, /*South=*/true, /*East=*/false>(
out, position, src.begin, clipX, color);
}
}
template <bool SkipColorIndexZero>
void RenderCelOutlineClippedXY(const Surface &out, Point position, RenderSrcBackwards src, uint8_t color) // NOLINT(readability-function-cognitive-complexity)
{
// Skip the bottom clipped lines.
const auto dstHeight = out.h();
SkipLinesForRenderBackwards<CelGetBlitCommand>(position, src, dstHeight);
if (src.begin == src.end)
return;
ClipX clipX = CalculateClipX(position.x, src.width, out);
if (clipX.width < 0)
return;
if (clipX.left > 0) {
--clipX.left, ++clipX.width;
} else if (clipX.right > 0) {
--clipX.right, ++clipX.width;
}
position.x += static_cast<int>(clipX.left);
if (position.y == dstHeight) {
// After-bottom line - can only draw north.
if (position.x <= 0) {
src.begin = RenderCelOutlineRowClipped<SkipColorIndexZero, /*North=*/true, /*West=*/false, /*South=*/false, /*East=*/false,
/*ClipWidth=*/true, /*CheckFirstColumn=*/true, /*CheckLastColumn=*/false>(out, position, src.begin, clipX, color);
} else if (position.x + clipX.width >= out.w()) {
src.begin = RenderCelOutlineRowClipped<SkipColorIndexZero, /*North=*/true, /*West=*/false, /*South=*/false, /*East=*/false,
/*ClipWidth=*/true, /*CheckFirstColumn=*/false, /*CheckLastColumn=*/true>(out, position, src.begin, clipX, color);
} else {
src.begin = RenderCelOutlineRowClipped<SkipColorIndexZero, /*North=*/true, /*West=*/false, /*South=*/false, /*East=*/false,
/*ClipWidth=*/true>(out, position, src.begin, clipX, color);
}
--position.y;
}
if (src.begin == src.end)
return;
if (position.y + 1 == dstHeight) {
// Bottom line - cannot draw south.
if (position.x <= 0) {
src.begin = RenderCelOutlineRowClipped<SkipColorIndexZero, /*North=*/true, /*West=*/true, /*South=*/false, /*East=*/true,
/*ClipWidth=*/true, /*CheckFirstColumn=*/true, /*CheckLastColumn=*/false>(
out, position, src.begin, clipX, color);
} else if (position.x + clipX.width >= out.w()) {
src.begin = RenderCelOutlineRowClipped<SkipColorIndexZero, /*North=*/true, /*West=*/true, /*South=*/false, /*East=*/true,
/*ClipWidth=*/true, /*CheckFirstColumn=*/false, /*CheckLastColumn=*/true>(
out, position, src.begin, clipX, color);
} else {
src.begin = RenderCelOutlineRowClipped<SkipColorIndexZero, /*North=*/true, /*West=*/true, /*South=*/false, /*East=*/true,
/*ClipWidth=*/true>(
out, position, src.begin, clipX, color);
}
--position.y;
}
if (position.x <= 0) {
while (position.y > 0 && src.begin != src.end) {
src.begin = RenderCelOutlineRowClipped<SkipColorIndexZero, /*North=*/true, /*West=*/true, /*South=*/true, /*East=*/true,
/*ClipWidth=*/true, /*CheckFirstColumn=*/true, /*CheckLastColumn=*/false>(
out, position, src.begin, clipX, color);
--position.y;
}
} else if (position.x + clipX.width >= out.w()) {
while (position.y > 0 && src.begin != src.end) {
src.begin = RenderCelOutlineRowClipped<SkipColorIndexZero, /*North=*/true, /*West=*/true, /*South=*/true, /*East=*/true,
/*ClipWidth=*/true, /*CheckFirstColumn=*/false, /*CheckLastColumn=*/true>(
out, position, src.begin, clipX, color);
--position.y;
}
} else {
while (position.y > 0 && src.begin != src.end) {
src.begin = RenderCelOutlineRowClipped<SkipColorIndexZero, /*North=*/true, /*West=*/true, /*South=*/true, /*East=*/true,
/*ClipWidth=*/true>(
out, position, src.begin, clipX, color);
--position.y;
}
}
if (src.begin == src.end)
return;
if (position.y == 0) {
if (position.x <= 0) {
src.begin = RenderCelOutlineRowClipped<SkipColorIndexZero, /*North=*/false, /*West=*/true, /*South=*/true, /*East=*/true,
/*ClipWidth=*/true, /*CheckFirstColumn=*/true, /*CheckLastColumn=*/false>(
out, position, src.begin, clipX, color);
} else if (position.x + clipX.width >= out.w()) {
src.begin = RenderCelOutlineRowClipped<SkipColorIndexZero, /*North=*/false, /*West=*/true, /*South=*/true, /*East=*/true,
/*ClipWidth=*/true, /*CheckFirstColumn=*/false, /*CheckLastColumn=*/true>(
out, position, src.begin, clipX, color);
} else {
src.begin = RenderCelOutlineRowClipped<SkipColorIndexZero, /*North=*/false, /*West=*/true, /*South=*/true, /*East=*/true,
/*ClipWidth=*/true>(
out, position, src.begin, clipX, color);
}
--position.y;
}
if (src.begin == src.end)
return;
if (position.y == -1) {
// After-bottom line - can only draw south.
if (position.x <= 0) {
src.begin = RenderCelOutlineRowClipped<SkipColorIndexZero, /*North=*/false, /*West=*/false, /*South=*/true, /*East=*/false,
/*ClipWidth=*/true, /*CheckFirstColumn=*/true, /*CheckLastColumn=*/false>(out, position, src.begin, clipX, color);
} else if (position.x + clipX.width >= out.w()) {
src.begin = RenderCelOutlineRowClipped<SkipColorIndexZero, /*North=*/false, /*West=*/false, /*South=*/true, /*East=*/false,
/*ClipWidth=*/true, /*CheckFirstColumn=*/false, /*CheckLastColumn=*/true>(out, position, src.begin, clipX, color);
} else {
src.begin = RenderCelOutlineRowClipped<SkipColorIndexZero, /*North=*/false, /*West=*/false, /*South=*/true, /*East=*/false,
/*ClipWidth=*/true>(out, position, src.begin, clipX, color);
}
}
}
template <bool SkipColorIndexZero>
void RenderCelOutline(const Surface &out, Point position, const uint8_t *src, std::size_t srcSize,
std::size_t srcWidth, uint8_t color)
{
RenderSrcBackwards srcForBackwards { src, src + srcSize, static_cast<uint_fast16_t>(srcWidth) };
if (position.x > 0 && position.x + static_cast<int>(srcWidth) < static_cast<int>(out.w())) {
RenderCelOutlineClippedY<SkipColorIndexZero>(out, position, srcForBackwards, color);
} else {
RenderCelOutlineClippedXY<SkipColorIndexZero>(out, position, srcForBackwards, color);
}
}
/**
* @brief Blit CEL sprite to the given buffer, checks for drawing outside the buffer.
* @param out Target buffer
* @param position Target buffer coordinate
* @param pRLEBytes CEL pixel stream (run-length encoded)
* @param nDataSize Size of CEL in bytes
* @param nWidth Width of sprite in pixels
*/
void CelBlitSafeTo(const Surface &out, Point position, const byte *pRLEBytes, int nDataSize, int nWidth)
{
assert(pRLEBytes != nullptr);
DoRenderBackwards</*TransparentCommandCanCrossLines=*/false, CelGetBlitCommand>(
out, position, reinterpret_cast<const uint8_t *>(pRLEBytes), nDataSize, nWidth, BlitDirect {});
}
/**
* @brief Same as CelBlitLightSafe, with blended transparency applied
* @param out Target buffer
* @param position Target buffer coordinate
* @param pRLEBytes CEL pixel stream (run-length encoded)
* @param nDataSize Size of CEL in bytes
* @param nWidth Width of sprite in pixels
* @param tbl Palette translation table
*/
void CelBlitLightBlendedSafeTo(const Surface &out, Point position, const byte *pRLEBytes, int nDataSize, int nWidth, const uint8_t *tbl)
{
assert(pRLEBytes != nullptr);
if (tbl == nullptr)
tbl = &LightTables[LightTableIndex * 256];
DoRenderBackwards</*TransparentCommandCanCrossLines=*/false, CelGetBlitCommand>(
out, position, reinterpret_cast<const uint8_t *>(pRLEBytes), nDataSize, nWidth, BlitBlendedWithMap { tbl });
}
void RenderCelWithLightTable(const Surface &out, Point position, const byte *src, std::size_t srcSize, std::size_t srcWidth, const uint8_t *tbl)
{
DoRenderBackwards</*TransparentCommandCanCrossLines=*/false, CelGetBlitCommand>(
out, position, reinterpret_cast<const uint8_t *>(src), srcSize, srcWidth, BlitWithMap { tbl });
}
/**
* @brief Blit CEL sprite, and apply lighting, to the given buffer, checks for drawing outside the buffer
* @param out Target buffer
* @param position Target buffer coordinate
* @param pRLEBytes CEL pixel stream (run-length encoded)
* @param nDataSize Size of CEL in bytes
* @param nWidth Width of sprite in pixels
* @param tbl Palette translation table
*/
void CelBlitLightSafeTo(const Surface &out, Point position, const byte *pRLEBytes, int nDataSize, int nWidth, uint8_t *tbl)
{
assert(pRLEBytes != nullptr);
if (tbl == nullptr)
tbl = &LightTables[LightTableIndex * 256];
RenderCelWithLightTable(out, position, pRLEBytes, nDataSize, nWidth, tbl);
}
} // namespace
void CelDrawTo(const Surface &out, Point position, CelSprite cel, int frame)
{
int nDataSize;
const auto *pRLEBytes = CelGetFrame(cel.Data(), frame, &nDataSize);
CelBlitSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame));
}
void CelClippedDrawTo(const Surface &out, Point position, CelSprite cel, int frame)
{
int nDataSize;
const auto *pRLEBytes = CelGetFrameClipped(cel.Data(), frame, &nDataSize);
CelBlitSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame));
}
void CelDrawLightTo(const Surface &out, Point position, CelSprite cel, int frame, uint8_t *tbl)
{
int nDataSize;
const auto *pRLEBytes = CelGetFrame(cel.Data(), frame, &nDataSize);
if (LightTableIndex != 0 || tbl != nullptr)
CelBlitLightSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame), tbl);
else
CelBlitSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame));
}
void CelClippedDrawLightTo(const Surface &out, Point position, CelSprite cel, int frame)
{
int nDataSize;
const auto *pRLEBytes = CelGetFrameClipped(cel.Data(), frame, &nDataSize);
if (LightTableIndex != 0)
CelBlitLightSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame), nullptr);
else
CelBlitSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame));
}
void CelDrawLightRedTo(const Surface &out, Point position, CelSprite cel, int frame)
{
int nDataSize;
const auto *pRLEBytes = CelGetFrameClipped(cel.Data(), frame, &nDataSize);
RenderCelWithLightTable(out, position, pRLEBytes, nDataSize, cel.Width(frame), GetInfravisionTRN());
}
void CelDrawItem(const Item &item, const Surface &out, Point position, CelSprite cel, int frame)
{
bool usable = item._iStatFlag;
if (!usable) {
CelDrawLightRedTo(out, position, cel, frame);
} else {
CelClippedDrawTo(out, position, cel, frame);
}
}
void CelClippedBlitLightTransTo(const Surface &out, Point position, CelSprite cel, int frame)
{
int nDataSize;
const byte *pRLEBytes = CelGetFrameClipped(cel.Data(), frame, &nDataSize);
if (cel_transparency_active) {
CelBlitLightBlendedSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame), nullptr);
} else if (LightTableIndex != 0)
CelBlitLightSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame), nullptr);
else
CelBlitSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame));
}
void CelDrawUnsafeTo(const Surface &out, Point position, CelSprite cel, int frame)
{
int srcSize;
const auto *srcBegin = reinterpret_cast<const uint8_t *>(CelGetFrame(cel.Data(), frame, &srcSize));
RenderSrcBackwards src { srcBegin, srcBegin + srcSize, cel.Width(frame) };
DoRenderBackwardsClipY</*TransparentCommandCanCrossLines=*/false, &CelGetBlitCommand>(
out, position, src, BlitDirect {});
}
void CelBlitOutlineTo(const Surface &out, uint8_t col, Point position, CelSprite cel, int frame, bool skipColorIndexZero)
{
int nDataSize;
const uint8_t *src = reinterpret_cast<const uint8_t *>(CelGetFrameClipped(cel.Data(), frame, &nDataSize));
if (skipColorIndexZero)
RenderCelOutline<true>(out, position, src, nDataSize, cel.Width(frame), col);
else
RenderCelOutline<false>(out, position, src, nDataSize, cel.Width(frame), col);
}
std::pair<int, int> MeasureSolidHorizontalBounds(CelSprite cel, int frame)
{
int nDataSize;
const byte *src = CelGetFrameClipped(cel.Data(), frame, &nDataSize);
const auto *end = &src[nDataSize];
const int celWidth = cel.Width(frame);
int xBegin = celWidth;
int xEnd = 0;
while (src < end) {
int xCur = 0;
while (xCur < celWidth) {
const auto val = static_cast<uint8_t>(*src++);
if (IsCelTransparent(val)) {
const int width = GetCelTransparentWidth(val);
xCur += width;
} else {
xBegin = std::min(xBegin, xCur);
xCur += val;
xEnd = std::max(xEnd, xCur);
src += val;
}
}
if (xBegin == 0 && xEnd == celWidth)
break;
}
return { xBegin, xEnd };
}
void CelApplyTrans(byte *p, const std::array<uint8_t, 256> &translation)
{
assert(p != nullptr);
const uint32_t numFrames = LoadLE32(p);
const byte *frameOffsets = p + 4;
p += 4 * (2 + static_cast<size_t>(numFrames));
uint32_t frameEnd = LoadLE32(&frameOffsets[0]);
for (uint32_t i = 0; i < numFrames; ++i) {
const uint32_t frameBegin = frameEnd;
frameEnd = LoadLE32(&frameOffsets[4 * (static_cast<size_t>(i) + 1)]);
const byte *end = p + (frameEnd - frameBegin);
const bool frameHasHeader = static_cast<uint8_t>(*p) == 0;
if (frameHasHeader) {
constexpr uint32_t FrameHeaderSize = 5 * 2;
p += FrameHeaderSize;
}
while (p != end) {
const auto val = static_cast<uint8_t>(*p++);
if (IsCelTransparent(val)) {
continue;
}
for (unsigned i = 0; i < val; ++i) {
const auto color = static_cast<uint8_t>(*p);
*p++ = static_cast<byte>(translation[color]);
}
}
}
}
} // namespace devilution

116
Source/engine/render/cel_render.hpp

@ -1,116 +0,0 @@
/**
* @file cel_render.hpp
*
* CEL rendering.
*/
#pragma once
#include <utility>
#include "engine.h"
#include "engine/cel_sprite.hpp"
#include "engine/point.hpp"
#include "items.h"
namespace devilution {
/**
* Returns a pair of X coordinates containing the start (inclusive) and end (exclusive)
* of fully transparent columns in the sprite.
*/
std::pair<int, int> MeasureSolidHorizontalBounds(CelSprite cel, int frame = 0);
/**
* @brief Apply the color swaps to a CEL sprite
*
* @param p CEL buffer
* @param translation Palette translation table
*/
void CelApplyTrans(byte *p, const std::array<uint8_t, 256> &translation);
/**
* @brief Blit CEL sprite to the back buffer at the given coordinates
* @param out Target buffer
* @param position Target buffer coordinate
* @param cel CEL sprite
* @param frame CEL frame number
*/
void CelDrawTo(const Surface &out, Point position, CelSprite cel, int frame);
/**
* @brief Blit CEL sprite to the given buffer, does not perform bounds-checking.
* @param out Target buffer
* @param position Coordinate in the target buffer coordinate
* @param cel CEL sprite
* @param frame CEL frame number
*/
void CelDrawUnsafeTo(const Surface &out, Point position, CelSprite cel, int frame);
/**
* @brief Same as CelDrawTo but with the option to skip parts of the top and bottom of the sprite
* @param out Target buffer
* @param position Target buffer coordinate
* @param cel CEL sprite
* @param frame CEL frame number
*/
void CelClippedDrawTo(const Surface &out, Point position, CelSprite cel, int frame);
/**
* @brief Blit CEL sprite, and apply lighting, to the back buffer at the given coordinates
* @param out Target buffer
* @param position Target buffer coordinate
* @param cel CEL sprite
* @param frame CEL frame number
* @param tbl Palette translation table
*/
void CelDrawLightTo(const Surface &out, Point position, CelSprite cel, int frame, uint8_t *tbl);
/**
* @brief Same as CelDrawLightTo but with the option to skip parts of the top and bottom of the sprite
* @param out Target buffer
* @param position Target buffer coordinate
* @param cel CEL sprite
* @param frame CEL frame number
*/
void CelClippedDrawLightTo(const Surface &out, Point position, CelSprite cel, int frame);
/**
* @brief Same as CelBlitLightSafeTo but with transparency applied
* @param out Target buffer
* @param position Target buffer coordinate
* @param cel CEL sprite
* @param frame CEL frame number
*/
void CelClippedBlitLightTransTo(const Surface &out, Point position, CelSprite cel, int frame);
/**
* @brief Blit CEL sprite, and apply lighting, to the back buffer at the given coordinates, translated to a red hue
* @param out Target buffer
* @param position Target buffer coordinate
* @param cel CEL sprite
* @param frame CEL frame number
*/
void CelDrawLightRedTo(const Surface &out, Point position, CelSprite cel, int frame);
/**
* @brief Blit item's CEL sprite recolored red if not usable, normal if usable
* @param item Item being drawn
* @param out Target buffer
* @param position Target buffer coordinate
* @param cel CEL sprite
* @param frame CEL frame number
*/
void CelDrawItem(const Item &item, const Surface &out, Point position, CelSprite cel, int frame);
/**
* @brief Blit a solid colder shape one pixel larger than the given sprite shape, to the target buffer at the given coordianates
* @param out Target buffer
* @param col Color index from current palette
* @param position Target buffer coordinate
* @param cel CEL sprite
* @param frame CEL frame number
* @param skipColorIndexZero If true, color in index 0 will be treated as transparent (these are typically used for shadows in sprites)
*/
void Cl2DrawOutline(const Surface &out, uint8_t col, Point position, CelSprite cel, int frame, bool skipColorIndexZero = true);
} // namespace devilution

6
Source/engine/render/cl2_render.cpp

@ -71,7 +71,7 @@ BlitCommand Cl2GetBlitCommand(const uint8_t *src)
*/
void Cl2Blit(const Surface &out, Point position, const byte *pRLEBytes, int nDataSize, int nWidth)
{
DoRenderBackwards</*TransparentCommandCanCrossLines=*/true, Cl2GetBlitCommand>(
DoRenderBackwards<Cl2GetBlitCommand>(
out, position, reinterpret_cast<const uint8_t *>(pRLEBytes), nDataSize, nWidth, BlitDirect {});
}
@ -87,13 +87,13 @@ void Cl2Blit(const Surface &out, Point position, const byte *pRLEBytes, int nDat
*/
void Cl2BlitTRN(const Surface &out, Point position, const byte *pRLEBytes, int nDataSize, int nWidth, uint8_t *pTable)
{
DoRenderBackwards</*TransparentCommandCanCrossLines=*/true, Cl2GetBlitCommand>(
DoRenderBackwards<Cl2GetBlitCommand>(
out, position, reinterpret_cast<const uint8_t *>(pRLEBytes), nDataSize, nWidth, BlitWithMap { pTable });
}
void Cl2BlitBlendedTRN(const Surface &out, Point position, const byte *pRLEBytes, int nDataSize, int nWidth, uint8_t *pTable)
{
DoRenderBackwards</*TransparentCommandCanCrossLines=*/true, Cl2GetBlitCommand>(
DoRenderBackwards<Cl2GetBlitCommand>(
out, position, reinterpret_cast<const uint8_t *>(pRLEBytes), nDataSize, nWidth, BlitBlendedWithMap { pTable });
}

105
Source/engine/render/common_impl.h

@ -90,16 +90,6 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT const uint8_t *SkipRestOfLineWithOverrun(
return src;
}
template <GetBlitCommandFn GetBlitCommand>
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void SkipLinesForRenderBackwards(
Point &position, RenderSrcBackwards &src, int_fast16_t dstHeight)
{
while (position.y >= dstHeight && src.begin != src.end) {
src.begin = SkipRestOfLine<GetBlitCommand>(src.begin, src.width);
--position.y;
}
}
// Returns the horizontal overrun.
template <GetBlitCommandFn GetBlitCommand>
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT int_fast16_t SkipLinesForRenderBackwardsWithOverrun(
@ -124,20 +114,12 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void SkipLinesForRenderForwards(Point &posit
}
}
template <
bool TransparentCommandCanCrossLines,
GetBlitCommandFn GetBlitCommand,
typename BlitFn>
template <GetBlitCommandFn GetBlitCommand, typename BlitFn>
void DoRenderBackwardsClipY(
const Surface &out, Point position, RenderSrcBackwards src, BlitFn &&blitFn)
{
// Skip the bottom clipped lines.
int_fast16_t xOffset;
if (TransparentCommandCanCrossLines) {
xOffset = SkipLinesForRenderBackwardsWithOverrun<GetBlitCommand>(position, src, out.h());
} else {
SkipLinesForRenderBackwards<GetBlitCommand>(position, src, out.h());
}
int_fast16_t xOffset = SkipLinesForRenderBackwardsWithOverrun<GetBlitCommand>(position, src, out.h());
if (src.begin >= src.end)
return;
@ -145,11 +127,8 @@ void DoRenderBackwardsClipY(
const auto *dstBegin = out.begin();
const int dstPitch = out.pitch();
while (src.begin != src.end && dst >= dstBegin) {
auto remainingWidth = static_cast<int_fast16_t>(src.width);
if (TransparentCommandCanCrossLines) {
remainingWidth -= xOffset;
dst += xOffset;
}
auto remainingWidth = static_cast<int_fast16_t>(src.width) - xOffset;
dst += xOffset;
while (remainingWidth > 0) {
BlitCommand cmd = GetBlitCommand(src.begin);
blitFn(cmd, dst, src.begin + 1);
@ -159,32 +138,22 @@ void DoRenderBackwardsClipY(
}
dst -= dstPitch + src.width - remainingWidth;
if (TransparentCommandCanCrossLines) {
if (remainingWidth < 0) {
const auto skipSize = GetSkipSize(-remainingWidth, static_cast<int_fast16_t>(src.width));
xOffset = skipSize.xOffset;
dst -= skipSize.wholeLines * dstPitch;
} else {
xOffset = 0;
}
if (remainingWidth < 0) {
const auto skipSize = GetSkipSize(-remainingWidth, static_cast<int_fast16_t>(src.width));
xOffset = skipSize.xOffset;
dst -= skipSize.wholeLines * dstPitch;
} else {
xOffset = 0;
}
}
}
template <
bool TransparentCommandCanCrossLines,
GetBlitCommandFn GetBlitCommand,
typename BlitFn>
template <GetBlitCommandFn GetBlitCommand, typename BlitFn>
void DoRenderBackwardsClipXY(
const Surface &out, Point position, RenderSrcBackwards src, ClipX clipX, BlitFn &&blitFn)
{
// Skip the bottom clipped lines.
int_fast16_t xOffset;
if (TransparentCommandCanCrossLines) {
xOffset = SkipLinesForRenderBackwardsWithOverrun<GetBlitCommand>(position, src, out.h());
} else {
SkipLinesForRenderBackwards<GetBlitCommand>(position, src, out.h());
}
int_fast16_t xOffset = SkipLinesForRenderBackwardsWithOverrun<GetBlitCommand>(position, src, out.h());
if (src.begin >= src.end)
return;
@ -197,13 +166,10 @@ void DoRenderBackwardsClipXY(
// Skip initial src if clipping on the left.
// Handles overshoot, i.e. when the RLE segment goes into the unclipped area.
int_fast16_t remainingWidth = clipX.width;
int_fast16_t remainingLeftClip = clipX.left;
if (TransparentCommandCanCrossLines) {
remainingLeftClip -= xOffset;
if (remainingLeftClip < 0) {
dst += std::min<unsigned>(remainingWidth, -remainingLeftClip);
remainingWidth += remainingLeftClip;
}
int_fast16_t remainingLeftClip = clipX.left - xOffset;
if (remainingLeftClip < 0) {
dst += std::min<unsigned>(remainingWidth, -remainingLeftClip);
remainingWidth += remainingLeftClip;
}
while (remainingLeftClip > 0) {
BlitCommand cmd = GetBlitCommand(src.begin);
@ -234,31 +200,24 @@ void DoRenderBackwardsClipXY(
// Set dst to (position.y - 1, position.x)
dst -= dstPitch + clipX.width;
if (TransparentCommandCanCrossLines) {
// `remainingWidth` can be negative, in which case it is the amount of pixels
// that the source has overran the line.
remainingWidth += clipX.right;
SkipSize skipSize { 0, 0 };
if (remainingWidth > 0) {
skipSize.xOffset = static_cast<int_fast16_t>(src.width) - remainingWidth;
src.begin = SkipRestOfLineWithOverrun<GetBlitCommand>(
src.begin, static_cast<int_fast16_t>(src.width), skipSize);
--skipSize.wholeLines;
} else if (remainingWidth < 0) {
skipSize = GetSkipSize(-remainingWidth, static_cast<int_fast16_t>(src.width));
}
xOffset = skipSize.xOffset;
dst -= dstPitch * skipSize.wholeLines;
} else {
src.begin = SkipRestOfLine<GetBlitCommand>(src.begin, clipX.right + remainingWidth);
// `remainingWidth` can be negative, in which case it is the amount of pixels
// that the source has overran the line.
remainingWidth += clipX.right;
SkipSize skipSize { 0, 0 };
if (remainingWidth > 0) {
skipSize.xOffset = static_cast<int_fast16_t>(src.width) - remainingWidth;
src.begin = SkipRestOfLineWithOverrun<GetBlitCommand>(
src.begin, static_cast<int_fast16_t>(src.width), skipSize);
--skipSize.wholeLines;
} else if (remainingWidth < 0) {
skipSize = GetSkipSize(-remainingWidth, static_cast<int_fast16_t>(src.width));
}
xOffset = skipSize.xOffset;
dst -= dstPitch * skipSize.wholeLines;
}
}
template <
bool TransparentCommandCanCrossLines,
GetBlitCommandFn GetBlitCommand,
typename BlitFn>
template <GetBlitCommandFn GetBlitCommand, typename BlitFn>
void DoRenderBackwards(
const Surface &out, Point position, const uint8_t *src, size_t srcSize, unsigned srcWidth,
BlitFn &&blitFn)
@ -268,10 +227,10 @@ void DoRenderBackwards(
return;
RenderSrcBackwards srcForBackwards { src, src + srcSize, static_cast<uint_fast16_t>(srcWidth) };
if (static_cast<std::size_t>(clipX.width) == srcWidth) {
DoRenderBackwardsClipY<TransparentCommandCanCrossLines, GetBlitCommand>(
DoRenderBackwardsClipY<GetBlitCommand>(
out, position, srcForBackwards, std::forward<BlitFn>(blitFn));
} else {
DoRenderBackwardsClipXY<TransparentCommandCanCrossLines, GetBlitCommand>(
DoRenderBackwardsClipXY<GetBlitCommand>(
out, position, srcForBackwards, clipX, std::forward<BlitFn>(blitFn));
}
}

Loading…
Cancel
Save