diff --git a/001.simple_image/Makefile b/001.simple_image/Makefile index 02a6832..6471c11 100644 --- a/001.simple_image/Makefile +++ b/001.simple_image/Makefile @@ -7,4 +7,4 @@ MODULE=image.s include ../base.mk $(EXTRA): $(IMAGECON) $(IMAGEFILE) - $(IMAGECON) --input $(IMAGEFILE) --output out/image --colors 32 --quantize + $(IMAGECON) --input $(IMAGEFILE) --output out/image --colors 32 --quantize --output-bitplanes --output-copperlist diff --git a/003.music/Makefile b/003.music/Makefile index 221fc9d..a73b3fc 100644 --- a/003.music/Makefile +++ b/003.music/Makefile @@ -7,4 +7,4 @@ MODULE=music.s include ../base.mk $(EXTRA): $(IMAGECON) $(IMAGEFILE) - $(IMAGECON) --input $(IMAGEFILE) --output out/image --colors 32 --quantize + $(IMAGECON) --input $(IMAGEFILE) --output out/image --colors 32 --quantize --output-bitplanes --output-copperlist diff --git a/006.simple_blit/Makefile b/006.simple_blit/Makefile index 58668e8..3731873 100644 --- a/006.simple_blit/Makefile +++ b/006.simple_blit/Makefile @@ -4,15 +4,17 @@ IMAGEDATA=out/image-copper-list.s out/image.bin IMAGEFILE=../assets/mission-beach.png TC_IMAGEDATA=out/tc.bin out/tc-mask.bin TC_IMAGEFILE=../assets/tc.png -EXTRA=$(IMAGEDATA) $(TC_IMAGEDATA) out/bitblit.s +EXTRA=$(IMAGEDATA) $(TC_IMAGEDATA) +SHARED_PALETTE_BASE=out/shared-palette +SHARED_PALETTE=$(SHARED_PALETTE_BASE).pal include ../base.mk -out/bitblit.s: bitblit.c - vc -S bitblit.c -o out/bitblit.s +$(SHARED_PALETTE): $(IMAGEFILE) $(TC_IMAGEFILE) + $(IMAGECON) --input $(IMAGEFILE),$(TC_IMAGEFILE) --output $(SHARED_PALETTE_BASE) --colors 32 --quantize --output-palette -$(IMAGEDATA): $(IMAGECON) $(IMAGEFILE) - $(IMAGECON) --input $(IMAGEFILE) --output out/image --colors 32 --quantize +$(IMAGEDATA): $(IMAGECON) $(IMAGEFILE) $(SHARED_PALETTE) + $(IMAGECON) --input $(IMAGEFILE) --output out/image --output-bitplanes --output-copperlist --override-palette $(SHARED_PALETTE) -$(TC_IMAGEDATA): $(IMAGECON) $(TC_IMAGEFILE) - $(IMAGECON) --input $(TC_IMAGEFILE) --output out/tc --colors 32 --quantize --output-mask +$(TC_IMAGEDATA): $(IMAGECON) $(TC_IMAGEFILE) $(SHARED_PALETTE) + $(IMAGECON) --input $(TC_IMAGEFILE) --output out/tc --output-bitplanes --output-mask --output-copperlist --override-palette $(SHARED_PALETTE) diff --git a/006.simple_blit/README.md b/006.simple_blit/README.md index 08af624..749a960 100644 --- a/006.simple_blit/README.md +++ b/006.simple_blit/README.md @@ -1,15 +1,18 @@ -Display a simple image -====================== +perform a basic blit +===================== -Building on [trackdisk.device](../000.trackdisk), we now display a simple color image. +We make some changes to [001.simple_image)(../001.simple_image): + 1. The bitplane pointers are now reset using the copper. + 2. Interrupt processing is disabled + 3. A6 is now used as the base register for CUSTOM -I display a 5 bitplane (32 color) low res image. +Next we use some new features in [imagecon](../tools/imagecon) that allow us to generate a shared palette based on two PNG images. -The image data is prepared using a new tool I wrote called [imagecon](../tools/imagecon/imagecon.c). This takes (almost) any 320x256 PNG and using [libimagequant](https://pngquant.org/lib/) it reduces the palette to 32 colors, then dumps out the copper list and interleaved bitplane data ready to be included into [image.s](image.s). +This means out sprite and background can share the single palette. -The original version of this example used [vilcans amiga-startup](https://github.com/vilcans/amiga-startup) as a starting point, however almost all of that code has been replaced as my understanding exanded. +We then blit the sprite to the background. -[Download disk image](bin/image.adf?raw=true) +[Download disk image](bin/blit.adf?raw=true) Screenshot: diff --git a/006.simple_blit/bin/blit.adf b/006.simple_blit/bin/blit.adf index 8cf5b8b..fb36b0e 100644 Binary files a/006.simple_blit/bin/blit.adf and b/006.simple_blit/bin/blit.adf differ diff --git a/006.simple_blit/bitblit.c b/006.simple_blit/bitblit.c deleted file mode 100644 index 564e91c..0000000 --- a/006.simple_blit/bitblit.c +++ /dev/null @@ -1,43 +0,0 @@ -#include "hardware/custom.h" -#include "hardware/dmabits.h" - -/* -Scrollit: -;; --- scroll! --- -bltoffs =plotY*ScrBpl*3 - -blth =20 -bltw =w/16 - bltskip =0 ;modulo -brcorner=blth*ScrBpl*3-2 - - movem.l d0-a6,-(sp) - lea $dff000,a6 - bsr BlitWait - - move.l #$49f00002,BLTCON0(a6) - move.l #$ffffffff,BLTAFWM(a6) - move.l #Screen+bltoffs+brcorner,BLTAPTH(a6) - move.l #Screen+bltoffs+brcorner,BLTDPTH(a6) - move.w #bltskip,BLTAMOD(a6) - move.w #bltskip,BLTDMOD(a6) - - move.w #blth*3*64+bltw,BLTSIZE(a6) - movem.l (sp)+,d0-a6 - rts -*/ - - - -extern void blitwait(void); - -void bitblit(unsigned* src, unsigned* dest, unsigned sw, unsigned dw, unsigned dx, unsigned dy) -{ - static struct Custom *custom = (struct Custom *)0xDFF000; - - custom->dmacon = (DMAF_SETCLR|DMAF_COPPER|DMAF_RASTER|DMAF_MASTER); - /* - blitwait(); - custom->bltcon0 = 0x49f00002; - custom->bltafwm = 0xffffffff;*/ -} diff --git a/006.simple_blit/blit.s b/006.simple_blit/blit.s index 0704843..a5d2f51 100644 --- a/006.simple_blit/blit.s +++ b/006.simple_blit/blit.s @@ -12,8 +12,6 @@ RASTER_X_START equ $81 ; hard coded coordinates from hardware manual RASTER_Y_START equ $2c RASTER_X_STOP equ RASTER_X_START+SCREEN_WIDTH RASTER_Y_STOP equ RASTER_Y_START+SCREEN_HEIGHT - - public _bitblit entry: ;; custom chip base globally in a6 @@ -22,8 +20,7 @@ entry: move #$7ff,DMACON(a6) ; disable all dma move #$7fff,INTENA(a6) ; disable all interrupts - ;; bsr.s resetBitplanePointers - ;; reset color registers to white + ;; reset color registers to white to prevent startup flicker move.l #32,d0 lea COLOR00(a6),a0 .loop: @@ -108,21 +105,21 @@ TC_WIDTH_BYTES equ TC_WIDTH/8 TC_WIDTH_WORDS equ TC_WIDTH/16 TC_XPOS equ 16 TC_YPOS equ 16 +TC_XPOS_BYTES equ (TC_XPOS)/8 + doblit: movem.l d0-a6,-(sp) - lea $dff000,a6 bsr blitWait move.l #$09f00000,BLTCON0(a6) ;A->D copy, no shifts, ascending mode move.l #$ffffffff,BLTAFWM(a6) ;no masking of first/last word move.w #0,BLTAMOD(a6) ;A modulo=bytes to skip between lines move.w #SCREEN_WIDTH_BYTES-TC_WIDTH_BYTES,BLTDMOD(a6) ;D modulo move.l #tc,BLTAPTH(a6) ;source graphic top left corner - move.l #bitplanes+(TC_XPOS)/8+(SCREEN_WIDTH_BYTES*SCREEN_BIT_DEPTH*TC_YPOS),BLTDPTH(a6) ;destination top left corner - move.w #(TC_HEIGHT*SCREEN_BIT_DEPTH)<<6|(TC_WIDTH_WORDS),BLTSIZE(a6) ;rectangle size, starts blit + move.l #bitplanes+TC_XPOS_BYTES+(SCREEN_WIDTH_BYTES*SCREEN_BIT_DEPTH*TC_YPOS),BLTDPTH(a6) ;destination top left corner + move.w #(TC_HEIGHT*SCREEN_BIT_DEPTH)<<6|(TC_WIDTH_WORDS),BLTSIZE(a6) ;rectangle size, starts blit movem.l (sp)+,d0-a6 rts - include "out/bitblit.s" copper: ;; bitplane pointers must be first else poking addresses will be incorrect dc.w BPL1PTL,0 diff --git a/examples/link.script b/examples/link.script new file mode 100644 index 0000000..4977fad --- /dev/null +++ b/examples/link.script @@ -0,0 +1,14 @@ +MEMORY +{ +ram: org = 0x70000, len = 0x100000 +} + +SECTIONS +{ +.text : { *(.text) } > ram +.bss : { *(.bss) } > ram +.data : { *(.data) } > ram +CODE : { *(CODE) } > ram +DATA : { *(DATA) } > ram +} + diff --git a/tools/imagecon/Makefile b/tools/imagecon/Makefile index 27386b0..ba4b3cc 100644 --- a/tools/imagecon/Makefile +++ b/tools/imagecon/Makefile @@ -7,10 +7,13 @@ REFERENCE_BASE=reference/mission-beach TEST_IMAGE=../../assets/mission-beach.png LIBS=-lpng -limagequant -$(IMAGECON): out bin $(OBJS) +$(IMAGECON): out bin $(OBJS) gcc $(OBJS) -o $(IMAGECON) $(LIBS) +out/imagecon.o: imagecon.h +out/png.o: imagecon.h + out/%.o: %.c gcc -c $(HOST_CFLAGS) $< -o $@ @@ -22,7 +25,7 @@ bin: out/mission-beach.bin: $(IMAGECON) -rm -f $(OUTPUT_BASE).bin $(OUTPUT_BASE)-copper-list.s - $(IMAGECON) --input $(TEST_IMAGE) --output $(OUTPUT_BASE) --colors 32 --quantize + $(IMAGECON) --input $(TEST_IMAGE) --output $(OUTPUT_BASE) --output-copperlist --output-bitplanes --colors 32 --quantize test: $(IMAGECON) $(OUTPUT_BASE).bin diff $(OUTPUT_BASE).bin $(REFERENCE_BASE).bin diff --git a/tools/imagecon/README.md b/tools/imagecon/README.md index cc3b452..e6f26ad 100644 --- a/tools/imagecon/README.md +++ b/tools/imagecon/README.md @@ -6,24 +6,32 @@ Generate amiga data/files from a PNG image file. usage ----- ``` - imagecon: --input [options] - Options: + imagecon: --input [options] + options: --output --colors --quantize --output-palette + --output-bitplanes + --output-mask + --output-copperlist --override-palette --verbose ``` -The following files will be generated: +The following files can be generated: 1. **<output prefix>.bin** binary interleave bitplane data 2. **<output prefix>-copper-list.s** m68k assembler syntax copper list with no symbols -3. **<output prefix>.pal** (optional) palette file listing the palette colors as hex +3. **<output prefix>.pal** palette file listing the palette colors as hex +3. **<output prefix>-mask.bin** binary interleave bitplane mask options ------- +**--input** i<nput1.png,input2.png...> + +Specify the file(s) to be processed. Multiple files are coma separated. If bitplane output is directed, the bitplane data is appended vertically filling any empty portions with color index zero. + **--output** <output prefix> Specify the prefix for the output file set. Extentions will be added to this. Default is the input file name minus the extension. @@ -36,6 +44,18 @@ Specify the maximum number of colors allowed in the palette. Acceptable values a Convert the image to use less colors. +**--output-bitplanes** + +Output the binary bitplane data in interleaved format + +**--output-copperlist** + +Output the copper is as a series of m68k instructions (No labels are generated) + +**--output-mask** + +Output the binary bitplane data for use as a blitter source mask + **--output-palette** Generate a palette file of the final palette used. Output will be the output file with the ".pal" extension. @@ -50,6 +70,15 @@ Display debugging information example ------- + +Create a copper list and bitplane data file with an automatically generate 32 color palette. ``` - ./imagecon --input full_color.png --output image-data --quantize --colors 32 --palette + ./imagecon --input full_color.png --output image-data --quantize --colors 32 --output-bitplanes --output-copperlist +``` + +Create a shared palette based on two files, then use that palette to generate image and copper list data for each file. +``` + ./imagecon --input file1.png,file2.png --output shared --quantize --colors 32 --output-palette + ./imagecon --input file1.png --output file1 --override-palette shared.pal --output-bitplanes --output-copperlist + ./imagecon --input file2.png --output file2 --override-palette shared.pal --output-bitplanes --output-copperlist ``` diff --git a/tools/imagecon/imagecon.c b/tools/imagecon/imagecon.c index c87a81d..d833764 100644 --- a/tools/imagecon/imagecon.c +++ b/tools/imagecon/imagecon.c @@ -18,22 +18,28 @@ imagecon_config_t config = { .maxColors = MAX_PALETTE, .outputPalette = 0, .outputMask = 0, + .outputBitplanes = 0, + .outputCopperList = 0, .quantize = 0, .overridePalette = 0 }; -typedef struct { - unsigned char r; - unsigned char g; - unsigned char b; - unsigned char a; -} amiga_color_t; - void usage() { - fprintf(stderr, "%s: --input [options]\nOptions:\n --output \n --colors \n --quantize\n --output-mask\n --output-palette\n --override-palette \n --verbose\n", config.argv[0]); + fprintf(stderr, + "%s: --input [options]\n"\ + "options:\n"\ + " --output \n"\ + " --colors \n"\ + " --quantize\n --output-mask\n"\ + " --output-bitplanes\n"\ + " --output-copperlist\n"\ + " --output-mask\n"\ + " --output-palette\n"\ + " --override-palette \n"\ + " --verbose\n", config.argv[0]); exit(1); } @@ -90,14 +96,19 @@ openFileRead(const char * s, ...) void -outputPalette(char* outFilename, amiga_color_t* palette, int numColors) +outputPalette(char* outFilename, imagecon_image_t* ic) { if (config.verbose) { printf("outputPalette...\n"); } - FILE* fp = openFileWrite("%s-copper-list.s", outFilename); + FILE* fp = 0; FILE* paletteFP = 0; + + if (config.outputCopperList) { + fp = openFileWrite("%s-copper-list.s", outFilename); + } + if (config.outputPalette) { paletteFP = openFileWrite("%s.pal", outFilename); } @@ -106,20 +117,25 @@ outputPalette(char* outFilename, amiga_color_t* palette, int numColors) printf("outputPalette:\n"); } - for (int i = 0; i < numColors; i++) { + for (int i = 0; i < ic->numColors; i++) { if (config.verbose) { - printf("%02d: hex=%03x r=%03d g=%03d b=%03d a=%03d\n", i , palette[i].r << 8 | palette[i].g << 4 | palette[i].b, palette[i].r, palette[i].g, palette[i].b, palette[i].a); + printf("%02d: hex=%03x r=%03d g=%03d b=%03d a=%03d\n", i , ic->palette[i].r << 8 | ic->palette[i].g << 4 | ic->palette[i].b, ic->palette[i].r, ic->palette[i].g, ic->palette[i].b, ic->palette[i].a); } if (paletteFP) { - fprintf(paletteFP, "%03x\n", palette[i].r << 8 | palette[i].g << 4 | palette[i].b); + fprintf(paletteFP, "%03x\n", ic->palette[i].r << 8 | ic->palette[i].g << 4 | ic->palette[i].b); + } + if (fp) { + fprintf(fp, "\tdc.w $%x,$%x\n", 0x180+(i*2), ic->palette[i].r << 8 | ic->palette[i].g << 4 | ic->palette[i].b); } - fprintf(fp, "\tdc.w $%x,$%x\n", 0x180+(i*2), palette[i].r << 8 | palette[i].g << 4 | palette[i].b); } + if (paletteFP) { fclose(paletteFP); } - fclose(fp); + if (fp) { + fclose(fp); + } if (config.verbose) { printf("done\n\n"); @@ -127,15 +143,15 @@ outputPalette(char* outFilename, amiga_color_t* palette, int numColors) } -int -generateQuantizedPalette(unsigned char* amigaImage, png_bytep* rowPointers, amiga_color_t* palette) +void +generateQuantizedPalette(imagecon_image_t* ic) { if (config.verbose) { printf("generateQuantizedPalette...\n"); } liq_attr *attr = liq_attr_create(); - liq_image *image = liq_image_create_rgba_rows(attr, (void**)rowPointers, config.width, config.height, 0); + liq_image *image = liq_image_create_rgba_rows(attr, (void**)ic->rowPointers, ic->width, ic->height, 0); if (config.overridePalette) { FILE* fp = openFileRead(config.overridePalette); @@ -163,48 +179,49 @@ generateQuantizedPalette(unsigned char* amigaImage, png_bytep* rowPointers, amig config.maxColors = paletteIndex; } + liq_set_max_colors(attr, config.maxColors); liq_set_speed(attr, 1); liq_result *res = liq_quantize_image(attr, image); - liq_write_remapped_image(res, image, amigaImage, config.width*config.height); - + liq_write_remapped_image(res, image, ic->amigaImage, ic->width*ic->height); + const liq_palette *pal = liq_get_palette(res); if (config.verbose) { printf("pal->count = %d\n", pal->count); printf("generateQuantizedPalette: post liq_write_remapped_image\n"); } - + for (unsigned i = 0; i < pal->count; i++) { if (config.verbose) { printf("%02d: r=%03d g=%03d b=%03d a=%03d\n", i, pal->entries[i].r, pal->entries[i].g, pal->entries[i].b, pal->entries[i].a); } - palette[i].r = pal->entries[i].r >> 4; - palette[i].g = pal->entries[i].g >> 4; - palette[i].b = pal->entries[i].b >> 4; - palette[i].a = pal->entries[i].a >> 4; + ic->palette[i].r = pal->entries[i].r >> 4; + ic->palette[i].g = pal->entries[i].g >> 4; + ic->palette[i].b = pal->entries[i].b >> 4; + ic->palette[i].a = pal->entries[i].a >> 4; } if (config.verbose) { printf("done\n\n"); } - return pal->count; + ic->numColors = pal->count; } -int -generatePalette(unsigned char* amigaImage, png_bytep* rowPointers, amiga_color_t* palette) +void +generatePalette(imagecon_image_t* ic) { if (config.verbose) { printf("generatePalette...\n"); } int paletteIndex = 0; - for (int y=0; yheight; y++) { + png_byte* row = ic->rowPointers[y]; + for (int x=0; x < ic->width; x++) { png_byte* ptr = &(row[x*4]); amiga_color_t color; @@ -215,7 +232,7 @@ generatePalette(unsigned char* amigaImage, png_bytep* rowPointers, amiga_color_t int index = -1; for (int i = 0; i < paletteIndex; i++) { - if (memcmp(&palette[i], &color, sizeof(amiga_color_t)) == 0) { + if (memcmp(&ic->palette[i], &color, sizeof(amiga_color_t)) == 0) { index = i; break; } @@ -229,8 +246,8 @@ generatePalette(unsigned char* amigaImage, png_bytep* rowPointers, amiga_color_t abort_("Too many colors. Use --quantize.\n"); } - palette[index] = color ; - amigaImage[(config.width*y)+x] = index; + ic->palette[index] = color ; + ic->amigaImage[(ic->width*y)+x] = index; } } @@ -238,37 +255,38 @@ generatePalette(unsigned char* amigaImage, png_bytep* rowPointers, amiga_color_t printf("done\n\n"); } - return paletteIndex; + ic->numColors = paletteIndex; } + void -outputBitplanes(char* outFilename, unsigned char* amigaImage, int numColors) +outputBitplanes(char* outFilename, imagecon_image_t* ic) { if (config.verbose) { printf("outputBitplanes...\n"); } - int numBitPlanes = (int)(log(numColors-1) / log(2))+1; + int numBitPlanes = (int)(log(ic->numColors-1) / log(2))+1; if (config.verbose) { - printf("number of colors = %d\n", numColors); + printf("number of colors = %d\n", ic->numColors); printf("number of bitplanes = %d\n", numBitPlanes); } - int byteWidth = (config.width + 7) / 8; + int byteWidth = (ic->width + 7) / 8; char** bitplanes = malloc(sizeof(void*)*numBitPlanes); for (int i = 0; i < numBitPlanes; i++) { - bitplanes[i] = calloc(byteWidth*config.height, 1); + bitplanes[i] = calloc(byteWidth*ic->height, 1); } - for (int y = 0, writeIndex = 0; y < config.height; y++) { + 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 palette_index = amigaImage[(config.width*y)+x]; + int palette_index = ic->amigaImage[(ic->width*y)+x]; for (int plane_index = 0; plane_index < numBitPlanes; plane_index++) { char* plane = bitplanes[plane_index]; plane[writeIndex] |= ((palette_index >> plane_index) & 1) << bit; @@ -278,10 +296,9 @@ outputBitplanes(char* outFilename, unsigned char* amigaImage, int numColors) } } - FILE* fp = openFileWrite("%s.bin", outFilename); - for (int y = 0; y < config.height; y++) { + 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); @@ -293,28 +310,28 @@ outputBitplanes(char* outFilename, unsigned char* amigaImage, int numColors) } } + void -outputMask(char* outFilename, unsigned char* amigaImage, amiga_color_t* palette, int numColors) +outputMask(char* outFilename, imagecon_image_t* ic) { if (config.verbose) { printf("outputMask...\n"); } - int numBitPlanes = (int)(log(numColors-1) / log(2))+1; + int numBitPlanes = (int)(log(ic->numColors-1) / log(2))+1; - int byteWidth = (config.width + 7) / 8; + int byteWidth = (ic->width + 7) / 8; char** bitplanes = malloc(sizeof(void*)*numBitPlanes); for (int i = 0; i < numBitPlanes; i++) { - bitplanes[i] = calloc(byteWidth*config.height, 1); + bitplanes[i] = calloc(byteWidth*ic->height, 1); } - - for (int y = 0, writeIndex = 0; y < config.height; y++) { + 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 = amigaImage[(config.width*y)+x]; - int bitmask = palette[paletteIndex].a > 0 ? 0xFF : 0; + int paletteIndex = ic->amigaImage[(ic->width*y)+x]; + int bitmask = ic->palette[paletteIndex].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; @@ -326,7 +343,7 @@ outputMask(char* outFilename, unsigned char* amigaImage, amiga_color_t* palette, FILE* fp = openFileWrite("%s-mask.bin", outFilename); - for (int y = 0; y < config.height; y++) { + 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); @@ -339,38 +356,91 @@ outputMask(char* outFilename, unsigned char* amigaImage, amiga_color_t* palette, } } + void -processFile(char* outFilename, png_bytep* rowPointers) +processFile(char* outFilename, imagecon_image_t* ic) { if (config.verbose) { printf("processFile...\n"); } - int numColors; - amiga_color_t palette[MAX_PALETTE]; - - unsigned char* amigaImage = 0; - - amigaImage = calloc(config.width*config.height, 1); - if (config.quantize || config.overridePalette) { - numColors = generateQuantizedPalette(amigaImage, rowPointers, palette); + generateQuantizedPalette(ic); } else { - numColors = generatePalette(amigaImage, rowPointers, palette); + generatePalette(ic); } - outputBitplanes(outFilename, amigaImage, numColors); + if (config.outputBitplanes) { + outputBitplanes(outFilename, ic); + } if (config.outputMask) { - outputMask(outFilename, amigaImage, palette, numColors); + outputMask(outFilename, ic); } - outputPalette(outFilename, palette, numColors); + + outputPalette(outFilename, ic); if (config.verbose) { printf("done\n\n"); } } + +void +splitFiles(char* inputFile, int* count, char*** vector) +{ + char* ptr = inputFile; + char* end; + char** files = calloc(sizeof(void*), 1); + int index = 0; + do { + end = strchr(ptr, ','); + char* file; + if (end) { + file = calloc(end-ptr+1, 1); + strncpy(file, ptr, end-ptr); + ptr = end+1; + } else { + file = calloc(strlen(ptr)+1, 1); + strcpy(file, ptr); + } + + files[index++] = file; + files = realloc(files, index*sizeof(void*)); + + } while (end != 0); + + + *vector = files; + *count = index; +} + +#define max(x,y) (x > y ? x : y) + +void +combineImages(imagecon_image_t** images, int numImages, imagecon_image_t* ic) +{ + ic->width = 0; + ic->height = 0; + + for (int i = 0; i < numImages; i++) { + ic->width = max(images[i]->width, ic->width); + ic->height += images[i]->height; + } + + ic->rowPointers = (png_bytep*) malloc(sizeof(png_bytep) * ic->height); + ic->amigaImage = calloc(ic->width*ic->height, 1); + + for (int y = 0; y < ic->height; y++) { + ic->rowPointers[y] = (png_byte*) calloc(ic->width*4, 1); + } + + for (int i = 0, ny = 0; i < numImages; i++) { + for (int y = 0; y < images[i]->height; y++, ny++) { + memcpy(ic->rowPointers[ny], images[i]->rowPointers[y], images[i]->width*4); + } + } +} int @@ -384,6 +454,8 @@ main(int argc, char **argv) static struct option long_options[] = { {"verbose", no_argument, &config.verbose, 1}, {"quantize", no_argument, &config.quantize, 1}, + {"output-copperlist", no_argument, &config.outputCopperList, 1}, + {"output-bitplanes", no_argument, &config.outputBitplanes, 1}, {"output-palette", no_argument, &config.outputPalette, 1}, {"output-mask", no_argument, &config.outputMask, 1}, {"override-palette", required_argument, 0, 'p'}, @@ -444,11 +516,26 @@ main(int argc, char **argv) usage(); } - if (config.verbose) { - printf("Options:\nverbose = %d\ninputFile = %s\noutputFile = %s\nmaxColors = %d\noutputPalette = %d\noutputMask = %d\n\n", config.verbose, inputFile, outputFile, config.maxColors, config.outputPalette, config.outputMask); + if (strchr(inputFile, ',') == 0) { + imagecon_image_t ic = {0}; + png_read(inputFile, &ic); + processFile(outputFile, &ic); + } else { + char** files; + int numFiles; + splitFiles(inputFile, &numFiles, &files); + + imagecon_image_t** images = malloc(sizeof(imagecon_image_t*)*numFiles); + + for (int i = 0; i < numFiles; i++) { + images[i] = calloc(sizeof(imagecon_image_t), 1); + png_read(files[i], images[i]); + } + + imagecon_image_t combined; + combineImages(images, numFiles, &combined); + processFile(outputFile, &combined); } - - processFile(outputFile, png_read(inputFile)); return 0; } diff --git a/tools/imagecon/imagecon.h b/tools/imagecon/imagecon.h index 3fdeeda..e1bf794 100644 --- a/tools/imagecon/imagecon.h +++ b/tools/imagecon/imagecon.h @@ -3,17 +3,36 @@ #define MAX_PALETTE 32 typedef struct { - int width; - int height; + int maxColors; int outputPalette; int outputMask; + int outputBitplanes; + int outputCopperList; char* overridePalette; int quantize; int verbose; char** argv; } imagecon_config_t; +typedef struct { + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; +} amiga_color_t; + + +typedef struct { + int numColors; + int width; + int height; + png_bytep* rowPointers; + unsigned char* amigaImage; + amiga_color_t palette[MAX_PALETTE]; +} imagecon_image_t; + + extern imagecon_config_t config; extern void abort_(const char * s, ...); -extern png_bytep* png_read(char* file_name); +extern void png_read(char* file_name, imagecon_image_t* ic); diff --git a/tools/imagecon/png.c b/tools/imagecon/png.c index 7511cbc..e52a571 100644 --- a/tools/imagecon/png.c +++ b/tools/imagecon/png.c @@ -16,8 +16,8 @@ #include "imagecon.h" -png_bytep* -png_read(char* file_name) +void +png_read(char* file_name, imagecon_image_t* ic) { png_structp png_ptr; png_byte color_type; @@ -51,14 +51,14 @@ png_read(char* file_name) png_read_info(png_ptr, info_ptr); - config.width = png_get_image_width(png_ptr, info_ptr); - config.height = png_get_image_height(png_ptr, info_ptr); + ic->width = png_get_image_width(png_ptr, info_ptr); + ic->height = png_get_image_height(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); if (config.verbose) { - printf("width = %d\n", config.width); - printf("height = %d\n", config.height); + printf("width = %d\n", ic->width); + printf("height = %d\n", ic->height); printf("color_type = %d (palette = %s)\n", color_type, color_type == PNG_COLOR_TYPE_PALETTE ? "yes" : "no"); printf("bit_depth = %d\n", bit_depth); printf("number_of_passes = %d\n", number_of_passes); @@ -84,35 +84,37 @@ png_read(char* file_name) number_of_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); - config.width = png_get_image_width(png_ptr, info_ptr); - config.height = png_get_image_height(png_ptr, info_ptr); + ic->width = png_get_image_width(png_ptr, info_ptr); + ic->height = png_get_image_height(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); if (setjmp(png_jmpbuf(png_ptr))) abort_("Error during read_image"); - png_bytep* rowPointers = (png_bytep*) malloc(sizeof(png_bytep) * config.height); + ic->rowPointers = (png_bytep*) malloc(sizeof(png_bytep) * ic->height); + /* if (bit_depth == 16) - rowbytes = config.width*8; - else - rowbytes = config.width*4; + rowbytes = ic->width*8; + else */ + rowbytes = ic->width*4; + + + for (int y=0; y< ic->height; y++) + ic->rowPointers[y] = (png_byte*) malloc(rowbytes); - for (int y=0; yrowPointers); fclose(fp); if (config.verbose) { - printf("width = %d\n", config.width); - printf("height = %d\n", config.height); + printf("width = %d\n", ic->width); + printf("height = %d\n", ic->height); printf("color_type = %d (palette = %s)\n", color_type, color_type == PNG_COLOR_TYPE_PALETTE ? "yes" : "no"); printf("bit_depth = %d\n", bit_depth); printf("number_of_passes = %d\n", number_of_passes); } - return rowPointers; + ic->amigaImage = calloc(ic->width*ic->height, 1); }