Browse Source

Move PCX code to utils/pcx.cpp

pull/4518/head
Gleb Mazovetskiy 4 years ago
parent
commit
5eeaa76a75
  1. 1
      Source/CMakeLists.txt
  2. 72
      Source/DiabloUI/art.cpp
  3. 88
      Source/utils/pcx.cpp
  4. 9
      Source/utils/pcx.hpp

1
Source/CMakeLists.txt

@ -107,6 +107,7 @@ set(libdevilutionx_SRCS
utils/language.cpp
utils/logged_fstream.cpp
utils/paths.cpp
utils/pcx.cpp
utils/sdl_bilinear_scale.cpp
utils/sdl_thread.cpp
utils/utf8.cpp

72
Source/DiabloUI/art.cpp

@ -13,78 +13,6 @@
namespace devilution {
namespace {
constexpr size_t PcxHeaderSize = 128;
constexpr unsigned NumPaletteColors = 256;
bool LoadPcxMeta(SDL_RWops *handle, int &width, int &height, std::uint8_t &bpp)
{
PCXHeader pcxhdr;
if (SDL_RWread(handle, &pcxhdr, PcxHeaderSize, 1) == 0) {
return false;
}
width = SDL_SwapLE16(pcxhdr.Xmax) - SDL_SwapLE16(pcxhdr.Xmin) + 1;
height = SDL_SwapLE16(pcxhdr.Ymax) - SDL_SwapLE16(pcxhdr.Ymin) + 1;
bpp = pcxhdr.BitsPerPixel;
return true;
}
bool LoadPcxPixelsAndPalette(SDL_RWops *handle, int width, int height, std::uint8_t bpp,
uint8_t *buffer, std::ptrdiff_t bufferPitch, SDL_Color *palette)
{
std::ptrdiff_t pixelDataSize = SDL_RWsize(handle);
if (pixelDataSize < 0) {
// Unable to determine size, or an error occurred.
return false;
}
// SDL_RWsize gives the total size of the file however we've already read the header from an earlier call to
// LoadPcxMeta, so we only need to read the remainder of the file.
const std::size_t readSize = pixelDataSize - PcxHeaderSize;
std::unique_ptr<uint8_t[]> fileBuffer { new uint8_t[readSize] };
if (SDL_RWread(handle, fileBuffer.get(), readSize, 1) == 0) {
return false;
}
const std::ptrdiff_t xSkip = bufferPitch - width;
const std::ptrdiff_t srcSkip = width % 2;
uint8_t *dataPtr = fileBuffer.get();
for (int j = 0; j < height; j++) {
for (int x = 0; x < width;) {
constexpr std::uint8_t PcxMaxSinglePixel = 0xBF;
const std::uint8_t byte = *dataPtr++;
if (byte <= PcxMaxSinglePixel) {
*buffer++ = byte;
++x;
continue;
}
constexpr std::uint8_t PcxRunLengthMask = 0x3F;
const std::uint8_t runLength = (byte & PcxRunLengthMask);
std::memset(buffer, *dataPtr++, runLength);
buffer += runLength;
x += runLength;
}
dataPtr += srcSkip;
buffer += xSkip;
}
if (palette != nullptr && bpp == 8) {
// The file has a 256 color palette that needs to be loaded.
[[maybe_unused]] constexpr unsigned PcxPaletteSeparator = 0x0C;
assert(*dataPtr == PcxPaletteSeparator); // sanity check the delimiter
++dataPtr;
auto *out = palette;
for (unsigned i = 0; i < NumPaletteColors; ++i) {
out->r = *dataPtr++;
out->g = *dataPtr++;
out->b = *dataPtr++;
#ifndef USE_SDL1
out->a = SDL_ALPHA_OPAQUE;
#endif
++out;
}
}
return true;
}
Uint32 GetPcxSdlPixelFormat(unsigned bpp)
{

88
Source/utils/pcx.cpp

@ -0,0 +1,88 @@
#include "utils/pcx.hpp"
#include <cstring>
#include <memory>
#include "appfat.h"
#ifdef USE_SDL1
#include "utils/sdl2_to_1_2_backports.h"
#endif
namespace devilution {
namespace {
constexpr unsigned NumPaletteColors = 256;
constexpr unsigned PcxPaletteSize = 1 + NumPaletteColors * 3;
} // namespace
bool LoadPcxMeta(SDL_RWops *handle, int &width, int &height, uint8_t &bpp)
{
PCXHeader pcxhdr;
if (SDL_RWread(handle, &pcxhdr, PcxHeaderSize, 1) == 0) {
return false;
}
width = SDL_SwapLE16(pcxhdr.Xmax) - SDL_SwapLE16(pcxhdr.Xmin) + 1;
height = SDL_SwapLE16(pcxhdr.Ymax) - SDL_SwapLE16(pcxhdr.Ymin) + 1;
bpp = pcxhdr.BitsPerPixel;
return true;
}
bool LoadPcxPixelsAndPalette(SDL_RWops *handle, int width, int height, std::uint8_t bpp,
uint8_t *buffer, std::ptrdiff_t bufferPitch, SDL_Color *palette)
{
std::ptrdiff_t pixelDataSize = SDL_RWsize(handle);
if (pixelDataSize < 0) {
// Unable to determine size, or an error occurred.
return false;
}
// SDL_RWsize gives the total size of the file however we've already read the header from an earlier call to
// LoadPcxMeta, so we only need to read the remainder of the file.
const std::size_t readSize = pixelDataSize - PcxHeaderSize;
std::unique_ptr<uint8_t[]> fileBuffer { new uint8_t[readSize] };
if (SDL_RWread(handle, fileBuffer.get(), readSize, 1) == 0) {
return false;
}
const std::ptrdiff_t xSkip = bufferPitch - width;
const std::ptrdiff_t srcSkip = width % 2;
uint8_t *dataPtr = fileBuffer.get();
for (int j = 0; j < height; j++) {
for (int x = 0; x < width;) {
constexpr std::uint8_t PcxMaxSinglePixel = 0xBF;
const std::uint8_t byte = *dataPtr++;
if (byte <= PcxMaxSinglePixel) {
*buffer++ = byte;
++x;
continue;
}
constexpr std::uint8_t PcxRunLengthMask = 0x3F;
const std::uint8_t runLength = (byte & PcxRunLengthMask);
std::memset(buffer, *dataPtr++, runLength);
buffer += runLength;
x += runLength;
}
dataPtr += srcSkip;
buffer += xSkip;
}
if (palette != nullptr && bpp == 8) {
// The file has a 256 color palette that needs to be loaded.
[[maybe_unused]] constexpr unsigned PcxPaletteSeparator = 0x0C;
assert(*dataPtr == PcxPaletteSeparator); // sanity check the delimiter
++dataPtr;
auto *out = palette;
for (unsigned i = 0; i < NumPaletteColors; ++i) {
out->r = *dataPtr++;
out->g = *dataPtr++;
out->b = *dataPtr++;
#ifndef USE_SDL1
out->a = SDL_ALPHA_OPAQUE;
#endif
++out;
}
}
return true;
}
} // namespace devilution

9
Source/utils/pcx.hpp

@ -1,7 +1,10 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <SDL.h>
namespace devilution {
struct PCXHeader {
@ -25,4 +28,10 @@ struct PCXHeader {
uint8_t Filler[54];
};
static constexpr size_t PcxHeaderSize = 128;
bool LoadPcxMeta(SDL_RWops *handle, int &width, int &height, uint8_t &bpp);
bool LoadPcxPixelsAndPalette(SDL_RWops *handle, int width, int height, std::uint8_t bpp,
uint8_t *buffer, std::ptrdiff_t bufferPitch, SDL_Color *palette);
} // namespace devilution

Loading…
Cancel
Save