mirror of https://github.com/OpenRCT2/OpenRCT2.git
Refactor image importer out into new class
This commit is contained in:
parent
f0348dafb7
commit
bffbf5857d
|
@ -20,16 +20,15 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <jansson.h>
|
#include <jansson.h>
|
||||||
#include "CmdlineSprite.h"
|
#include "CmdlineSprite.h"
|
||||||
#include "drawing/Drawing.h"
|
|
||||||
#include "core/Imaging.h"
|
#include "core/Imaging.h"
|
||||||
|
#include "drawing/Drawing.h"
|
||||||
|
#include "drawing/ImageImporter.h"
|
||||||
#include "localisation/Language.h"
|
#include "localisation/Language.h"
|
||||||
#include "OpenRCT2.h"
|
#include "OpenRCT2.h"
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "util/Util.h"
|
#include "util/Util.h"
|
||||||
|
|
||||||
#define MODE_DEFAULT 0
|
using namespace OpenRCT2::Drawing;
|
||||||
#define MODE_CLOSEST 1
|
|
||||||
#define MODE_DITHERING 2
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
|
@ -254,283 +253,26 @@ static bool sprite_file_export(sint32 spriteIndex, const char *outPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_transparent_pixel(const sint16 *colour){
|
|
||||||
return colour[3] < 128;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if pixel index is an index not used for remapping
|
|
||||||
static bool is_changable_pixel(sint32 palette_index) {
|
|
||||||
if (palette_index == -1)
|
|
||||||
return true;
|
|
||||||
if (palette_index == 0)
|
|
||||||
return false;
|
|
||||||
if (palette_index >= 203 && palette_index < 214)
|
|
||||||
return false;
|
|
||||||
if (palette_index == 226)
|
|
||||||
return false;
|
|
||||||
if (palette_index >= 227 && palette_index < 229)
|
|
||||||
return false;
|
|
||||||
if (palette_index >= 243)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static sint32 get_closest_palette_index(const sint16 *colour){
|
|
||||||
uint32 smallest_error = (uint32)-1;
|
|
||||||
sint32 best_match = -1;
|
|
||||||
|
|
||||||
for (sint32 x = 0; x < 256; x++){
|
|
||||||
if (is_changable_pixel(x)){
|
|
||||||
uint32 error =
|
|
||||||
((sint16)(spriteFilePalette[x].r) - colour[0]) * ((sint16)(spriteFilePalette[x].r) - colour[0]) +
|
|
||||||
((sint16)(spriteFilePalette[x].g) - colour[1]) * ((sint16)(spriteFilePalette[x].g) - colour[1]) +
|
|
||||||
((sint16)(spriteFilePalette[x].b) - colour[2]) * ((sint16)(spriteFilePalette[x].b) - colour[2]);
|
|
||||||
|
|
||||||
if (smallest_error == (uint32)-1 || smallest_error > error){
|
|
||||||
best_match = x;
|
|
||||||
smallest_error = error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return best_match;
|
|
||||||
}
|
|
||||||
|
|
||||||
static sint32 get_palette_index(sint16 *colour)
|
|
||||||
{
|
|
||||||
if (is_transparent_pixel(colour))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
for (sint32 i = 0; i < 256; i++) {
|
|
||||||
if ((sint16)(spriteFilePalette[i].r) != colour[0]) continue;
|
|
||||||
if ((sint16)(spriteFilePalette[i].g) != colour[1]) continue;
|
|
||||||
if ((sint16)(spriteFilePalette[i].b) != colour[2]) continue;
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static bool sprite_file_import(const char *path, sint16 x_offset, sint16 y_offset, bool keep_palette, rct_g1_element *outElement, uint8 **outBuffer, int *outBufferLength, sint32 mode)
|
static bool sprite_file_import(const char *path, sint16 x_offset, sint16 y_offset, bool keep_palette, rct_g1_element *outElement, uint8 **outBuffer, int *outBufferLength, sint32 mode)
|
||||||
{
|
{
|
||||||
Image image;
|
|
||||||
auto format = keep_palette ? IMAGE_FORMAT::PNG : IMAGE_FORMAT::PNG_32;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
image = std::move(Imaging::ReadFromFile(path, format));
|
auto format = keep_palette ? IMAGE_FORMAT::PNG : IMAGE_FORMAT::PNG_32;
|
||||||
|
auto image = Imaging::ReadFromFile(path, format);
|
||||||
|
|
||||||
|
ImageImporter importer;
|
||||||
|
auto result = importer.Import(image, x_offset, y_offset, keep_palette, (ImageImporter::IMPORT_MODE)mode);
|
||||||
|
|
||||||
|
*outElement = result.Element;
|
||||||
|
*outBuffer = (uint8 *)result.Buffer;
|
||||||
|
*outBufferLength = (int)result.BufferLength;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Error reading PNG: %s\n", e.what());
|
fprintf(stderr, "%s\n", e.what());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (image.Width > 256 || image.Height > 256)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Only images 256x256 or less are supported.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keep_palette && (image.Depth != 8))
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Image is not palletted, it has bit depth of %d\n", image.Depth);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto width = image.Width;
|
|
||||||
const auto height = image.Height;
|
|
||||||
const auto pixels = image.Pixels.data();
|
|
||||||
|
|
||||||
memcpy(spriteFilePalette, CmdlineSprite::_standardPalette, 256 * 4);
|
|
||||||
|
|
||||||
uint8 *buffer = (uint8 *)malloc((height * 2) + (width * height * 16));
|
|
||||||
memset(buffer, 0, (height * 2) + (width * height * 16));
|
|
||||||
uint16 *yOffsets = (uint16*)buffer;
|
|
||||||
|
|
||||||
// A larger range is needed for proper dithering
|
|
||||||
uint8 *palettedSrc = pixels;
|
|
||||||
sint16 *rgbaSrc = keep_palette? nullptr : (sint16 *)malloc(height * width * 4 * 2);
|
|
||||||
sint16 *rgbaSrc_orig = rgbaSrc;
|
|
||||||
if (!keep_palette)
|
|
||||||
{
|
|
||||||
for (uint32 x = 0; x < height * width * 4; x++)
|
|
||||||
{
|
|
||||||
rgbaSrc[x] = (sint16) pixels[x];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8 *dst = buffer + (height * 2);
|
|
||||||
|
|
||||||
for (uint32 y = 0; y < height; y++) {
|
|
||||||
rle_code *previousCode, *currentCode;
|
|
||||||
|
|
||||||
yOffsets[y] = (uint16)(dst - buffer);
|
|
||||||
|
|
||||||
previousCode = nullptr;
|
|
||||||
currentCode = (rle_code*)dst;
|
|
||||||
dst += 2;
|
|
||||||
sint32 startX = 0;
|
|
||||||
sint32 npixels = 0;
|
|
||||||
bool pushRun = false;
|
|
||||||
for (uint32 x = 0; x < width; x++) {
|
|
||||||
sint32 paletteIndex;
|
|
||||||
|
|
||||||
if (keep_palette)
|
|
||||||
{
|
|
||||||
paletteIndex = *palettedSrc;
|
|
||||||
// The 1st index is always transparent
|
|
||||||
if (paletteIndex == 0)
|
|
||||||
{
|
|
||||||
paletteIndex = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
paletteIndex = get_palette_index(rgbaSrc);
|
|
||||||
|
|
||||||
if (mode == MODE_CLOSEST || mode == MODE_DITHERING)
|
|
||||||
{
|
|
||||||
if (paletteIndex == -1 && !is_transparent_pixel(rgbaSrc))
|
|
||||||
{
|
|
||||||
paletteIndex = get_closest_palette_index(rgbaSrc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode == MODE_DITHERING)
|
|
||||||
{
|
|
||||||
if (!is_transparent_pixel(rgbaSrc) && is_changable_pixel(get_palette_index(rgbaSrc)))
|
|
||||||
{
|
|
||||||
sint16 dr = rgbaSrc[0] - (sint16)(spriteFilePalette[paletteIndex].r);
|
|
||||||
sint16 dg = rgbaSrc[1] - (sint16)(spriteFilePalette[paletteIndex].g);
|
|
||||||
sint16 db = rgbaSrc[2] - (sint16)(spriteFilePalette[paletteIndex].b);
|
|
||||||
|
|
||||||
if (x + 1 < width)
|
|
||||||
{
|
|
||||||
if (!is_transparent_pixel(rgbaSrc + 4) && is_changable_pixel(get_palette_index(rgbaSrc + 4)))
|
|
||||||
{
|
|
||||||
// Right
|
|
||||||
rgbaSrc[4] += dr * 7 / 16;
|
|
||||||
rgbaSrc[5] += dg * 7 / 16;
|
|
||||||
rgbaSrc[6] += db * 7 / 16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (y + 1 < height)
|
|
||||||
{
|
|
||||||
if (x > 0)
|
|
||||||
{
|
|
||||||
if (!is_transparent_pixel(rgbaSrc + 4 * (width - 1)) && is_changable_pixel(get_palette_index(rgbaSrc + 4 * (width - 1))))
|
|
||||||
{
|
|
||||||
// Bottom left
|
|
||||||
rgbaSrc[4 * (width - 1)] += dr * 3 / 16;
|
|
||||||
rgbaSrc[4 * (width - 1) + 1] += dg * 3 / 16;
|
|
||||||
rgbaSrc[4 * (width - 1) + 2] += db * 3 / 16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bottom
|
|
||||||
if (!is_transparent_pixel(rgbaSrc + 4 * width) && is_changable_pixel(get_palette_index(rgbaSrc + 4 * width)))
|
|
||||||
{
|
|
||||||
rgbaSrc[4 * width] += dr * 5 / 16;
|
|
||||||
rgbaSrc[4 * width + 1] += dg * 5 / 16;
|
|
||||||
rgbaSrc[4 * width + 2] += db * 5 / 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x + 1 < width)
|
|
||||||
{
|
|
||||||
if (!is_transparent_pixel(rgbaSrc + 4 * (width + 1)) && is_changable_pixel(get_palette_index(rgbaSrc + 4 * (width + 1))))
|
|
||||||
{
|
|
||||||
// Bottom right
|
|
||||||
rgbaSrc[4 * (width + 1)] += dr * 1 / 16;
|
|
||||||
rgbaSrc[4 * (width + 1) + 1] += dg * 1 / 16;
|
|
||||||
rgbaSrc[4 * (width + 1) + 2] += db * 1 / 16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rgbaSrc += 4;
|
|
||||||
palettedSrc += 1;
|
|
||||||
|
|
||||||
if (paletteIndex == -1)
|
|
||||||
{
|
|
||||||
if (npixels != 0)
|
|
||||||
{
|
|
||||||
x--;
|
|
||||||
rgbaSrc -= 4;
|
|
||||||
palettedSrc -= 1;
|
|
||||||
pushRun = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (npixels == 0)
|
|
||||||
{
|
|
||||||
startX = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
npixels++;
|
|
||||||
*dst++ = (uint8)paletteIndex;
|
|
||||||
}
|
|
||||||
if (npixels == 127 || x == width - 1)
|
|
||||||
{
|
|
||||||
pushRun = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pushRun)
|
|
||||||
{
|
|
||||||
if (npixels > 0)
|
|
||||||
{
|
|
||||||
previousCode = currentCode;
|
|
||||||
currentCode->num_pixels = npixels;
|
|
||||||
currentCode->offset_x = startX;
|
|
||||||
|
|
||||||
if (x == width - 1)
|
|
||||||
{
|
|
||||||
currentCode->num_pixels |= 0x80;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentCode = (rle_code*)dst;
|
|
||||||
dst += 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (previousCode == nullptr)
|
|
||||||
{
|
|
||||||
currentCode->num_pixels = 0x80;
|
|
||||||
currentCode->offset_x = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
previousCode->num_pixels |= 0x80;
|
|
||||||
dst -= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
startX = 0;
|
|
||||||
npixels = 0;
|
|
||||||
pushRun = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(rgbaSrc_orig);
|
|
||||||
|
|
||||||
sint32 bufferLength = (sint32)(dst - buffer);
|
|
||||||
buffer = (uint8 *)realloc(buffer, bufferLength);
|
|
||||||
|
|
||||||
outElement->offset = buffer;
|
|
||||||
outElement->width = width;
|
|
||||||
outElement->height = height;
|
|
||||||
outElement->flags = G1_FLAG_RLE_COMPRESSION;
|
|
||||||
outElement->x_offset = x_offset;
|
|
||||||
outElement->y_offset = y_offset;
|
|
||||||
outElement->zoomed_offset = 0;
|
|
||||||
|
|
||||||
*outBuffer = buffer;
|
|
||||||
*outBufferLength = bufferLength;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sint32 cmdline_for_sprite(const char **argv, sint32 argc)
|
sint32 cmdline_for_sprite(const char **argv, sint32 argc)
|
||||||
|
|
|
@ -27,6 +27,14 @@
|
||||||
struct rct_drawpixelinfo;
|
struct rct_drawpixelinfo;
|
||||||
struct rct_palette;
|
struct rct_palette;
|
||||||
|
|
||||||
|
struct PaletteBGRA
|
||||||
|
{
|
||||||
|
uint8 Blue{};
|
||||||
|
uint8 Green{};
|
||||||
|
uint8 Red{};
|
||||||
|
uint8 Alpha{};
|
||||||
|
};
|
||||||
|
|
||||||
enum class IMAGE_FORMAT
|
enum class IMAGE_FORMAT
|
||||||
{
|
{
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
|
|
|
@ -0,0 +1,596 @@
|
||||||
|
#pragma region Copyright (c) 2018 OpenRCT2 Developers
|
||||||
|
/*****************************************************************************
|
||||||
|
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
||||||
|
*
|
||||||
|
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
|
||||||
|
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* A full copy of the GNU General Public License can be found in licence.txt
|
||||||
|
*****************************************************************************/
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include "../core/Imaging.h"
|
||||||
|
#include "ImageImporter.h"
|
||||||
|
|
||||||
|
using namespace OpenRCT2::Drawing;
|
||||||
|
using ImportResult = ImageImporter::ImportResult;
|
||||||
|
|
||||||
|
struct RLECode
|
||||||
|
{
|
||||||
|
uint8 NumPixels;
|
||||||
|
uint8 OffsetX;
|
||||||
|
};
|
||||||
|
|
||||||
|
ImportResult ImageImporter::Import(
|
||||||
|
const Image& image,
|
||||||
|
sint32 offsetX,
|
||||||
|
sint32 offsetY,
|
||||||
|
bool keepPalette,
|
||||||
|
IMPORT_MODE mode) const
|
||||||
|
{
|
||||||
|
if (image.Width > 256 || image.Height > 256)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Only images 256x256 or less are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keepPalette && image.Depth != 8)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Image is not palletted, it has bit depth of " + image.Depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto width = image.Width;
|
||||||
|
const auto height = image.Height;
|
||||||
|
const auto pixels = image.Pixels.data();
|
||||||
|
const auto palette = StandardPalette;
|
||||||
|
|
||||||
|
auto buffer = (uint8 *)std::malloc((height * 2) + (width * height * 16));
|
||||||
|
std::memset(buffer, 0, (height * 2) + (width * height * 16));
|
||||||
|
auto yOffsets = (uint16 *)buffer;
|
||||||
|
|
||||||
|
// A larger range is needed for proper dithering
|
||||||
|
auto palettedSrc = pixels;
|
||||||
|
std::unique_ptr<sint16[]> rgbaSrcBuffer;
|
||||||
|
if (!keepPalette)
|
||||||
|
{
|
||||||
|
rgbaSrcBuffer = std::make_unique<sint16[]>(height * width * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto rgbaSrc = rgbaSrcBuffer.get();
|
||||||
|
if (!keepPalette)
|
||||||
|
{
|
||||||
|
for (uint32 x = 0; x < height * width * 4; x++)
|
||||||
|
{
|
||||||
|
rgbaSrc[x] = (sint16)pixels[x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
if (keepPalette)
|
||||||
|
{
|
||||||
|
paletteIndex = *palettedSrc;
|
||||||
|
// The 1st index is always transparent
|
||||||
|
if (paletteIndex == 0)
|
||||||
|
{
|
||||||
|
paletteIndex = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
paletteIndex = GetPaletteIndex(palette, rgbaSrc);
|
||||||
|
|
||||||
|
if (mode == IMPORT_MODE::CLOSEST || mode == IMPORT_MODE::DITHERING)
|
||||||
|
{
|
||||||
|
if (paletteIndex == -1 && !IsTransparentPixel(rgbaSrc))
|
||||||
|
{
|
||||||
|
paletteIndex = GetClosestPaletteIndex(palette, rgbaSrc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == IMPORT_MODE::DITHERING)
|
||||||
|
{
|
||||||
|
if (!IsTransparentPixel(rgbaSrc) && IsChangablePixel(GetPaletteIndex(palette, rgbaSrc)))
|
||||||
|
{
|
||||||
|
sint16 dr = rgbaSrc[0] - (sint16)(palette[paletteIndex].Red);
|
||||||
|
sint16 dg = rgbaSrc[1] - (sint16)(palette[paletteIndex].Green);
|
||||||
|
sint16 db = rgbaSrc[2] - (sint16)(palette[paletteIndex].Blue);
|
||||||
|
|
||||||
|
if (x + 1 < width)
|
||||||
|
{
|
||||||
|
if (!IsTransparentPixel(rgbaSrc + 4) && IsChangablePixel(GetPaletteIndex(palette, rgbaSrc + 4)))
|
||||||
|
{
|
||||||
|
// Right
|
||||||
|
rgbaSrc[4] += dr * 7 / 16;
|
||||||
|
rgbaSrc[5] += dg * 7 / 16;
|
||||||
|
rgbaSrc[6] += db * 7 / 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y + 1 < height)
|
||||||
|
{
|
||||||
|
if (x > 0)
|
||||||
|
{
|
||||||
|
if (!IsTransparentPixel(rgbaSrc + 4 * (width - 1)) && IsChangablePixel(GetPaletteIndex(palette, rgbaSrc + 4 * (width - 1))))
|
||||||
|
{
|
||||||
|
// Bottom left
|
||||||
|
rgbaSrc[4 * (width - 1)] += dr * 3 / 16;
|
||||||
|
rgbaSrc[4 * (width - 1) + 1] += dg * 3 / 16;
|
||||||
|
rgbaSrc[4 * (width - 1) + 2] += db * 3 / 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom
|
||||||
|
if (!IsTransparentPixel(rgbaSrc + 4 * width) && IsChangablePixel(GetPaletteIndex(palette, rgbaSrc + 4 * width)))
|
||||||
|
{
|
||||||
|
rgbaSrc[4 * width] += dr * 5 / 16;
|
||||||
|
rgbaSrc[4 * width + 1] += dg * 5 / 16;
|
||||||
|
rgbaSrc[4 * width + 2] += db * 5 / 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x + 1 < width)
|
||||||
|
{
|
||||||
|
if (!IsTransparentPixel(rgbaSrc + 4 * (width + 1)) && IsChangablePixel(GetPaletteIndex(palette, rgbaSrc + 4 * (width + 1))))
|
||||||
|
{
|
||||||
|
// Bottom right
|
||||||
|
rgbaSrc[4 * (width + 1)] += dr * 1 / 16;
|
||||||
|
rgbaSrc[4 * (width + 1) + 1] += dg * 1 / 16;
|
||||||
|
rgbaSrc[4 * (width + 1) + 2] += db * 1 / 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rgbaSrc += 4;
|
||||||
|
palettedSrc += 1;
|
||||||
|
|
||||||
|
if (paletteIndex == -1)
|
||||||
|
{
|
||||||
|
if (npixels != 0)
|
||||||
|
{
|
||||||
|
x--;
|
||||||
|
rgbaSrc -= 4;
|
||||||
|
palettedSrc -= 1;
|
||||||
|
pushRun = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (npixels == 0)
|
||||||
|
{
|
||||||
|
startX = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
npixels++;
|
||||||
|
*dst++ = (uint8)paletteIndex;
|
||||||
|
}
|
||||||
|
if (npixels == 127 || x == width - 1)
|
||||||
|
{
|
||||||
|
pushRun = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pushRun)
|
||||||
|
{
|
||||||
|
if (npixels > 0)
|
||||||
|
{
|
||||||
|
previousCode = currentCode;
|
||||||
|
currentCode->NumPixels = npixels;
|
||||||
|
currentCode->OffsetX = startX;
|
||||||
|
|
||||||
|
if (x == width - 1)
|
||||||
|
{
|
||||||
|
currentCode->NumPixels |= 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentCode = (RLECode *)dst;
|
||||||
|
dst += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (previousCode == nullptr)
|
||||||
|
{
|
||||||
|
currentCode->NumPixels = 0x80;
|
||||||
|
currentCode->OffsetX = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
previousCode->NumPixels |= 0x80;
|
||||||
|
dst -= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
startX = 0;
|
||||||
|
npixels = 0;
|
||||||
|
pushRun = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
sint32 ImageImporter::GetPaletteIndex(const PaletteBGRA * palette, sint16 * colour)
|
||||||
|
{
|
||||||
|
if (!IsTransparentPixel(colour))
|
||||||
|
{
|
||||||
|
for (sint32 i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
if ((sint16)(palette[i].Red) == colour[0] &&
|
||||||
|
(sint16)(palette[i].Green) == colour[1] &&
|
||||||
|
(sint16)(palette[i].Blue) == colour[2])
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImageImporter::IsTransparentPixel(const sint16 * colour)
|
||||||
|
{
|
||||||
|
return colour[3] < 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns true if pixel index is an index not used for remapping.
|
||||||
|
*/
|
||||||
|
bool ImageImporter::IsChangablePixel(sint32 paletteIndex)
|
||||||
|
{
|
||||||
|
if (paletteIndex == -1)
|
||||||
|
return true;
|
||||||
|
if (paletteIndex == 0)
|
||||||
|
return false;
|
||||||
|
if (paletteIndex >= 203 && paletteIndex < 214)
|
||||||
|
return false;
|
||||||
|
if (paletteIndex == 226)
|
||||||
|
return false;
|
||||||
|
if (paletteIndex >= 227 && paletteIndex < 229)
|
||||||
|
return false;
|
||||||
|
if (paletteIndex >= 243)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
sint32 ImageImporter::GetClosestPaletteIndex(const PaletteBGRA * palette, const sint16 * colour)
|
||||||
|
{
|
||||||
|
uint32 smallest_error = (uint32)-1;
|
||||||
|
sint32 best_match = -1;
|
||||||
|
|
||||||
|
for (sint32 x = 0; x < 256; x++) {
|
||||||
|
if (IsChangablePixel(x)) {
|
||||||
|
uint32 error =
|
||||||
|
((sint16)(palette[x].Red) - colour[0]) * ((sint16)(palette[x].Red) - colour[0]) +
|
||||||
|
((sint16)(palette[x].Green) - colour[1]) * ((sint16)(palette[x].Green) - colour[1]) +
|
||||||
|
((sint16)(palette[x].Blue) - colour[2]) * ((sint16)(palette[x].Blue) - colour[2]);
|
||||||
|
|
||||||
|
if (smallest_error == (uint32)-1 || smallest_error > error) {
|
||||||
|
best_match = x;
|
||||||
|
smallest_error = error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return best_match;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PaletteBGRA ImageImporter::StandardPalette[256] =
|
||||||
|
{
|
||||||
|
// 0 (unused)
|
||||||
|
{ 0, 0, 0, 255 },
|
||||||
|
|
||||||
|
// 1 - 9 (misc. e.g. font and water)
|
||||||
|
{ 0, 0, 0, 255 },
|
||||||
|
{ 0, 0, 0, 255 },
|
||||||
|
{ 0, 0, 0, 255 },
|
||||||
|
{ 0, 0, 0, 255 },
|
||||||
|
{ 0, 0, 0, 255 },
|
||||||
|
{ 0, 0, 0, 255 },
|
||||||
|
{ 0, 0, 0, 255 },
|
||||||
|
{ 0, 0, 0, 255 },
|
||||||
|
{ 0, 0, 0, 255 },
|
||||||
|
|
||||||
|
//
|
||||||
|
{ 35, 35, 23, 255 },
|
||||||
|
{ 51, 51, 35, 255 },
|
||||||
|
{ 67, 67, 47, 255 },
|
||||||
|
{ 83, 83, 63, 255 },
|
||||||
|
{ 99, 99, 75, 255 },
|
||||||
|
{ 115, 115, 91, 255 },
|
||||||
|
{ 131, 131, 111, 255 },
|
||||||
|
{ 151, 151, 131, 255 },
|
||||||
|
{ 175, 175, 159, 255 },
|
||||||
|
{ 195, 195, 183, 255 },
|
||||||
|
{ 219, 219, 211, 255 },
|
||||||
|
{ 243, 243, 239, 255 },
|
||||||
|
{ 0, 47, 51, 255 },
|
||||||
|
{ 0, 59, 63, 255 },
|
||||||
|
{ 11, 75, 79, 255 },
|
||||||
|
{ 19, 91, 91, 255 },
|
||||||
|
{ 31, 107, 107, 255 },
|
||||||
|
{ 47, 123, 119, 255 },
|
||||||
|
{ 59, 139, 135, 255 },
|
||||||
|
{ 79, 155, 151, 255 },
|
||||||
|
{ 95, 175, 167, 255 },
|
||||||
|
{ 115, 191, 187, 255 },
|
||||||
|
{ 139, 207, 203, 255 },
|
||||||
|
{ 163, 227, 223, 255 },
|
||||||
|
{ 7, 43, 67, 255 },
|
||||||
|
{ 11, 59, 87, 255 },
|
||||||
|
{ 23, 75, 111, 255 },
|
||||||
|
{ 31, 87, 127, 255 },
|
||||||
|
{ 39, 99, 143, 255 },
|
||||||
|
{ 51, 115, 159, 255 },
|
||||||
|
{ 67, 131, 179, 255 },
|
||||||
|
{ 87, 151, 191, 255 },
|
||||||
|
{ 111, 175, 203, 255 },
|
||||||
|
{ 135, 199, 219, 255 },
|
||||||
|
{ 163, 219, 231, 255 },
|
||||||
|
{ 195, 239, 247, 255 },
|
||||||
|
{ 0, 27, 71, 255 },
|
||||||
|
{ 0, 43, 95, 255 },
|
||||||
|
{ 0, 63, 119, 255 },
|
||||||
|
{ 7, 83, 143, 255 },
|
||||||
|
{ 7, 111, 167, 255 },
|
||||||
|
{ 15, 139, 191, 255 },
|
||||||
|
{ 19, 167, 215, 255 },
|
||||||
|
{ 27, 203, 243, 255 },
|
||||||
|
{ 47, 231, 255, 255 },
|
||||||
|
{ 95, 243, 255, 255 },
|
||||||
|
{ 143, 251, 255, 255 },
|
||||||
|
{ 195, 255, 255, 255 },
|
||||||
|
{ 0, 0, 35, 255 },
|
||||||
|
{ 0, 0, 79, 255 },
|
||||||
|
{ 7, 7, 95, 255 },
|
||||||
|
{ 15, 15, 111, 255 },
|
||||||
|
{ 27, 27, 127, 255 },
|
||||||
|
{ 39, 39, 143, 255 },
|
||||||
|
{ 59, 59, 163, 255 },
|
||||||
|
{ 79, 79, 179, 255 },
|
||||||
|
{ 103, 103, 199, 255 },
|
||||||
|
{ 127, 127, 215, 255 },
|
||||||
|
{ 159, 159, 235, 255 },
|
||||||
|
{ 191, 191, 255, 255 },
|
||||||
|
{ 19, 51, 27, 255 },
|
||||||
|
{ 23, 63, 35, 255 },
|
||||||
|
{ 31, 79, 47, 255 },
|
||||||
|
{ 39, 95, 59, 255 },
|
||||||
|
{ 43, 111, 71, 255 },
|
||||||
|
{ 51, 127, 87, 255 },
|
||||||
|
{ 59, 143, 99, 255 },
|
||||||
|
{ 67, 155, 115, 255 },
|
||||||
|
{ 75, 171, 131, 255 },
|
||||||
|
{ 83, 187, 147, 255 },
|
||||||
|
{ 95, 203, 163, 255 },
|
||||||
|
{ 103, 219, 183, 255 },
|
||||||
|
{ 27, 55, 31, 255 },
|
||||||
|
{ 35, 71, 47, 255 },
|
||||||
|
{ 43, 83, 59, 255 },
|
||||||
|
{ 55, 99, 75, 255 },
|
||||||
|
{ 67, 111, 91, 255 },
|
||||||
|
{ 79, 135, 111, 255 },
|
||||||
|
{ 95, 159, 135, 255 },
|
||||||
|
{ 111, 183, 159, 255 },
|
||||||
|
{ 127, 207, 183, 255 },
|
||||||
|
{ 147, 219, 195, 255 },
|
||||||
|
{ 167, 231, 207, 255 },
|
||||||
|
{ 191, 247, 223, 255 },
|
||||||
|
{ 0, 63, 15, 255 },
|
||||||
|
{ 0, 83, 19, 255 },
|
||||||
|
{ 0, 103, 23, 255 },
|
||||||
|
{ 0, 123, 31, 255 },
|
||||||
|
{ 7, 143, 39, 255 },
|
||||||
|
{ 23, 159, 55, 255 },
|
||||||
|
{ 39, 175, 71, 255 },
|
||||||
|
{ 63, 191, 91, 255 },
|
||||||
|
{ 87, 207, 111, 255 },
|
||||||
|
{ 115, 223, 139, 255 },
|
||||||
|
{ 143, 239, 163, 255 },
|
||||||
|
{ 179, 255, 195, 255 },
|
||||||
|
{ 19, 43, 79, 255 },
|
||||||
|
{ 27, 55, 99, 255 },
|
||||||
|
{ 43, 71, 119, 255 },
|
||||||
|
{ 59, 87, 139, 255 },
|
||||||
|
{ 67, 99, 167, 255 },
|
||||||
|
{ 83, 115, 187, 255 },
|
||||||
|
{ 99, 131, 207, 255 },
|
||||||
|
{ 115, 151, 215, 255 },
|
||||||
|
{ 131, 171, 227, 255 },
|
||||||
|
{ 151, 191, 239, 255 },
|
||||||
|
{ 171, 207, 247, 255 },
|
||||||
|
{ 195, 227, 255, 255 },
|
||||||
|
{ 55, 19, 15, 255 },
|
||||||
|
{ 87, 43, 39, 255 },
|
||||||
|
{ 103, 55, 51, 255 },
|
||||||
|
{ 119, 67, 63, 255 },
|
||||||
|
{ 139, 83, 83, 255 },
|
||||||
|
{ 155, 99, 99, 255 },
|
||||||
|
{ 175, 119, 119, 255 },
|
||||||
|
{ 191, 139, 139, 255 },
|
||||||
|
{ 207, 159, 159, 255 },
|
||||||
|
{ 223, 183, 183, 255 },
|
||||||
|
{ 239, 211, 211, 255 },
|
||||||
|
{ 255, 239, 239, 255 },
|
||||||
|
{ 111, 27, 0, 255 },
|
||||||
|
{ 151, 39, 0, 255 },
|
||||||
|
{ 167, 51, 7, 255 },
|
||||||
|
{ 187, 67, 15, 255 },
|
||||||
|
{ 203, 83, 27, 255 },
|
||||||
|
{ 223, 103, 43, 255 },
|
||||||
|
{ 227, 135, 67, 255 },
|
||||||
|
{ 231, 163, 91, 255 },
|
||||||
|
{ 239, 187, 119, 255 },
|
||||||
|
{ 243, 211, 143, 255 },
|
||||||
|
{ 251, 231, 175, 255 },
|
||||||
|
{ 255, 247, 215, 255 },
|
||||||
|
{ 15, 43, 11, 255 },
|
||||||
|
{ 23, 55, 15, 255 },
|
||||||
|
{ 31, 71, 23, 255 },
|
||||||
|
{ 43, 83, 35, 255 },
|
||||||
|
{ 59, 99, 47, 255 },
|
||||||
|
{ 75, 115, 59, 255 },
|
||||||
|
{ 95, 135, 79, 255 },
|
||||||
|
{ 119, 155, 99, 255 },
|
||||||
|
{ 139, 175, 123, 255 },
|
||||||
|
{ 167, 199, 147, 255 },
|
||||||
|
{ 195, 219, 175, 255 },
|
||||||
|
{ 223, 243, 207, 255 },
|
||||||
|
{ 95, 0, 63, 255 },
|
||||||
|
{ 115, 7, 75, 255 },
|
||||||
|
{ 127, 15, 83, 255 },
|
||||||
|
{ 143, 31, 95, 255 },
|
||||||
|
{ 155, 43, 107, 255 },
|
||||||
|
{ 171, 63, 123, 255 },
|
||||||
|
{ 187, 83, 135, 255 },
|
||||||
|
{ 199, 103, 155, 255 },
|
||||||
|
{ 215, 127, 171, 255 },
|
||||||
|
{ 231, 155, 191, 255 },
|
||||||
|
{ 243, 195, 215, 255 },
|
||||||
|
{ 255, 235, 243, 255 },
|
||||||
|
{ 0, 0, 63, 255 },
|
||||||
|
{ 0, 0, 87, 255 },
|
||||||
|
{ 0, 0, 115, 255 },
|
||||||
|
{ 0, 0, 143, 255 },
|
||||||
|
{ 0, 0, 171, 255 },
|
||||||
|
{ 0, 0, 199, 255 },
|
||||||
|
{ 0, 7, 227, 255 },
|
||||||
|
{ 0, 7, 255, 255 },
|
||||||
|
{ 67, 79, 255, 255 },
|
||||||
|
{ 115, 123, 255, 255 },
|
||||||
|
{ 163, 171, 255, 255 },
|
||||||
|
{ 215, 219, 255, 255 },
|
||||||
|
{ 0, 39, 79, 255 },
|
||||||
|
{ 0, 51, 111, 255 },
|
||||||
|
{ 0, 63, 147, 255 },
|
||||||
|
{ 0, 71, 183, 255 },
|
||||||
|
{ 0, 79, 219, 255 },
|
||||||
|
{ 0, 83, 255, 255 },
|
||||||
|
{ 23, 111, 255, 255 },
|
||||||
|
{ 51, 139, 255, 255 },
|
||||||
|
{ 79, 163, 255, 255 },
|
||||||
|
{ 107, 183, 255, 255 },
|
||||||
|
{ 135, 203, 255, 255 },
|
||||||
|
{ 163, 219, 255, 255 },
|
||||||
|
{ 47, 51, 0, 255 },
|
||||||
|
{ 55, 63, 0, 255 },
|
||||||
|
{ 67, 75, 0, 255 },
|
||||||
|
{ 79, 87, 0, 255 },
|
||||||
|
{ 99, 107, 7, 255 },
|
||||||
|
{ 119, 127, 23, 255 },
|
||||||
|
{ 143, 147, 43, 255 },
|
||||||
|
{ 163, 167, 71, 255 },
|
||||||
|
{ 187, 187, 99, 255 },
|
||||||
|
{ 207, 207, 131, 255 },
|
||||||
|
{ 231, 231, 171, 255 },
|
||||||
|
{ 255, 255, 207, 255 },
|
||||||
|
|
||||||
|
// 203 - 214 (Secondary remap)
|
||||||
|
{ 27, 0, 63, 255 },
|
||||||
|
{ 51, 0, 103, 255 },
|
||||||
|
{ 63, 11, 123, 255 },
|
||||||
|
{ 79, 23, 143, 255 },
|
||||||
|
{ 95, 31, 163, 255 },
|
||||||
|
{ 111, 39, 183, 255 },
|
||||||
|
{ 143, 59, 219, 255 },
|
||||||
|
{ 171, 91, 239, 255 },
|
||||||
|
{ 187, 119, 243, 255 },
|
||||||
|
{ 203, 151, 247, 255 },
|
||||||
|
{ 223, 183, 251, 255 },
|
||||||
|
{ 239, 215, 255, 255 },
|
||||||
|
|
||||||
|
// 214 - 225 (Brown)
|
||||||
|
{ 0, 19, 39, 255 },
|
||||||
|
{ 7, 31, 55, 255 },
|
||||||
|
{ 15, 47, 71, 255 },
|
||||||
|
{ 31, 63, 91, 255 },
|
||||||
|
{ 51, 83, 107, 255 },
|
||||||
|
{ 75, 103, 123, 255 },
|
||||||
|
{ 107, 127, 143, 255 },
|
||||||
|
{ 127, 147, 163, 255 },
|
||||||
|
{ 147, 171, 187, 255 },
|
||||||
|
{ 171, 195, 207, 255 },
|
||||||
|
{ 195, 219, 231, 255 },
|
||||||
|
{ 223, 243, 255, 255 },
|
||||||
|
|
||||||
|
// 226 (unknown)
|
||||||
|
{ 75, 75, 55, 255 },
|
||||||
|
|
||||||
|
// 227 - 229 (tertiary remap)
|
||||||
|
{ 0, 183, 255, 255 },
|
||||||
|
{ 0, 219, 255, 255 },
|
||||||
|
{ 0, 255, 255, 255 },
|
||||||
|
|
||||||
|
// 230 - 239 (water)
|
||||||
|
{ 99, 107, 7, 255 },
|
||||||
|
{ 99, 107, 7, 255 },
|
||||||
|
{ 135, 143, 39, 255 },
|
||||||
|
{ 123, 131, 27, 255 },
|
||||||
|
{ 99, 107, 7, 255 },
|
||||||
|
{ 151, 155, 55, 255 },
|
||||||
|
{ 151, 155, 55, 255 },
|
||||||
|
{ 227, 227, 155, 255 },
|
||||||
|
{ 203, 203, 115, 255 },
|
||||||
|
{ 151, 155, 55, 255 },
|
||||||
|
|
||||||
|
// 240 - 242 (chain lift)
|
||||||
|
{ 91, 91, 67, 255 },
|
||||||
|
{ 107, 107, 83, 255 },
|
||||||
|
{ 123, 123, 99, 255 },
|
||||||
|
|
||||||
|
// Old 243 - 245, changed to nice shade remap below
|
||||||
|
// { 47, 47, 47, 255 },
|
||||||
|
// { 47, 47, 47, 255 },
|
||||||
|
// { 47, 71, 87, 255 },
|
||||||
|
|
||||||
|
// 243 to 254 (primary remap)
|
||||||
|
{ 47, 51, 111, 255 },
|
||||||
|
{ 47, 55, 131, 255 },
|
||||||
|
{ 51, 63, 151, 255 },
|
||||||
|
{ 51, 67, 171, 255 },
|
||||||
|
{ 47, 75, 191, 255 },
|
||||||
|
{ 43, 79, 211, 255 },
|
||||||
|
{ 35, 87, 231, 255 },
|
||||||
|
{ 31, 95, 255, 255 },
|
||||||
|
{ 39, 127, 255, 255 },
|
||||||
|
{ 51, 155, 255, 255 },
|
||||||
|
{ 63, 183, 255, 255 },
|
||||||
|
{ 75, 207, 255, 255 },
|
||||||
|
|
||||||
|
// 255 (unused?)
|
||||||
|
{ 0, 0, 0, 255 }
|
||||||
|
};
|
|
@ -0,0 +1,60 @@
|
||||||
|
#pragma region Copyright (c) 2018 OpenRCT2 Developers
|
||||||
|
/*****************************************************************************
|
||||||
|
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
||||||
|
*
|
||||||
|
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
|
||||||
|
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* A full copy of the GNU General Public License can be found in licence.txt
|
||||||
|
*****************************************************************************/
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
#include "../core/Imaging.h"
|
||||||
|
#include "Drawing.h"
|
||||||
|
|
||||||
|
struct Image;
|
||||||
|
|
||||||
|
namespace OpenRCT2::Drawing
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Imports images to the internal RCT G1 format.
|
||||||
|
*/
|
||||||
|
class ImageImporter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct ImportResult
|
||||||
|
{
|
||||||
|
rct_g1_element Element{};
|
||||||
|
void * Buffer{};
|
||||||
|
size_t BufferLength{};
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class IMPORT_MODE
|
||||||
|
{
|
||||||
|
DEFAULT,
|
||||||
|
CLOSEST,
|
||||||
|
DITHERING,
|
||||||
|
};
|
||||||
|
|
||||||
|
ImportResult Import(
|
||||||
|
const Image& image,
|
||||||
|
sint32 offsetX = 0,
|
||||||
|
sint32 offsetY = 0,
|
||||||
|
bool keepPalette = false,
|
||||||
|
IMPORT_MODE mode = IMPORT_MODE::DEFAULT) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const PaletteBGRA StandardPalette[256];
|
||||||
|
|
||||||
|
static sint32 GetPaletteIndex(const PaletteBGRA * palette, sint16 * colour);
|
||||||
|
static bool IsTransparentPixel(const sint16 * colour);
|
||||||
|
static bool IsChangablePixel(sint32 paletteIndex);
|
||||||
|
static sint32 GetClosestPaletteIndex(const PaletteBGRA * palette, const sint16 * colour);
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue