From 4c1c2f34addc6d745451ac057a69a50e46e92675 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 10 Dec 2018 12:32:26 +0100 Subject: [PATCH] Move the 1layer => C64 FLI code to C64_pixels_to_FLI() --- src/miscfileformats.c | 165 +--------------------------------- src/oldies.c | 201 ++++++++++++++++++++++++++++++++++++++++++ src/oldies.h | 13 +++ 3 files changed, 216 insertions(+), 163 deletions(-) diff --git a/src/miscfileformats.c b/src/miscfileformats.c index 149703ac..e6afc1ea 100644 --- a/src/miscfileformats.c +++ b/src/miscfileformats.c @@ -3316,37 +3316,6 @@ static int Save_C64_hires(T_IO_Context *context, byte saveWhat, byte loadAddr) return 0; } -#if defined(__GNUC__) && __GNUC__ > 2 -/* use GCC built in's */ -#define count_set_bits __builtin_popcount -#define count_trailing_zeros __builtin_ctz -#else -/** - * Count the number of bit sets - */ -static int count_set_bits(unsigned int value) -{ - int count; - - for (count = 0; value != 0; value >>= 1) - count += (value & 1); - return count; -} - -/** - * Count the number of low order zero's before the first bit set - */ -static int count_trailing_zeros(unsigned int value) -{ - int count; - - if (value == 0) - return -1; - for (count = 0; (value & 1) == 0; value >>= 1) - count++; - return count; -} -#endif /** * Save a C64 FLI (Flexible Line Interpretation) picture. @@ -3369,146 +3338,16 @@ static int count_trailing_zeros(unsigned int value) int Save_C64_fli_monolayer(T_IO_Context *context, byte saveWhat, byte loadAddr) { FILE * file; - int bx, by; // 4x8 block coordinates - int cx, cy; // coordinates inside block byte bitmap[8000],screen_ram[1024*8],color_ram[1024]; byte background[256]; - byte pixel; memset(bitmap, 0, sizeof(bitmap)); memset(screen_ram, 0, sizeof(screen_ram)); memset(color_ram, 0, sizeof(color_ram)); memset(background, 0, sizeof(background)); - for (by = 0; by < 25; by++) - { - word background_possible[8]; - word color_ram_possible[40]; - - for(cy = 0; cy < 8; cy++) - background_possible[cy] = 0xffff; - for(bx = 0; bx < 40; bx++) - color_ram_possible[bx] = 0xffff; - - // first we try to find the background color of the 8 lines - // and the Color RAM (color 11) of the 40 blocks - for(cy = 0; cy < 8; cy++) - { - for(bx = 0; bx < 40; bx++) - { - word colors_used = 0; - int n_color_used; - for(cx = 0; cx < 4; cx++) - { - pixel = Get_pixel(context, bx*4+cx, by*8+cy); - // if (pixel > 15) error - colors_used |= 1 << pixel; - } - n_color_used = count_set_bits(colors_used); - if (n_color_used == 4) - { - background_possible[cy] &= colors_used; // The background is among the color used in this 4x1 block - color_ram_possible[bx] &= colors_used; // The color 11 is among the color used in this 4x1 block - } - } - } - // Choose background (default is black #0) - for(cy = 0; cy < 8; cy++) - { - int n_possible_backgrounds = count_set_bits(background_possible[cy]); - if (n_possible_backgrounds == 0) - { - //ERROR - Warning_with_format("No possible background color for line %d.\n4x1 pixel blocks using 4 different colors must share at least one color.", by*8+cy); - return 1; - } - else - { - // pick the first one - background[by*8+cy] = count_trailing_zeros(background_possible[cy]); -#ifdef _DEBUG - if (background[by*8+cy] != 0) - GFX2_Log(GFX2_DEBUG, " y=%d background_possible=$%04x (count=%d) background color=#%d\n", - by*8+cy, background_possible[cy], n_possible_backgrounds, background[by*8+cy]); -#endif - } - } - // 2nd pass for color RAM values - for(cy = 0; cy < 8; cy++) - { - for(bx = 0; bx < 40; bx++) - { - word colors_used = 0; - int n_color_used; - for(cx = 0; cx < 4; cx++) - { - pixel = Get_pixel(context, bx*4+cx, by*8+cy); - colors_used |= 1 << pixel; - } - colors_used &= ~(1 << background[by*8+cy]); // remove background - n_color_used = count_set_bits(colors_used); - if (n_color_used == 3) - { - color_ram_possible[bx] &= colors_used; // The color 11 is among the color used in this 4x1 block - } - } - } - // choose the color RAM values (default to #0) - for(bx = 0; bx < 40; bx++) - { - int n_possibles_color11 = count_set_bits(color_ram_possible[bx]); - if (n_possibles_color11 == 0) - { - Warning_with_format("No possible color RAM value for 4x8 block (%d,%d) coordinates (%d,%d)\nThe 8 4x1 blocks must share a color.", bx, by, bx*4, by*8); - return 1; - } - else - { - color_ram[by*40+bx] = count_trailing_zeros(color_ram_possible[bx]); -#ifdef _DEBUG - if (color_ram[by*40+bx] != 0) - GFX2_Log(GFX2_DEBUG, "bx=%d by=%d color_ram_possible=%04x (count=%d) color11=#%d\n", - bx, by, color_ram_possible[bx], n_possibles_color11, color_ram[by*40+bx]); -#endif - } - } - // Now it is possible to encode Screen RAM and Bitmap - for(cy = 0; cy < 8; cy++) - { - for(bx = 0; bx < 40; bx++) - { - byte bits = 0; - byte c[4]; - c[0] = background[by*8+cy]; // color 00 = background - c[1] = c[0]; // color 01 (defaulting to same as background) - c[2] = c[1]; // color 10 (defaulting to same as background) - c[3] = color_ram[by*40+bx]; // color 11 = color RAM value - for(cx = 0; cx < 4; cx++) - { - bits <<= 2; - pixel = Get_pixel(context, bx*4+cx, by*8+cy); - if (pixel == c[0]) // background => color 00 - continue; - if(pixel == c[3]) // color RAM value => color 11 - bits |= 3; - else - { - if (c[1] == c[0]) - c[1] = pixel; // set color 01 = upper nibble of screen RAM - if (pixel == c[1]) - bits |= 1; - else - { - c[2] = pixel; // set color 02 = lower nibble of screen RAM - bits |= 2; - } - } - } - screen_ram[1024*cy + bx + by * 40] = (c[1] << 4) | c[2]; - bitmap[(by*40 + bx)*8 + cy] = bits; - } - } - } + if (C64_pixels_to_FLI(bitmap, screen_ram, color_ram, background, context->Target_address, context->Pitch) > 0) + return 1; file = Open_file_write(context); diff --git a/src/oldies.c b/src/oldies.c index 10a958d7..a9d6b5f2 100644 --- a/src/oldies.c +++ b/src/oldies.c @@ -46,6 +46,41 @@ #endif #endif +#if defined(__GNUC__) && __GNUC__ > 2 +/* use GCC built in's */ +#define count_set_bits __builtin_popcount +#define count_trailing_zeros __builtin_ctz +#else +/** + * Count the number of bit sets "Popcount" + * + * Based on Wikipedia article for Hamming_weight, it's optimized + * for cases when zeroes are more frequent. + */ +static int count_set_bits(unsigned int value) +{ + int count; + + for (count = 0; value != 0; count++) + value &= value-1; + return count; +} + +/** + * Count the number of low order zero's before the first bit set + */ +static int count_trailing_zeros(unsigned int value) +{ + int count; + + if (value == 0) + return -1; + for (count = 0; (value & 1) == 0; value >>= 1) + count++; + return count; +} +#endif + #if 0 static void Set_Pixel_in_layer(word x,word y, byte layer, byte color) { @@ -364,6 +399,172 @@ int C64_FLI(T_IO_Context * context, byte *bitmap, byte *screen_ram, byte *color_ } +int C64_pixels_to_FLI(byte *bitmap, byte *screen_ram, byte *color_ram, byte *background, const byte * pixels, long pitch) +{ + int bx, by; // 4x8 block coordinates + int cx, cy; // coordinates inside block + byte pixel; + int error_count = 0; + + for (by = 0; by < 25; by++) + { + word background_possible[8]; + word color_ram_possible[40]; + + for(cy = 0; cy < 8; cy++) + background_possible[cy] = 0xffff; + for(bx = 0; bx < 40; bx++) + color_ram_possible[bx] = 0xffff; + + // first we try to find the background color of the 8 lines + // and the Color RAM (color 11) of the 40 blocks + for(cy = 0; cy < 8; cy++) + { + for(bx = 0; bx < 40; bx++) + { + word colors_used = 0; + int n_color_used; + for(cx = 0; cx < 4; cx++) + { + pixel = pixels[bx*4+cx + pitch*(by*8+cy)]; + // if (pixel > 15) error + colors_used |= 1 << pixel; + } + n_color_used = count_set_bits(colors_used); + if (n_color_used == 4) + { + background_possible[cy] &= colors_used; // The background is among the color used in this 4x1 block + color_ram_possible[bx] &= colors_used; // The color 11 is among the color used in this 4x1 block + } + } + } + // Choose background (default is black #0) + for(cy = 0; cy < 8; cy++) + { + int n_possible_backgrounds = count_set_bits(background_possible[cy]); + if (n_possible_backgrounds == 0) + { + //ERROR + Warning_with_format("No possible background color for line %d.\n4x1 pixel blocks using 4 different colors must share at least one color.", by*8+cy); + return 1; + } + else + { + // pick the first one + background[by*8+cy] = count_trailing_zeros(background_possible[cy]); +#ifdef _DEBUG + if (background[by*8+cy] != 0) + GFX2_Log(GFX2_DEBUG, " y=%d background_possible=$%04x (count=%d) background color=#%d\n", + by*8+cy, background_possible[cy], n_possible_backgrounds, background[by*8+cy]); +#endif + } + } + // 2nd pass for color RAM values + for(bx = 0; bx < 40; bx++) + { + word color_usage[16]; + + memset(color_usage, 0, sizeof(color_usage)); + for(cy = 0; cy < 8; cy++) + { + word colors_used = 0; + int n_color_used; + for(cx = 0; cx < 4; cx++) + { + pixel = pixels[bx*4+cx + pitch*(by*8+cy)]; + if (pixel < 16) + { + colors_used |= 1 << pixel; + color_usage[pixel]++; + } + } + colors_used &= ~(1 << background[by*8+cy]); // remove background + n_color_used = count_set_bits(colors_used); + if (n_color_used == 3) + { + color_ram_possible[bx] &= colors_used; // The color 11 is among the color used in this 4x1 block + } + } + // choose the color RAM values (default to #0) + if (color_ram_possible[bx] == 0) + { + Warning_with_format("No possible color RAM value for 4x8 block (%d,%d) coordinates (%d,%d)\nThe 8 4x1 blocks must share a color.", bx, by, bx*4, by*8); + return 1; + } + else + { + word possible = color_ram_possible[bx]; + // avoid using same color as background + for(cy = 0; cy < 8; cy++) + possible &= ~(1 << background[by*8+cy]); + + if (possible != 0) + { // pickup most used color (but not background color) + byte col; + word max_usage = 0; + byte max_index = count_trailing_zeros(possible); // default to 1st color (except background) + + for (col = max_index; col < 16; col++) + { + if ((possible & (1 << col)) != 0 && color_usage[col] > max_usage) + { + max_usage = color_usage[col]; + max_index = col; + } + } + color_ram[by*40+bx] = max_index; + } + else + color_ram[by*40+bx] = count_trailing_zeros(color_ram_possible[bx]); +#ifdef _DEBUG + if (color_ram[by*40+bx] != 0) + GFX2_Log(GFX2_DEBUG, "bx=%d by=%d color_ram_possible=%04x color11=#%d\n", + bx, by, color_ram_possible[bx], color_ram[by*40+bx]); +#endif + } + } + // Now it is possible to encode Screen RAM and Bitmap + for(cy = 0; cy < 8; cy++) + { + for(bx = 0; bx < 40; bx++) + { + byte bits = 0; + byte c[4]; + c[0] = background[by*8+cy]; // color 00 = background + c[1] = c[0]; // color 01 (defaulting to same as background) + c[2] = c[1]; // color 10 (defaulting to same as background) + c[3] = color_ram[by*40+bx]; // color 11 = color RAM value + for(cx = 0; cx < 4; cx++) + { + bits <<= 2; + pixel = pixels[bx*4+cx + pitch*(by*8+cy)]; + if (pixel == c[0]) // background => color 00 + continue; + if(pixel == c[3]) // color RAM value => color 11 + bits |= 3; + else + { + if (c[1] == c[0]) + c[1] = pixel; // set color 01 = upper nibble of screen RAM + if (pixel == c[1]) + bits |= 1; + else + { + c[2] = pixel; // set color 02 = lower nibble of screen RAM + bits |= 2; + } + } + } + screen_ram[1024*cy + bx + by * 40] = (c[1] << 4) | c[2]; + bitmap[(by*40 + bx)*8 + cy] = bits; + } + } + } + + return error_count; +} + + #if 0 int C64_FLI_enforcer(void) { diff --git a/src/oldies.h b/src/oldies.h index 371dee7b..c4f9d46c 100644 --- a/src/oldies.h +++ b/src/oldies.h @@ -40,6 +40,19 @@ */ int C64_FLI(T_IO_Context * context, byte *bitmap, byte *screen_ram, byte *color_ram, byte *background); +/** + * Convert a (1 layer) picture to C64 FLI format + * + * @param bitmap a 8000 byte buffer to store bitmap data + * @param screen_ram a 8192 byte buffer to store the 8 screen RAMs + * @param color_ram a 1000 byte buffer to store the color RAM + * @param background a 200 byte buffer to store the background colors + * @param pixels source pixel buffer (at least 160x200) + * @param pitch bytes per line of the pixel buffer + * @return 0 the number of constraint errors + */ +int C64_pixels_to_FLI(byte *bitmap, byte *screen_ram, byte *color_ram, byte *background, const byte * pixels, long pitch); + #if 0 /** * FLI Check/enforcer