From 5e7f8feb3e4bdaec2f1586b53462f6f3d84dec70 Mon Sep 17 00:00:00 2001 From: alpine9000 Date: Thu, 3 Mar 2016 14:34:58 +1100 Subject: [PATCH] Simple blit --- 001.simple_image/Makefile | 2 +- 003.music/Makefile | 2 +- 006.simple_blit/Makefile | 16 +-- 006.simple_blit/README.md | 17 +-- 006.simple_blit/bin/blit.adf | Bin 901120 -> 901120 bytes 006.simple_blit/bitblit.c | 43 ------- 006.simple_blit/blit.s | 13 +- examples/link.script | 14 +++ tools/imagecon/Makefile | 7 +- tools/imagecon/README.md | 39 +++++- tools/imagecon/imagecon.c | 227 ++++++++++++++++++++++++----------- tools/imagecon/imagecon.h | 25 +++- tools/imagecon/png.c | 40 +++--- 13 files changed, 279 insertions(+), 166 deletions(-) delete mode 100644 006.simple_blit/bitblit.c create mode 100644 examples/link.script 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 8cf5b8b3e3c209c7f64ac31b321344367da63f95..fb36b0e5143e5f0b722e8509c6fa84d494aa95e8 100644 GIT binary patch literal 901120 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 zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 O009ILK;Zuuf&U9SGw1*S 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); }