From 55456559bbc5429a7a6f15d127c4aa02aaec4512 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 31 May 2015 20:35:40 +0200 Subject: [PATCH 1/4] Added dithering and closest pixel conversion for sprite tool --- src/cmdline.c | 1 + src/cmdline.h | 2 + src/cmdline_sprite.c | 118 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 117 insertions(+), 4 deletions(-) diff --git a/src/cmdline.c b/src/cmdline.c index 013af496f2..b61452922f 100644 --- a/src/cmdline.c +++ b/src/cmdline.c @@ -60,6 +60,7 @@ int cmdline_run(const char **argv, int argc) OPT_HELP(), OPT_BOOLEAN('v', "version", &version, "show version information and exit"), OPT_BOOLEAN(0, "verbose", &verbose, "log verbose messages"), + OPT_INTEGER('m', "mode", &sprite_mode, "the type of sprite conversion. 0 = default, 1 = simple closest pixel match, 2 = dithering"), OPT_END() }; diff --git a/src/cmdline.h b/src/cmdline.h index dfb1d86b40..b86393f047 100644 --- a/src/cmdline.h +++ b/src/cmdline.h @@ -26,6 +26,8 @@ /** The exit code for OpenRCT2 when it exits. */ extern int gExitCode; +int sprite_mode; + int cmdline_run(const char **argv, int argc); int cmdline_for_sprite(const char **argv, int argc); diff --git a/src/cmdline_sprite.c b/src/cmdline_sprite.c index 77811394c5..f1503f400e 100644 --- a/src/cmdline_sprite.c +++ b/src/cmdline_sprite.c @@ -3,6 +3,10 @@ #include "drawing/drawing.h" #include "util/util.h" +#define MODE_DEFAULT 0 +#define MODE_CLOSEST 1 +#define MODE_DITHERING 2 + typedef struct { uint32 num_entries; uint32 total_size; @@ -171,6 +175,49 @@ bool sprite_file_export(int spriteIndex, const char *outPath) } } +bool is_transparent_pixel(uint8 *colour){ + return colour[3] == 0; +} + +// Returns true if pixel index is an index not used for remapping +bool is_changable_pixel(int 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; +} + +int get_closest_palette_index(uint32 colour){ + sint32 smallest_error = -1; + int best_match = -1; + + uint8 *rgba = (uint8*)(&colour); + + for (int x = 0; x < 256; x++){ + if (is_changable_pixel(x)){ + sint32 error = + (spriteFilePalette[x].r - rgba[0]) * (spriteFilePalette[x].r - rgba[0]) + + (spriteFilePalette[x].g - rgba[1]) * (spriteFilePalette[x].g - rgba[1]) + + (spriteFilePalette[x].b - rgba[2]) * (spriteFilePalette[x].b - rgba[2]); + + if (smallest_error == -1 || smallest_error > error){ + best_match = x; + smallest_error = error; + } + } + } + return best_match; +} + int get_palette_index(uint32 colour) { uint8 *rgba = (uint8*)(&colour); @@ -193,7 +240,7 @@ typedef struct { uint8 offset_x; } rle_code; -bool sprite_file_import(const char *path, rct_g1_element *outElement, uint8 **outBuffer, int *outBufferLength) +bool sprite_file_import(const char *path, rct_g1_element *outElement, uint8 **outBuffer, int *outBufferLength, int mode) { unsigned char *pixels; unsigned int width, height; @@ -217,6 +264,8 @@ bool sprite_file_import(const char *path, rct_g1_element *outElement, uint8 **ou uint16 *yOffsets = (uint16*)buffer; uint8 *src = pixels; uint8 *dst = buffer + (height * 2); + + int dos = 0; for (unsigned int y = 0; y < height; y++) { rle_code *previousCode, *currentCode; @@ -231,8 +280,67 @@ bool sprite_file_import(const char *path, rct_g1_element *outElement, uint8 **ou bool pushRun = false; for (unsigned int x = 0; x < width; x++) { int paletteIndex = get_palette_index(*((uint32*)src)); + + if (mode == MODE_CLOSEST || mode == MODE_DITHERING) + if (paletteIndex == -1 && !is_transparent_pixel(src)) + paletteIndex = get_closest_palette_index(*((uint32*)src)); + + + if (mode == MODE_DITHERING) + if (!is_transparent_pixel(src) && is_changable_pixel(get_palette_index(*((uint32*)src)))){ + int dr = src[0] - spriteFilePalette[paletteIndex].r; + int dg = src[1] - spriteFilePalette[paletteIndex].g; + int db = src[2] - spriteFilePalette[paletteIndex].b; + + if (dos < 40){ + printf("Original: %d, %d, %d\n", src[0], src[1], src[2]); + printf("Chosen: %d, %d, %d\n", spriteFilePalette[paletteIndex].r, spriteFilePalette[paletteIndex].g, spriteFilePalette[paletteIndex].b); + printf("%d - %d = %d", src[0], spriteFilePalette[paletteIndex].r, src[0] - spriteFilePalette[paletteIndex].r); + printf("Pixel: %d.\n", paletteIndex); + printf("%d, %d, %d\n", dr, dg, db); + puts(""); + dos++; + } + + if (x + 1 < width){ + if (!is_transparent_pixel(src + 4) && is_changable_pixel(get_palette_index(*((uint32*)(src + 4))))){ + // Right + src[4] += dr * 7 / 16; + src[5] += dg * 7 / 16; + src[6] += db * 7 / 16; + } + } + + if (y + 1 < height){ + if (x > 0){ + if (!is_transparent_pixel(src + 4 * (width - 1)) && is_changable_pixel(get_palette_index(*((uint32*)(src + 4 * (width - 1)))))){ + // Below left + src[4 * (width - 1)] += dr * 3 / 16; + src[4 * (width - 1) + 1] += dg * 3 / 16; + src[4 * (width - 1) + 2] += db * 3 / 16; + } + } + + // Below + if (!is_transparent_pixel(src + 4 * width) && is_changable_pixel(get_palette_index(*((uint32*)(src + 4 * width))))){ + src[4 * width] += dr * 5 / 16; + src[4 * width + 1] += dg * 5 / 16; + src[4 * width + 2] += db * 5 / 16; + } + + if (x + 1 < width){ + if (!is_transparent_pixel(src + 4 * (width - 1)) && is_changable_pixel(get_palette_index(*((uint32*)(src + 4 * (width + 1)))))){ + // Below right + src[4 * (width + 1)] += dr * 1 / 16; + src[4 * (width + 1) + 1] += dg * 1 / 16; + src[4 * (width + 1) + 2] += db * 1 / 16; + } + } + } + } + src += 4; - if (paletteIndex == -1) { + if (is_transparent_pixel(src)) { if (pixels != 0) { x--; src -= 4; @@ -391,7 +499,7 @@ int cmdline_for_sprite(const char **argv, int argc) rct_g1_element spriteElement; uint8 *buffer; int bufferLength; - if (!sprite_file_import(imagePath, &spriteElement, &buffer, &bufferLength)) + if (!sprite_file_import(imagePath, &spriteElement, &buffer, &bufferLength, sprite_mode)) return -1; if (!sprite_file_open(spriteFilePath)) { @@ -445,7 +553,7 @@ int cmdline_for_sprite(const char **argv, int argc) rct_g1_element spriteElement; uint8 *buffer; int bufferLength; - if (!sprite_file_import(imagePath, &spriteElement, &buffer, &bufferLength)) { + if (!sprite_file_import(imagePath, &spriteElement, &buffer, &bufferLength, sprite_mode)) { fprintf(stderr, "Could not import image file: %s\nCanceling\n", imagePath); return -1; } @@ -488,6 +596,8 @@ int cmdline_for_sprite(const char **argv, int argc) } } + + static rct_sprite_file_palette_entry _standardPalette[256] = { // 0 (unused) { 0, 0, 0, 255 }, From c266c21c9c99d2f7d77c082118a0ee61f02fc176 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 1 Jun 2015 13:19:40 +0200 Subject: [PATCH 2/4] Fix overflow issue --- src/cmdline_sprite.c | 64 +++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/src/cmdline_sprite.c b/src/cmdline_sprite.c index f1503f400e..a672b12c0c 100644 --- a/src/cmdline_sprite.c +++ b/src/cmdline_sprite.c @@ -175,7 +175,7 @@ bool sprite_file_export(int spriteIndex, const char *outPath) } } -bool is_transparent_pixel(uint8 *colour){ +bool is_transparent_pixel(sint16 *colour){ return colour[3] == 0; } @@ -196,18 +196,16 @@ bool is_changable_pixel(int palette_index) { return true; } -int get_closest_palette_index(uint32 colour){ - sint32 smallest_error = -1; +int get_closest_palette_index(sint16 *colour){ + uint32 smallest_error = -1; int best_match = -1; - uint8 *rgba = (uint8*)(&colour); - for (int x = 0; x < 256; x++){ if (is_changable_pixel(x)){ - sint32 error = - (spriteFilePalette[x].r - rgba[0]) * (spriteFilePalette[x].r - rgba[0]) + - (spriteFilePalette[x].g - rgba[1]) * (spriteFilePalette[x].g - rgba[1]) + - (spriteFilePalette[x].b - rgba[2]) * (spriteFilePalette[x].b - rgba[2]); + 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 == -1 || smallest_error > error){ best_match = x; @@ -218,17 +216,15 @@ int get_closest_palette_index(uint32 colour){ return best_match; } -int get_palette_index(uint32 colour) -{ - uint8 *rgba = (uint8*)(&colour); - - if (rgba[3] < 128) +int get_palette_index(sint16 *colour) +{ + if (colour[3] < 128) return -1; for (int i = 0; i < 256; i++) { - if (spriteFilePalette[i].r != rgba[0]) continue; - if (spriteFilePalette[i].g != rgba[1]) continue; - if (spriteFilePalette[i].b != rgba[2]) continue; + 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; } @@ -262,7 +258,13 @@ bool sprite_file_import(const char *path, rct_g1_element *outElement, uint8 **ou uint8 *buffer = malloc((height * 2) + (width * height * 16)); uint16 *yOffsets = (uint16*)buffer; - uint8 *src = pixels; + + // A larger range is needed for proper dithering + sint16 *src = malloc(height * width * 4 * 2); + for (int x = 0; x < height * width * 4; x++){ + src[x] = (sint16) pixels[x]; + } + uint8 *dst = buffer + (height * 2); int dos = 0; @@ -279,18 +281,18 @@ bool sprite_file_import(const char *path, rct_g1_element *outElement, uint8 **ou int pixels = 0; bool pushRun = false; for (unsigned int x = 0; x < width; x++) { - int paletteIndex = get_palette_index(*((uint32*)src)); + int paletteIndex = get_palette_index(src); if (mode == MODE_CLOSEST || mode == MODE_DITHERING) if (paletteIndex == -1 && !is_transparent_pixel(src)) - paletteIndex = get_closest_palette_index(*((uint32*)src)); + paletteIndex = get_closest_palette_index(src); if (mode == MODE_DITHERING) - if (!is_transparent_pixel(src) && is_changable_pixel(get_palette_index(*((uint32*)src)))){ - int dr = src[0] - spriteFilePalette[paletteIndex].r; - int dg = src[1] - spriteFilePalette[paletteIndex].g; - int db = src[2] - spriteFilePalette[paletteIndex].b; + 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 (dos < 40){ printf("Original: %d, %d, %d\n", src[0], src[1], src[2]); @@ -303,7 +305,7 @@ bool sprite_file_import(const char *path, rct_g1_element *outElement, uint8 **ou } if (x + 1 < width){ - if (!is_transparent_pixel(src + 4) && is_changable_pixel(get_palette_index(*((uint32*)(src + 4))))){ + 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; @@ -313,24 +315,24 @@ bool sprite_file_import(const char *path, rct_g1_element *outElement, uint8 **ou if (y + 1 < height){ if (x > 0){ - if (!is_transparent_pixel(src + 4 * (width - 1)) && is_changable_pixel(get_palette_index(*((uint32*)(src + 4 * (width - 1)))))){ - // Below left + 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; } } - // Below - if (!is_transparent_pixel(src + 4 * width) && is_changable_pixel(get_palette_index(*((uint32*)(src + 4 * width))))){ + // 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 (x + 1 < width){ - if (!is_transparent_pixel(src + 4 * (width - 1)) && is_changable_pixel(get_palette_index(*((uint32*)(src + 4 * (width + 1)))))){ - // Below right + 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; From f262ef977dd70b0e3909acaa40cecf3988803bbc Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 1 Jun 2015 14:04:35 +0200 Subject: [PATCH 3/4] Fix warning and remove debugging --- src/cmdline_sprite.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/cmdline_sprite.c b/src/cmdline_sprite.c index a672b12c0c..48a2cef7c6 100644 --- a/src/cmdline_sprite.c +++ b/src/cmdline_sprite.c @@ -176,7 +176,7 @@ bool sprite_file_export(int spriteIndex, const char *outPath) } bool is_transparent_pixel(sint16 *colour){ - return colour[3] == 0; + return colour[3] < 128; } // Returns true if pixel index is an index not used for remapping @@ -218,7 +218,7 @@ int get_closest_palette_index(sint16 *colour){ int get_palette_index(sint16 *colour) { - if (colour[3] < 128) + if (is_transparent_pixel(colour)) return -1; for (int i = 0; i < 256; i++) { @@ -261,13 +261,11 @@ bool sprite_file_import(const char *path, rct_g1_element *outElement, uint8 **ou // A larger range is needed for proper dithering sint16 *src = malloc(height * width * 4 * 2); - for (int x = 0; x < height * width * 4; x++){ + for (uint32 x = 0; x < height * width * 4; x++){ src[x] = (sint16) pixels[x]; } uint8 *dst = buffer + (height * 2); - - int dos = 0; for (unsigned int y = 0; y < height; y++) { rle_code *previousCode, *currentCode; @@ -294,16 +292,6 @@ bool sprite_file_import(const char *path, rct_g1_element *outElement, uint8 **ou sint16 dg = src[1] - (sint16)(spriteFilePalette[paletteIndex].g); sint16 db = src[2] - (sint16)(spriteFilePalette[paletteIndex].b); - if (dos < 40){ - printf("Original: %d, %d, %d\n", src[0], src[1], src[2]); - printf("Chosen: %d, %d, %d\n", spriteFilePalette[paletteIndex].r, spriteFilePalette[paletteIndex].g, spriteFilePalette[paletteIndex].b); - printf("%d - %d = %d", src[0], spriteFilePalette[paletteIndex].r, src[0] - spriteFilePalette[paletteIndex].r); - printf("Pixel: %d.\n", paletteIndex); - printf("%d, %d, %d\n", dr, dg, db); - puts(""); - dos++; - } - if (x + 1 < width){ if (!is_transparent_pixel(src + 4) && is_changable_pixel(get_palette_index(src + 4))){ // Right From a3368c4a5491c2a0288b61b6bafa7fa5ddc64888 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 1 Jun 2015 15:14:15 +0200 Subject: [PATCH 4/4] Fix issue --- src/cmdline_sprite.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmdline_sprite.c b/src/cmdline_sprite.c index 48a2cef7c6..3bc2808b69 100644 --- a/src/cmdline_sprite.c +++ b/src/cmdline_sprite.c @@ -330,7 +330,7 @@ bool sprite_file_import(const char *path, rct_g1_element *outElement, uint8 **ou } src += 4; - if (is_transparent_pixel(src)) { + if (paletteIndex == -1) { if (pixels != 0) { x--; src -= 4;