diff --git a/tools/imagecon/Makefile b/tools/imagecon/Makefile index 182f573..e432f56 100644 --- a/tools/imagecon/Makefile +++ b/tools/imagecon/Makefile @@ -21,6 +21,10 @@ EHB_IMAGE=../../assets/gigi.png EHB_BASE=out/ehb REFERENCE_EHB_BASE=reference/ehb +HAM_IMAGE=../../assets/gigi.png +HAM_BASE=out/ham +REFERENCE_HAM_BASE=reference/ham + $(IMAGECON): out bin $(OBJS) gcc $(OBJS) -o $(IMAGECON) $(LIBS) @@ -53,7 +57,10 @@ $(OUTPUT_BASE).bin: $(IMAGECON) $(EHB_BASE).bin: $(EHB_IMAGE) $(IMAGECON) --input $(EHB_IMAGE) --output $(EHB_BASE) --output-bitplanes --colors 32 --quantize --extra-half-brite --output-copperlist -test: $(IMAGECON) $(OUTPUT_BASE).bin $(SHARED_PALETTE) $(USED_PALETTE) $(EHB_BASE).bin +$(HAM_BASE).bin: $(HAM_IMAGE) + $(IMAGECON) --input $(HAM_IMAGE) --output $(HAM_BASE) --output-bitplanes --ham --output-palette-asm + +test: $(IMAGECON) $(OUTPUT_BASE).bin $(SHARED_PALETTE) $(USED_PALETTE) $(EHB_BASE).bin $(HAM_BASE).bin diff $(OUTPUT_BASE).bin $(REFERENCE_BASE).bin diff $(OUTPUT_BASE)-copper-list.s $(REFERENCE_BASE)-copper-list.s diff $(OUTPUT_BASE)-palette.s $(REFERENCE_BASE)-palette.s @@ -64,6 +71,8 @@ test: $(IMAGECON) $(OUTPUT_BASE).bin $(SHARED_PALETTE) $(USED_PALETTE) $(EHB_BAS diff $(BOB_BASE)-mask.bin $(REFERENCE_BOB_BASE)-mask.bin diff $(EHB_BASE).bin $(REFERENCE_EHB_BASE).bin diff $(EHB_BASE)-copper-list.s $(REFERENCE_EHB_BASE)-copper-list.s + diff $(HAM_BASE)-ham.bin $(REFERENCE_HAM_BASE)-ham.bin + diff $(HAM_BASE)-palette.s $(REFERENCE_HAM_BASE)-palette.s @echo "______ ___ _____ _____ ___________ " @echo "| ___ \/ _ \ / ___/ ___| ___| _ \ " diff --git a/tools/imagecon/imagecon.c b/tools/imagecon/imagecon.c index 32ac7f7..8662a40 100644 --- a/tools/imagecon/imagecon.c +++ b/tools/imagecon/imagecon.c @@ -24,6 +24,7 @@ imagecon_config_t config = { .outputBitplanes = 0, .outputCopperList = 0, .ehbMode = 0, + .hamMode = 0, .quantize = 0, .overridePalette = 0 }; @@ -45,7 +46,8 @@ usage() " --output-grey-palette-asm\n"\ " --output-palette\n"\ " --extra-half-brite\n"\ - " --use-palette \n" \ + " --ham\n"\ + " --use-palette \n"\ " --verbose\n", config.argv[0]); exit(1); } @@ -222,7 +224,6 @@ generateQuantizedImage(imagecon_image_t* ic, int usePalette) color.b = ic->palette[i].b; liq_image_add_fixed_color(image, color); } - config.maxColors = ic->numColors; } liq_set_max_colors(attr, config.maxColors); @@ -255,6 +256,29 @@ generateQuantizedImage(imagecon_image_t* ic, int usePalette) ic->numColors = pal->count; } +amiga_color_t +getOriginalColor(int x, int y, imagecon_image_t* ic) +{ + png_byte* ptr = ic->rowPointers[y] + (x*4); + amiga_color_t color; + color.r = ptr[0]; + color.g = ptr[1]; + color.b = ptr[2]; + color.a = ptr[3]; + return color; +} + +amiga_color_t +getColor(int x, int y, imagecon_image_t* ic) +{ + int paletteIndex = ic->amigaImage[(ic->width*y)+x]; + amiga_color_t color; + color.r = ic->palette[paletteIndex].r; + color.g = ic->palette[paletteIndex].g; + color.b = ic->palette[paletteIndex].b; + color.a = ic->palette[paletteIndex].a; + return color; +} void generatePalette(imagecon_image_t* ic) @@ -269,6 +293,7 @@ generatePalette(imagecon_image_t* ic) for (int x=0; x < ic->width; x++) { png_byte* ptr = &(row[x*4]); + // TODO: this shift is probably wrong now amiga_color_t color; color.r = ptr[0] >> 4; color.g = ptr[1] >> 4; @@ -399,9 +424,9 @@ outputMask(char* outFilename, imagecon_image_t* ic) for (int y = 0, writeIndex = 0; y < ic->height; y++) { for (int byte = 0;byte < byteWidth; byte++) { for (int bit = 0; bit < 8; bit++) { - int x = byte * 8 + 7 - bit; - int paletteIndex = ic->amigaImage[(ic->width*y)+x]; - int bitmask = ic->palette[paletteIndex].a > 0 ? 0xFF : 0; + int x = byte * 8 + 7 - bit; + amiga_color_t c = getOriginalColor(x, y, ic); + int bitmask = c.a > 0 ? 0xFF : 0; for (int plane_index = 0; plane_index < numBitPlanes; plane_index++) { char* plane = bitplanes[plane_index]; plane[writeIndex] |= ((bitmask >> plane_index) & 1) << bit; @@ -426,53 +451,249 @@ outputMask(char* outFilename, imagecon_image_t* ic) } } +void +generateEHBImage(imagecon_image_t* ic) +{ + if (config.maxColors > 32) { + abort_("Can't do EHB emode with > 32 colors\n"); + } + // First find best N color palette + generateQuantizedImage(ic, 0); + // now add the EHB colors + + for (int i = 0; i < ic->numColors; i++) { + ic->palette[i+ic->numColors].r = ic->palette[i].r/2; + ic->palette[i+ic->numColors].g = ic->palette[i].g/2; + ic->palette[i+ic->numColors].b = ic->palette[i].b/2; + ic->palette[i+ic->numColors].a = ic->palette[i].a; + } + config.maxColors = ic->numColors = config.maxColors * 2; + //now generate the half brite version*/ + generateQuantizedImage(ic, 1); +} void +printColor(amiga_color_t color) +{ + printf("R = %03d G = %03d B = %03d A = %03d", color.r, color.g, color.b, color.a); +} + + + +int +colorDelta(amiga_color_t c1, amiga_color_t c2) +{ + int dr = abs((c1.r)-(c2.r)); + int dg = abs((c1.g)-(c2.g)); + int db = abs((c1.b)-(c2.b)); + return (dr+dg+db) / 3; +} + +typedef struct { + int control; + int data; + amiga_color_t pixel; +} ham_control_t; + +ham_control_t +findBestHamPixel(imagecon_image_t* ic, amiga_color_t color, amiga_color_t orig, amiga_color_t last) +{ + int delta = INT_MAX; + + ham_control_t ham = {0}; + + for (int i = 0; i < ic->numColors; i++) { + int dc = colorDelta(color, ic->palette[i]); + if (dc < delta) { + delta = dc; + ham.data = i; + ham.pixel = ic->palette[i]; + } + } + + delta = colorDelta(orig, ham.pixel); + if (last.r != -1) { + for (int c = 0; c <= 0xF; c++) { + amiga_color_t copy = last; + copy.r = c<<4; + int dc = colorDelta(orig, copy); + if (dc < delta) { + ham.control = 2; + ham.data = c; + ham.pixel = copy; + delta = dc; + } + } + for (int c = 0; c <= 0xF; c++) { + amiga_color_t copy = last; + copy.g = c<<4; + int dc = colorDelta(orig, copy); + if (dc < delta) { + ham.control = 3; + ham.data = c; + ham.pixel = copy; + delta = dc; + } + } + for (int c = 0; c <= 0xF; c++) { + amiga_color_t copy = last; + copy.b = c<<4; + int dc = colorDelta(orig, copy); + if (dc < delta) { + ham.control = 1; + ham.data = c; + ham.pixel = copy; + delta = dc; + } + } + } + + return ham; +} + + +void +outputHamBitplanes(char* outFilename, imagecon_image_t* ic) +{ + if (config.verbose) { + printf("outputHamBitplanes\n"); + } + + int numBitPlanes = 6; + int numColors = 16; + + if (config.verbose) { + printf("ham number of colors = %d\n", numColors); + printf("ham number of bitplanes = %d\n", numBitPlanes); + } + + int byteWidth = (ic->width + 7) / 8; + + char** bitplanes = malloc(sizeof(void*)*numBitPlanes); + for (int i = 0; i < numBitPlanes; i++) { + bitplanes[i] = calloc(byteWidth*ic->height, 1); + } + + ham_control_t* hams = malloc(sizeof(ham_control_t)*ic->width*ic->height); + + for (int y = 0; y < ic->height; y++) { + amiga_color_t lastPixel = { -1, -1, -1, -1}; + for (int x = 0; x < ic->width; x++) { + + amiga_color_t color = getColor(x, y, ic); + amiga_color_t orig = getOriginalColor(x, y, ic); + + ham_control_t ham = findBestHamPixel(ic, color, orig, lastPixel); + lastPixel = ham.pixel; + +#if 0 + printf("Color: "); + printColor(color); + printf("\n"); + printf("Orig: "); + printColor(orig); + printf("\n"); + + printf("Ham:\n"); + printf("Control: %d\n", ham.control); + printf("Data: %d\n", ham.data); + printf("Color: "); + printColor(ham.pixel); + printf("\n\n"); +#endif + + hams[(y*ic->width)+x] = ham; + } + } + + + for (int y = 0, writeIndex = 0; y < ic->height; y++) { + for (int byte = 0;byte < byteWidth; byte++) { + for (int bit = 0; bit < 8; bit++) { + int x = byte * 8 + 7 - bit; + + ham_control_t ham = hams[(y*ic->width)+x]; + + int _numBitPlanes = 4; + for (int plane_index = 0; plane_index < _numBitPlanes; plane_index++) { + char* plane = bitplanes[plane_index]; + plane[writeIndex] |= ((ham.data >> plane_index) & 1) << bit; + } + + for (int plane_index = 0; plane_index < 2; plane_index++) { + char* plane = bitplanes[4+plane_index]; + plane[writeIndex] |= ((ham.control >> plane_index) & 1) << bit; + } + + + } + writeIndex++; + } + } + + + FILE* fp = openFileWrite("%s-ham.bin", outFilename); + + for (int y = 0; y < ic->height; y++) { + for (int plane_index = 0; plane_index < numBitPlanes; plane_index++) { + char* plane = bitplanes[plane_index]; + fwrite(&plane[y*byteWidth], byteWidth, 1, fp); + } + } + fclose(fp); + if (config.verbose) { + printf("done\n\n"); + } +} + +static void +doHamMode(char* outFilename, imagecon_image_t* ic) +{ + config.maxColors = 16; + generateQuantizedImage(ic, 0); + + if (config.outputBitplanes) { + outputHamBitplanes(outFilename, ic); + } + + outputPalette(outFilename, ic); + +} + +static void processFile(char* outFilename, imagecon_image_t* ic) { if (config.verbose) { printf("processFile...\n"); } - if (config.quantize || config.overridePalette) { - if (config.ehbMode) { - if (config.maxColors > 32) { - abort_("Can't do EHB emode with > 32 colors\n"); + if (config.hamMode) { + doHamMode(outFilename, ic); + } else { + if (config.quantize || config.overridePalette) { + if (config.ehbMode) { + generateEHBImage(ic); + } else { + if (config.overridePalette) { + loadPaletteFile(ic); + } + generateQuantizedImage(ic, config.overridePalette != 0); } - // First find best N color palette - generateQuantizedImage(ic, 0); - // now add the EHB colors - - for (int i = 0; i < ic->numColors; i++) { - ic->palette[i+ic->numColors].r = ic->palette[i].r/2; - ic->palette[i+ic->numColors].g = ic->palette[i].g/2; - ic->palette[i+ic->numColors].b = ic->palette[i].b/2; - ic->palette[i+ic->numColors].a = ic->palette[i].a; - } - config.maxColors = ic->numColors = config.maxColors * 2; - printf("config.maxColors = %d\n", config.maxColors); - //now generate the half brite version*/ - generateQuantizedImage(ic, 1); } else { - if (config.overridePalette) { - loadPaletteFile(ic); - } - generateQuantizedImage(ic, config.overridePalette != 0); + generatePalette(ic); } - } else { - generatePalette(ic); + + if (config.outputBitplanes) { + outputBitplanes(outFilename, ic); + } + + if (config.outputMask) { + outputMask(outFilename, ic); + } + + outputPalette(outFilename, ic); } - if (config.outputBitplanes) { - outputBitplanes(outFilename, ic); - } - - if (config.outputMask) { - outputMask(outFilename, ic); - } - - outputPalette(outFilename, ic); - if (config.verbose) { printf("done\n\n"); } @@ -557,6 +778,7 @@ main(int argc, char **argv) {"output-grey-palette-asm", no_argument, &config.outputPaletteGrey, 1}, {"output-mask", no_argument, &config.outputMask, 1}, {"extra-half-brite", no_argument, &config.ehbMode, 1}, + {"ham", no_argument, &config.hamMode, 1}, {"use-palette", required_argument, 0, 'p'}, {"output", required_argument, 0, 'o'}, {"colors", required_argument, 0, 'c'}, diff --git a/tools/imagecon/imagecon.h b/tools/imagecon/imagecon.h index 2e5ab14..bad5512 100644 --- a/tools/imagecon/imagecon.h +++ b/tools/imagecon/imagecon.h @@ -12,18 +12,29 @@ typedef struct { int outputBitplanes; int outputCopperList; int ehbMode; + int hamMode; char* overridePalette; int quantize; int verbose; char** argv; } imagecon_config_t; +#if 0 typedef struct { unsigned char r; unsigned char g; unsigned char b; unsigned char a; } amiga_color_t; +#else +typedef struct { + int r; + int g; + int b; + int a; +} amiga_color_t; + +#endif typedef struct { diff --git a/tools/imagecon/reference/ham-ham.bin b/tools/imagecon/reference/ham-ham.bin new file mode 100644 index 0000000..f41390a Binary files /dev/null and b/tools/imagecon/reference/ham-ham.bin differ diff --git a/tools/imagecon/reference/ham-palette.s b/tools/imagecon/reference/ham-palette.s new file mode 100644 index 0000000..42197ea --- /dev/null +++ b/tools/imagecon/reference/ham-palette.s @@ -0,0 +1,35 @@ + movem.l d0-a6,-(sp) + lea CUSTOM,a6 + lea COLOR00(a6),a0 + move.w #$421,(a0) + lea COLOR01(a6),a0 + move.w #$631,(a0) + lea COLOR02(a6),a0 + move.w #$852,(a0) + lea COLOR03(a6),a0 + move.w #$210,(a0) + lea COLOR04(a6),a0 + move.w #$79a,(a0) + lea COLOR05(a6),a0 + move.w #$ea6,(a0) + lea COLOR06(a6),a0 + move.w #$c84,(a0) + lea COLOR07(a6),a0 + move.w #$a63,(a0) + lea COLOR08(a6),a0 + move.w #$552,(a0) + lea COLOR09(a6),a0 + move.w #$688,(a0) + lea COLOR10(a6),a0 + move.w #$765,(a0) + lea COLOR11(a6),a0 + move.w #$455,(a0) + lea COLOR12(a6),a0 + move.w #$fb7,(a0) + lea COLOR13(a6),a0 + move.w #$9aa,(a0) + lea COLOR14(a6),a0 + move.w #$997,(a0) + lea COLOR15(a6),a0 + move.w #$edb,(a0) + movem.l (sp)+,d0-a6