1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-21 14:02:59 +01:00

Add "palette": "keep" option to import with an already correct palette

This commit is contained in:
Jeroen D Stout
2017-10-03 23:50:32 +02:00
committed by Michał Janiszewski
parent 71cfe112f1
commit b1792658c8

View File

@@ -24,6 +24,7 @@
#include "OpenRCT2.h"
#include "platform/platform.h"
#include "util/util.h"
#include "png.h"
#define MODE_DEFAULT 0
#define MODE_CLOSEST 1
@@ -306,16 +307,18 @@ static sint32 get_palette_index(sint16 *colour)
}
static bool sprite_file_import(const char *path, sint16 x_offset, sint16 y_offset, 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)
{
uint8 *pixels;
uint32 width, height;
if (!image_io_png_read(&pixels, &width, &height, path)) {
if (!image_io_png_read(&pixels, &width, &height, !keep_palette, path))
{
fprintf(stderr, "Error reading PNG");
return false;
}
if (width > 256 || height > 256) {
if (width > 256 || height > 256)
{
fprintf(stderr, "Only images 256x256 or less are supported.");
free(pixels);
return false;
@@ -328,10 +331,14 @@ static bool sprite_file_import(const char *path, sint16 x_offset, sint16 y_offse
uint16 *yOffsets = (uint16*)buffer;
// A larger range is needed for proper dithering
sint16 *src = malloc(height * width * 4 * 2);
sint16 *src_orig = src;
for (uint32 x = 0; x < height * width * 4; x++){
src[x] = (sint16) pixels[x];
uint8 *palettedSrc = pixels;
sint16 *rgbaSrc = keep_palette? 0 : 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);
@@ -348,92 +355,128 @@ static bool sprite_file_import(const char *path, sint16 x_offset, sint16 y_offse
sint32 npixels = 0;
bool pushRun = false;
for (uint32 x = 0; x < width; x++) {
sint32 paletteIndex = get_palette_index(src);
sint32 paletteIndex;
if (mode == MODE_CLOSEST || mode == MODE_DITHERING)
if (paletteIndex == -1 && !is_transparent_pixel(src))
paletteIndex = get_closest_palette_index(src);
if (keep_palette)
{
paletteIndex = *palettedSrc;
}
else
{
paletteIndex = get_palette_index(rgbaSrc);
if (mode == MODE_DITHERING)
if (!is_transparent_pixel(src) && is_changable_pixel(get_palette_index(src))){
sint16 dr = src[0] - (sint16)(spriteFilePalette[paletteIndex].r);
sint16 dg = src[1] - (sint16)(spriteFilePalette[paletteIndex].g);
sint16 db = src[2] - (sint16)(spriteFilePalette[paletteIndex].b);
if (x + 1 < width){
if (!is_transparent_pixel(src + 4) && is_changable_pixel(get_palette_index(src + 4))){
// Right
src[4] += dr * 7 / 16;
src[5] += dg * 7 / 16;
src[6] += db * 7 / 16;
}
if (mode == MODE_CLOSEST || mode == MODE_DITHERING)
{
if (paletteIndex == -1 && !is_transparent_pixel(rgbaSrc))
{
paletteIndex = get_closest_palette_index(rgbaSrc);
}
}
if (y + 1 < height){
if (x > 0){
if (!is_transparent_pixel(src + 4 * (width - 1)) && is_changable_pixel(get_palette_index(src + 4 * (width - 1)))){
// Bottom left
src[4 * (width - 1)] += dr * 3 / 16;
src[4 * (width - 1) + 1] += dg * 3 / 16;
src[4 * (width - 1) + 2] += db * 3 / 16;
}
}
// Bottom
if (!is_transparent_pixel(src + 4 * width) && is_changable_pixel(get_palette_index(src + 4 * width))){
src[4 * width] += dr * 5 / 16;
src[4 * width + 1] += dg * 5 / 16;
src[4 * width + 2] += db * 5 / 16;
}
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(src + 4 * (width - 1)) && is_changable_pixel(get_palette_index(src + 4 * (width + 1)))){
// Bottom right
src[4 * (width + 1)] += dr * 1 / 16;
src[4 * (width + 1) + 1] += dg * 1 / 16;
src[4 * (width + 1) + 2] += db * 1 / 16;
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;
}
}
}
}
}
}
src += 4;
if (paletteIndex == -1) {
if (npixels != 0) {
rgbaSrc += 4;
palettedSrc += 1;
if (paletteIndex == -1)
{
if (npixels != 0)
{
x--;
src -= 4;
rgbaSrc -= 4;
palettedSrc -= 1;
pushRun = true;
}
} else {
}
else
{
if (npixels == 0)
{
startX = x;
}
npixels++;
*dst++ = (uint8)paletteIndex;
}
if (npixels == 127 || x == width - 1)
{
pushRun = true;
}
if (pushRun) {
if (npixels > 0) {
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 == NULL) {
}
else
{
if (previousCode == NULL)
{
currentCode->num_pixels = 0x80;
currentCode->offset_x = 0;
} else {
}
else
{
previousCode->num_pixels |= 0x80;
dst -= 2;
}
}
startX = 0;
npixels = 0;
pushRun = false;
@@ -441,7 +484,7 @@ static bool sprite_file_import(const char *path, sint16 x_offset, sint16 y_offse
}
}
free(pixels);
free(src_orig);
free(rgbaSrc_orig);
sint32 bufferLength = (sint32)(dst - buffer);
buffer = realloc(buffer, bufferLength);
@@ -649,8 +692,7 @@ sint32 cmdline_for_sprite(const char **argv, sint32 argc)
uint8 *buffer;
sint32 bufferLength;
if (!sprite_file_import(imagePath, x_offset, y_offset, &spriteElement, &buffer, &bufferLength, gSpriteMode))
if (!sprite_file_import(imagePath, x_offset, y_offset, false, &spriteElement, &buffer, &bufferLength, gSpriteMode))
return -1;
if (!sprite_file_open(spriteFilePath)) {
@@ -732,6 +774,17 @@ sint32 cmdline_for_sprite(const char **argv, sint32 argc)
json_t* x_offset = json_object_get(sprite_description, "x_offset");
json_t* y_offset = json_object_get(sprite_description, "y_offset");
// Get palette option, if present
bool keep_palette = false;
json_t* palette = json_object_get(sprite_description, "palette");
if (palette && json_is_string(palette))
{
const char *option = json_string_value(palette);
if (strncmp(option, "keep", 4) == 0)
{
keep_palette = true;
}
}
// Resolve absolute sprite path
char *imagePath = platform_get_absolute_path(json_string_value(path), directoryPath);
@@ -740,7 +793,7 @@ sint32 cmdline_for_sprite(const char **argv, sint32 argc)
uint8 *buffer;
int bufferLength;
if (!sprite_file_import(imagePath, x_offset==NULL ? 0 : json_integer_value(x_offset), y_offset==NULL ? 0 : json_integer_value(y_offset), &spriteElement, &buffer, &bufferLength, gSpriteMode))
if (!sprite_file_import(imagePath, x_offset==NULL ? 0 : json_integer_value(x_offset), y_offset==NULL ? 0 : json_integer_value(y_offset), keep_palette, &spriteElement, &buffer, &bufferLength, gSpriteMode))
{
fprintf(stderr, "Could not import image file: %s\nCanceling\n", imagePath);
json_decref(sprite_list);