Browse Source

Remove PCX rendering code

We no longer render PCX
pull/5084/head
Gleb Mazovetskiy 4 years ago
parent
commit
1cdd76b617
  1. 2
      Source/CMakeLists.txt
  2. 34
      Source/engine/pcx_sprite.cpp
  3. 171
      Source/engine/pcx_sprite.hpp
  4. 122
      Source/engine/render/common_impl.h
  5. 49
      Source/engine/render/pcx_render.cpp
  6. 31
      Source/engine/render/pcx_render.hpp
  7. 4
      Source/utils/pcx_to_cl2.hpp

2
Source/CMakeLists.txt

@ -104,7 +104,6 @@ set(libdevilutionx_SRCS
engine/load_pcx.cpp
engine/palette.cpp
engine/path.cpp
engine/pcx_sprite.cpp
engine/random.cpp
engine/surface.cpp
engine/trn.cpp
@ -112,7 +111,6 @@ set(libdevilutionx_SRCS
engine/render/automap_render.cpp
engine/render/cl2_render.cpp
engine/render/dun_render.cpp
engine/render/pcx_render.cpp
engine/render/scrollrt.cpp
engine/render/text_render.cpp

34
Source/engine/pcx_sprite.cpp

@ -1,34 +0,0 @@
#include "engine/pcx_sprite.hpp"
namespace devilution {
std::unique_ptr<uint32_t[]> OwnedPcxSpriteSheet::calculateFrameOffsets(PcxSprite sprite, uint16_t numFrames)
{
uint16_t frameHeight = sprite.height() / numFrames;
std::unique_ptr<uint32_t[]> frameOffsets { new uint32_t[numFrames] };
frameOffsets[0] = 0;
const unsigned width = sprite.width();
const unsigned srcSkip = width % 2;
const uint8_t *data = sprite.data();
for (unsigned frame = 1; frame < numFrames; ++frame) {
for (unsigned y = 0; y < frameHeight; ++y) {
for (unsigned x = 0; x < width;) {
constexpr uint8_t PcxMaxSinglePixel = 0xBF;
const uint8_t byte = *data++;
if (byte <= PcxMaxSinglePixel) {
++x;
continue;
}
constexpr uint8_t PcxRunLengthMask = 0x3F;
const uint8_t runLength = (byte & PcxRunLengthMask);
++data;
x += runLength;
}
data += srcSkip;
}
frameOffsets[frame] = static_cast<uint32_t>(data - sprite.data());
}
return frameOffsets;
}
} // namespace devilution

171
Source/engine/pcx_sprite.hpp

@ -1,171 +0,0 @@
#pragma once
#include <cstdint>
#include <memory>
#include <utility>
#include "utils/stdcompat/optional.hpp"
namespace devilution {
class OwnedPcxSprite;
class OwnedPcxSpriteSheet;
/**
* @brief An 8-bit PCX sprite.
*/
class PcxSprite {
public:
PcxSprite(const uint8_t *data, uint16_t width, uint16_t height, std::optional<uint8_t> transparentColor = std::nullopt)
: data_(data)
, width_(width)
, height_(height)
, transparent_color_(transparentColor)
{
}
explicit PcxSprite(const OwnedPcxSprite &owned);
[[nodiscard]] const uint8_t *data() const
{
return data_;
}
[[nodiscard]] uint16_t width() const
{
return width_;
}
[[nodiscard]] uint16_t height() const
{
return height_;
}
[[nodiscard]] std::optional<uint8_t> transparentColor() const
{
return transparent_color_;
}
private:
const uint8_t *data_;
uint16_t width_;
uint16_t height_;
std::optional<uint8_t> transparent_color_;
};
class OwnedPcxSprite {
public:
OwnedPcxSprite(std::unique_ptr<uint8_t[]> &&data, uint16_t width, uint16_t height, std::optional<uint8_t> transparentColor = std::nullopt)
: data_(std::move(data))
, width_(width)
, height_(height)
, transparent_color_(transparentColor)
{
}
OwnedPcxSprite(OwnedPcxSprite &&) noexcept = default;
OwnedPcxSprite &operator=(OwnedPcxSprite &&) noexcept = default;
private:
std::unique_ptr<uint8_t[]> data_;
uint16_t width_;
uint16_t height_;
std::optional<uint8_t> transparent_color_;
friend class PcxSprite;
friend class OwnedPcxSpriteSheet;
};
inline PcxSprite::PcxSprite(const OwnedPcxSprite &owned)
: PcxSprite(owned.data_.get(), owned.width_, owned.height_, owned.transparent_color_)
{
}
/**
* @brief An 8-bit PCX sprite sheet consisting of vertically stacked frames.
*/
class PcxSpriteSheet {
public:
PcxSpriteSheet(const uint8_t *data, const uint32_t *frameOffsets, uint16_t numFrames, uint16_t width, uint16_t frameHeight, std::optional<uint8_t> transparentColor = std::nullopt)
: data_(data)
, frame_offsets_(frameOffsets)
, num_frames_(numFrames)
, width_(width)
, frame_height_(frameHeight)
, transparent_color_(transparentColor)
{
}
explicit PcxSpriteSheet(const OwnedPcxSpriteSheet &owned);
[[nodiscard]] PcxSprite sprite(uint16_t frame) const
{
return PcxSprite { data_ + frame_offsets_[frame], width_, frame_height_, transparent_color_ };
}
[[nodiscard]] uint16_t numFrames() const
{
return num_frames_;
}
[[nodiscard]] uint16_t width() const
{
return width_;
}
[[nodiscard]] uint16_t frameHeight() const
{
return frame_height_;
}
private:
const uint8_t *data_;
const uint32_t *frame_offsets_;
uint16_t num_frames_;
uint16_t width_;
uint16_t frame_height_;
std::optional<uint8_t> transparent_color_;
};
class OwnedPcxSpriteSheet {
public:
OwnedPcxSpriteSheet(std::unique_ptr<uint8_t[]> &&data, std::unique_ptr<uint32_t[]> &&frameOffsets, uint16_t numFrames, uint16_t width, uint16_t frameHeight, std::optional<uint8_t> transparentColor = std::nullopt)
: data_(std::move(data))
, frame_offsets_(std::move(frameOffsets))
, num_frames_(numFrames)
, width_(width)
, frame_height_(frameHeight)
, transparent_color_(transparentColor)
{
}
OwnedPcxSpriteSheet(OwnedPcxSprite &&sprite, uint16_t numFrames)
: OwnedPcxSpriteSheet(
std::move(sprite.data_),
calculateFrameOffsets(PcxSprite { sprite.data_.get(), sprite.width_, sprite.height_ }, numFrames),
numFrames, sprite.width_, sprite.height_ / numFrames, sprite.transparent_color_)
{
}
OwnedPcxSpriteSheet(OwnedPcxSpriteSheet &&) noexcept = default;
OwnedPcxSpriteSheet &operator=(OwnedPcxSpriteSheet &&) noexcept = default;
private:
static std::unique_ptr<uint32_t[]> calculateFrameOffsets(PcxSprite sprite, uint16_t numFrames);
std::unique_ptr<uint8_t[]> data_;
std::unique_ptr<uint32_t[]> frame_offsets_;
uint16_t num_frames_;
uint16_t width_;
uint16_t frame_height_;
std::optional<uint8_t> transparent_color_;
friend class PcxSpriteSheet;
};
inline PcxSpriteSheet::PcxSpriteSheet(const OwnedPcxSpriteSheet &owned)
: PcxSpriteSheet(owned.data_.get(), owned.frame_offsets_.get(), owned.num_frames_, owned.width_, owned.frame_height_, owned.transparent_color_)
{
}
} // namespace devilution

122
Source/engine/render/common_impl.h

@ -59,17 +59,6 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT SkipSize GetSkipSize(int_fast16_t overrun, i
using GetBlitCommandFn = BlitCommand (*)(const uint8_t *src);
template <GetBlitCommandFn GetBlitCommand>
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT const uint8_t *SkipRestOfLine(const uint8_t *src, unsigned remainingWidth)
{
while (remainingWidth > 0) {
const BlitCommand cmd = GetBlitCommand(src);
src = cmd.srcEnd;
remainingWidth -= cmd.length;
}
return src;
}
template <GetBlitCommandFn GetBlitCommand>
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT const uint8_t *SkipRestOfLineWithOverrun(
const uint8_t *src, int_fast16_t srcWidth, SkipSize &skipSize)
@ -104,16 +93,6 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT int_fast16_t SkipLinesForRenderBackwardsWith
return skipSize.xOffset;
}
template <GetBlitCommandFn GetBlitCommand>
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void SkipLinesForRenderForwards(Point &position, RenderSrcForwards &src, unsigned lineEndPadding)
{
while (position.y < 0 && src.height != 0) {
src.begin = SkipRestOfLine<GetBlitCommand>(src.begin, src.width) + lineEndPadding;
++position.y;
--src.height;
}
}
template <GetBlitCommandFn GetBlitCommand, typename BlitFn>
void DoRenderBackwardsClipY(
const Surface &out, Point position, RenderSrcBackwards src, BlitFn &&blitFn)
@ -235,107 +214,6 @@ void DoRenderBackwards(
}
}
template <
GetBlitCommandFn GetBlitCommand,
typename BlitFn,
typename TransformBlitCommandFn>
void DoRenderForwardsClipY(
const Surface &out, Point position, RenderSrcForwards src,
BlitFn &&blitFn, TransformBlitCommandFn &&transformBlitCommandFn)
{
// Even padding byte is specific to PCX which is the only renderer that uses this function currently.
const unsigned srcLineEndPadding = src.width % 2;
SkipLinesForRenderForwards<GetBlitCommand>(position, src, srcLineEndPadding);
src.height = static_cast<uint_fast16_t>(std::min<int_fast16_t>(out.h() - position.y, src.height));
const auto dstSkip = static_cast<unsigned>(out.pitch());
uint8_t *dst = &out[position];
for (unsigned y = 0; y < src.height; y++) {
for (unsigned x = 0; x < src.width;) {
BlitCommand cmd = GetBlitCommand(src.begin);
cmd = transformBlitCommandFn(cmd);
blitFn(cmd, dst + x, src.begin + 1);
src.begin = cmd.srcEnd;
x += cmd.length;
}
src.begin += srcLineEndPadding;
dst += dstSkip;
}
}
template <
GetBlitCommandFn GetBlitCommand,
typename BlitFn,
typename TransformBlitCommandFn>
void DoRenderForwardsClipXY(
const Surface &out, Point position, RenderSrcForwards src, ClipX clipX,
BlitFn &&blitFn, TransformBlitCommandFn &&transformBlitCommandFn)
{
const unsigned srcLineEndPadding = src.width % 2;
SkipLinesForRenderForwards<GetBlitCommand>(position, src, srcLineEndPadding);
src.height = static_cast<uint_fast16_t>(std::min<int_fast16_t>(out.h() - position.y, src.height));
position.x += static_cast<int>(clipX.left);
const auto dstSkip = static_cast<unsigned>(out.pitch() - clipX.width);
uint8_t *dst = &out[position];
for (unsigned y = 0; y < src.height; y++) {
// 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;
auto remainingLeftClip = clipX.left;
while (remainingLeftClip > 0) {
BlitCommand cmd = GetBlitCommand(src.begin);
if (static_cast<int_fast16_t>(cmd.length) > remainingLeftClip) {
const uint_fast16_t overshoot = cmd.length - remainingLeftClip;
cmd.length = std::min<unsigned>(overshoot, remainingWidth);
cmd = transformBlitCommandFn(cmd);
blitFn(cmd, dst, src.begin + 1 + remainingLeftClip);
src.begin = cmd.srcEnd;
dst += cmd.length;
remainingWidth -= static_cast<int_fast16_t>(overshoot);
break;
}
src.begin = cmd.srcEnd;
remainingLeftClip -= cmd.length;
}
while (remainingWidth > 0) {
BlitCommand cmd = GetBlitCommand(src.begin);
const unsigned unclippedLength = cmd.length;
cmd = transformBlitCommandFn(cmd);
cmd.length = std::min<unsigned>(cmd.length, remainingWidth);
blitFn(cmd, dst, src.begin + 1);
src.begin = cmd.srcEnd;
dst += cmd.length;
remainingWidth -= unclippedLength; // result can be negative
}
src.begin = SkipRestOfLine<GetBlitCommand>(src.begin, clipX.right + remainingWidth) + srcLineEndPadding;
dst += dstSkip;
}
}
template <
GetBlitCommandFn GetBlitCommand,
typename BlitFn,
typename TransformBlitCommandFn>
void DoRenderForwards(
const Surface &out, Point position, const uint8_t *src, unsigned srcWidth, unsigned srcHeight,
BlitFn &&blitFn, TransformBlitCommandFn &&transformBlitCommandFn)
{
if (position.y >= out.h() || position.y + srcHeight <= 0)
return;
const ClipX clipX = CalculateClipX(position.x, srcWidth, out);
if (clipX.width <= 0)
return;
RenderSrcForwards srcForForwards { src, static_cast<uint_fast16_t>(srcWidth), static_cast<uint_fast16_t>(srcHeight) };
if (static_cast<unsigned>(clipX.width) == srcWidth) {
DoRenderForwardsClipY<GetBlitCommand>(
out, position, srcForForwards, std::forward<BlitFn>(blitFn), std::forward<TransformBlitCommandFn>(transformBlitCommandFn));
} else {
DoRenderForwardsClipXY<GetBlitCommand>(
out, position, srcForForwards, clipX, std::forward<BlitFn>(blitFn), std::forward<TransformBlitCommandFn>(transformBlitCommandFn));
}
}
template <bool North, bool West, bool South, bool East>
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderOutlineForPixel(uint8_t *dst, int dstPitch, uint8_t color)
{

49
Source/engine/render/pcx_render.cpp

@ -1,49 +0,0 @@
#include "engine/render/pcx_render.hpp"
#include <algorithm>
#include <cstring>
#include "engine/render/common_impl.h"
#include "utils/log.hpp"
namespace devilution {
namespace {
constexpr uint8_t PcxMaxSinglePixel = 0xBF;
constexpr uint8_t PcxRunLengthMask = 0x3F;
BlitCommand PcxGetBlitCommand(const uint8_t *src)
{
const uint8_t value = *src++;
if (value <= PcxMaxSinglePixel)
return BlitCommand { BlitType::Pixel, src, 1, value };
const uint8_t runLength = value & PcxRunLengthMask;
const uint8_t color = *src++;
return BlitCommand { BlitType::Fill, src, runLength, color };
}
} // namespace
void RenderPcxSprite(const Surface &out, PcxSprite sprite, Point position)
{
if (sprite.transparentColor()) {
DoRenderForwards<PcxGetBlitCommand>(out, position, sprite.data(), sprite.width(), sprite.height(), BlitDirect {},
TransformBlitCommandTransparentColor { *sprite.transparentColor() });
} else {
DoRenderForwards<PcxGetBlitCommand>(out, position, sprite.data(), sprite.width(), sprite.height(), BlitDirect {},
TransformBlitCommandNoop);
}
}
void RenderPcxSpriteWithColorMap(const Surface &out, PcxSprite sprite, Point position, const std::array<uint8_t, 256> &colorMap)
{
if (sprite.transparentColor()) {
DoRenderForwards<PcxGetBlitCommand>(out, position, sprite.data(), sprite.width(), sprite.height(), BlitWithMap { colorMap.data() },
TransformBlitCommandTransparentColor { *sprite.transparentColor() });
} else {
DoRenderForwards<PcxGetBlitCommand>(out, position, sprite.data(), sprite.width(), sprite.height(), BlitWithMap { colorMap.data() },
TransformBlitCommandNoop);
}
}
} // namespace devilution

31
Source/engine/render/pcx_render.hpp

@ -1,31 +0,0 @@
#pragma once
#include <array>
#include <cstdint>
#include "engine/pcx_sprite.hpp"
#include "engine/point.hpp"
#include "engine/surface.hpp"
namespace devilution {
/**
* @brief Renders a PCX sprite to surface.
*
* @param out Output surface.
* @param sprite Source sprite.
* @param position Top-left position of the sprite on the surface.
*/
void RenderPcxSprite(const Surface &out, PcxSprite sprite, Point position);
/**
* @brief Renders a PCX sprite to surface, translating the colors per the given map.
*
* @param out Output surface.
* @param sprite Source sprite.
* @param position Top-left position of the sprite on the surface.
* @param colorMap Palette translation map.
*/
void RenderPcxSpriteWithColorMap(const Surface &out, PcxSprite sprite, Point position, const std::array<uint8_t, 256> &colorMap);
} // namespace devilution

4
Source/utils/pcx_to_cl2.hpp

@ -9,8 +9,8 @@
namespace devilution {
/** @brief Loads a PCX file as a CL2 sprite.
*
/**
* @brief Loads a PCX file as a CL2 sprite.
*
* @param handle A non-null SDL_RWops handle. Closed by this function.
* @param numFramesOrFrameHeight Pass a positive value with the number of frames, or the frame height as a negative value.

Loading…
Cancel
Save