Add support for raw images

This commit is contained in:
Ted John 2018-05-12 13:58:08 +01:00
parent 73a4d1400d
commit 0f0bb021d6
3 changed files with 95 additions and 44 deletions

View File

@ -23,12 +23,6 @@
using namespace OpenRCT2::Drawing;
using ImportResult = ImageImporter::ImportResult;
struct RLECode
{
uint8 NumPixels{};
uint8 OffsetX{};
};
constexpr sint32 PALETTE_TRANSPARENT = -1;
ImportResult ImageImporter::Import(
@ -48,18 +42,34 @@ ImportResult ImageImporter::Import(
throw std::invalid_argument("Image is not palletted, it has bit depth of " + std::to_string(image.Depth));
}
if (!(flags & IMPORT_FLAGS::RLE))
{
throw std::invalid_argument("Only RLE image import is currently supported.");
}
const auto width = image.Width;
const auto height = image.Height;
const auto pixels = image.Pixels.data();
auto buffer = (uint8 *)std::malloc((height * 2) + (width * height * 16));
std::memset(buffer, 0, (height * 2) + (width * height * 16));
auto yOffsets = (uint16 *)buffer;
auto pixels = GetPixels(image.Pixels.data(), width, height, flags, mode);
auto [buffer, bufferLength] = flags & IMPORT_FLAGS::RLE ?
EncodeRLE(pixels.data(), width, height) :
EncodeRaw(pixels.data(), width, height);
rct_g1_element outElement;
outElement.offset = (uint8 *)buffer;
outElement.width = width;
outElement.height = height;
outElement.flags = (flags & IMPORT_FLAGS::RLE ? G1_FLAG_RLE_COMPRESSION : G1_FLAG_BMP);
outElement.x_offset = offsetX;
outElement.y_offset = offsetY;
outElement.zoomed_offset = 0;
ImportResult result;
result.Element = outElement;
result.Buffer = buffer;
result.BufferLength = bufferLength;
return result;
}
std::vector<sint32> ImageImporter::GetPixels(const uint8 * pixels, uint32 width, uint32 height, IMPORT_FLAGS flags, IMPORT_MODE mode)
{
std::vector<sint32> buffer;
buffer.reserve(width * height);
// A larger range is needed for proper dithering
auto palettedSrc = pixels;
@ -78,18 +88,8 @@ ImportResult ImageImporter::Import(
}
}
auto dst = buffer + (height * 2);
for (uint32 y = 0; y < height; y++)
{
yOffsets[y] = (uint16)(dst - buffer);
auto previousCode = (RLECode *)nullptr;
auto currentCode = (RLECode *)dst;
dst += 2;
auto startX = 0;
auto npixels = 0;
bool pushRun = false;
for (uint32 x = 0; x < width; x++)
{
sint32 paletteIndex;
@ -110,13 +110,63 @@ ImportResult ImageImporter::Import(
rgbaSrc += 4;
palettedSrc += 1;
buffer.push_back(paletteIndex);
}
}
return buffer;
}
std::tuple<void *, size_t> ImageImporter::EncodeRaw(const sint32 * pixels, uint32 width, uint32 height)
{
auto bufferLength = width * height;
auto buffer = (uint8 *)std::malloc(bufferLength);
for (size_t i = 0; i < bufferLength; i++)
{
auto p = pixels[i];
buffer[i] = (p == PALETTE_TRANSPARENT ? 0 : (uint8)p);
}
return std::make_tuple(buffer, bufferLength);
}
std::tuple<void *, size_t> ImageImporter::EncodeRLE(const sint32 * pixels, uint32 width, uint32 height)
{
struct RLECode
{
uint8 NumPixels{};
uint8 OffsetX{};
};
auto src = pixels;
auto buffer = (uint8 *)std::malloc((height * 2) + (width * height * 16));
if (buffer == nullptr)
{
throw std::bad_alloc();
}
std::memset(buffer, 0, (height * 2) + (width * height * 16));
auto yOffsets = (uint16 *)buffer;
auto dst = buffer + (height * 2);
for (uint32 y = 0; y < height; y++)
{
yOffsets[y] = (uint16)(dst - buffer);
auto previousCode = (RLECode *)nullptr;
auto currentCode = (RLECode *)dst;
dst += 2;
auto startX = 0;
auto npixels = 0;
bool pushRun = false;
for (uint32 x = 0; x < width; x++)
{
sint32 paletteIndex = *src++;
if (paletteIndex == PALETTE_TRANSPARENT)
{
if (npixels != 0)
{
x--;
rgbaSrc -= 4;
palettedSrc -= 1;
src--;
pushRun = true;
}
}
@ -173,22 +223,12 @@ ImportResult ImageImporter::Import(
}
auto bufferLength = (size_t)(dst - buffer);
buffer = (uint8 *)realloc(buffer, bufferLength);
rct_g1_element outElement;
outElement.offset = buffer;
outElement.width = width;
outElement.height = height;
outElement.flags = G1_FLAG_RLE_COMPRESSION;
outElement.x_offset = offsetX;
outElement.y_offset = offsetY;
outElement.zoomed_offset = 0;
ImportResult result;
result.Element = outElement;
result.Buffer = buffer;
result.BufferLength = bufferLength;
return result;
buffer = (uint8 * )realloc(buffer, bufferLength);
if (buffer == nullptr)
{
throw std::bad_alloc();
}
return std::make_tuple(buffer, bufferLength);
}
sint32 ImageImporter::CalculatePaletteIndex(IMPORT_MODE mode, sint16 * rgbaSrc, sint32 x, sint32 y, sint32 width, sint32 height)

View File

@ -15,6 +15,7 @@
#pragma endregion
#include <string_view>
#include <tuple>
#include "../core/Imaging.h"
#include "Drawing.h"
@ -59,6 +60,10 @@ namespace OpenRCT2::Drawing
private:
static const PaletteBGRA StandardPalette[256];
static std::vector<sint32> GetPixels(const uint8 * pixels, uint32 width, uint32 height, IMPORT_FLAGS flags, IMPORT_MODE mode);
static std::tuple<void *, size_t> EncodeRaw(const sint32 * pixels, uint32 width, uint32 height);
static std::tuple<void *, size_t> EncodeRLE(const sint32 * pixels, uint32 width, uint32 height);
static sint32 CalculatePaletteIndex(IMPORT_MODE mode, sint16 * rgbaSrc, sint32 x, sint32 y, sint32 width, sint32 height);
static sint32 GetPaletteIndex(const PaletteBGRA * palette, sint16 * colour);
static bool IsTransparentPixel(const sint16 * colour);

View File

@ -347,15 +347,21 @@ namespace ObjectJsonHelpers
auto path = GetString(el, "path");
auto x = GetInteger(el, "x");
auto y = GetInteger(el, "y");
auto raw = (GetString(el, "format") == "raw");
std::vector<rct_g1_element> result;
try
{
auto flags = ImageImporter::IMPORT_FLAGS::NONE;
if (!raw)
{
flags = (ImageImporter::IMPORT_FLAGS)(flags | ImageImporter::IMPORT_FLAGS::RLE);
}
auto imageData = context->GetData(path);
auto image = Imaging::ReadFromBuffer(imageData, IMAGE_FORMAT::PNG_32);
ImageImporter importer;
auto importResult = importer.Import(image, 0, 0, ImageImporter::IMPORT_FLAGS::RLE);
auto importResult = importer.Import(image, 0, 0, flags);
auto g1Element = importResult.Element;
g1Element.x_offset = x;
g1Element.y_offset = y;