Simple blit

This commit is contained in:
alpine9000
2016-03-03 14:34:58 +11:00
parent 60eae1cdda
commit 5e7f8feb3e
13 changed files with 279 additions and 166 deletions
+1 -1
View File
@@ -7,4 +7,4 @@ MODULE=image.s
include ../base.mk include ../base.mk
$(EXTRA): $(IMAGECON) $(IMAGEFILE) $(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
+1 -1
View File
@@ -7,4 +7,4 @@ MODULE=music.s
include ../base.mk include ../base.mk
$(EXTRA): $(IMAGECON) $(IMAGEFILE) $(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
+9 -7
View File
@@ -4,15 +4,17 @@ IMAGEDATA=out/image-copper-list.s out/image.bin
IMAGEFILE=../assets/mission-beach.png IMAGEFILE=../assets/mission-beach.png
TC_IMAGEDATA=out/tc.bin out/tc-mask.bin TC_IMAGEDATA=out/tc.bin out/tc-mask.bin
TC_IMAGEFILE=../assets/tc.png 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 include ../base.mk
out/bitblit.s: bitblit.c $(SHARED_PALETTE): $(IMAGEFILE) $(TC_IMAGEFILE)
vc -S bitblit.c -o out/bitblit.s $(IMAGECON) --input $(IMAGEFILE),$(TC_IMAGEFILE) --output $(SHARED_PALETTE_BASE) --colors 32 --quantize --output-palette
$(IMAGEDATA): $(IMAGECON) $(IMAGEFILE) $(IMAGEDATA): $(IMAGECON) $(IMAGEFILE) $(SHARED_PALETTE)
$(IMAGECON) --input $(IMAGEFILE) --output out/image --colors 32 --quantize $(IMAGECON) --input $(IMAGEFILE) --output out/image --output-bitplanes --output-copperlist --override-palette $(SHARED_PALETTE)
$(TC_IMAGEDATA): $(IMAGECON) $(TC_IMAGEFILE) $(TC_IMAGEDATA): $(IMAGECON) $(TC_IMAGEFILE) $(SHARED_PALETTE)
$(IMAGECON) --input $(TC_IMAGEFILE) --output out/tc --colors 32 --quantize --output-mask $(IMAGECON) --input $(TC_IMAGEFILE) --output out/tc --output-bitplanes --output-mask --output-copperlist --override-palette $(SHARED_PALETTE)
+10 -7
View File
@@ -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: Screenshot:
Binary file not shown.
-43
View File
@@ -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;*/
}
+5 -8
View File
@@ -12,8 +12,6 @@ RASTER_X_START equ $81 ; hard coded coordinates from hardware manual
RASTER_Y_START equ $2c RASTER_Y_START equ $2c
RASTER_X_STOP equ RASTER_X_START+SCREEN_WIDTH RASTER_X_STOP equ RASTER_X_START+SCREEN_WIDTH
RASTER_Y_STOP equ RASTER_Y_START+SCREEN_HEIGHT RASTER_Y_STOP equ RASTER_Y_START+SCREEN_HEIGHT
public _bitblit
entry: entry:
;; custom chip base globally in a6 ;; custom chip base globally in a6
@@ -22,8 +20,7 @@ entry:
move #$7ff,DMACON(a6) ; disable all dma move #$7ff,DMACON(a6) ; disable all dma
move #$7fff,INTENA(a6) ; disable all interrupts move #$7fff,INTENA(a6) ; disable all interrupts
;; bsr.s resetBitplanePointers ;; reset color registers to white to prevent startup flicker
;; reset color registers to white
move.l #32,d0 move.l #32,d0
lea COLOR00(a6),a0 lea COLOR00(a6),a0
.loop: .loop:
@@ -108,21 +105,21 @@ TC_WIDTH_BYTES equ TC_WIDTH/8
TC_WIDTH_WORDS equ TC_WIDTH/16 TC_WIDTH_WORDS equ TC_WIDTH/16
TC_XPOS equ 16 TC_XPOS equ 16
TC_YPOS equ 16 TC_YPOS equ 16
TC_XPOS_BYTES equ (TC_XPOS)/8
doblit: doblit:
movem.l d0-a6,-(sp) movem.l d0-a6,-(sp)
lea $dff000,a6
bsr blitWait bsr blitWait
move.l #$09f00000,BLTCON0(a6) ;A->D copy, no shifts, ascending mode move.l #$09f00000,BLTCON0(a6) ;A->D copy, no shifts, ascending mode
move.l #$ffffffff,BLTAFWM(a6) ;no masking of first/last word 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 #0,BLTAMOD(a6) ;A modulo=bytes to skip between lines
move.w #SCREEN_WIDTH_BYTES-TC_WIDTH_BYTES,BLTDMOD(a6) ;D modulo move.w #SCREEN_WIDTH_BYTES-TC_WIDTH_BYTES,BLTDMOD(a6) ;D modulo
move.l #tc,BLTAPTH(a6) ;source graphic top left corner 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.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 move.w #(TC_HEIGHT*SCREEN_BIT_DEPTH)<<6|(TC_WIDTH_WORDS),BLTSIZE(a6) ;rectangle size, starts blit
movem.l (sp)+,d0-a6 movem.l (sp)+,d0-a6
rts rts
include "out/bitblit.s"
copper: copper:
;; bitplane pointers must be first else poking addresses will be incorrect ;; bitplane pointers must be first else poking addresses will be incorrect
dc.w BPL1PTL,0 dc.w BPL1PTL,0
+14
View File
@@ -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
}
+5 -2
View File
@@ -7,10 +7,13 @@ REFERENCE_BASE=reference/mission-beach
TEST_IMAGE=../../assets/mission-beach.png TEST_IMAGE=../../assets/mission-beach.png
LIBS=-lpng -limagequant LIBS=-lpng -limagequant
$(IMAGECON): out bin $(OBJS) $(IMAGECON): out bin $(OBJS)
gcc $(OBJS) -o $(IMAGECON) $(LIBS) gcc $(OBJS) -o $(IMAGECON) $(LIBS)
out/imagecon.o: imagecon.h
out/png.o: imagecon.h
out/%.o: %.c out/%.o: %.c
gcc -c $(HOST_CFLAGS) $< -o $@ gcc -c $(HOST_CFLAGS) $< -o $@
@@ -22,7 +25,7 @@ bin:
out/mission-beach.bin: $(IMAGECON) out/mission-beach.bin: $(IMAGECON)
-rm -f $(OUTPUT_BASE).bin $(OUTPUT_BASE)-copper-list.s -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 test: $(IMAGECON) $(OUTPUT_BASE).bin
diff $(OUTPUT_BASE).bin $(REFERENCE_BASE).bin diff $(OUTPUT_BASE).bin $(REFERENCE_BASE).bin
+34 -5
View File
@@ -6,24 +6,32 @@ Generate amiga data/files from a PNG image file.
usage usage
----- -----
``` ```
imagecon: --input <input.png> [options] imagecon: --input <input1.png,input2.png...> [options]
Options: options:
--output <output prefix> --output <output prefix>
--colors <max colors> --colors <max colors>
--quantize --quantize
--output-palette --output-palette
--output-bitplanes
--output-mask
--output-copperlist
--override-palette <palette file> --override-palette <palette file>
--verbose --verbose
``` ```
The following files will be generated: The following files can be generated:
1. **&lt;output prefix>.bin** binary interleave bitplane data 1. **&lt;output prefix>.bin** binary interleave bitplane data
2. **&lt;output prefix>-copper-list.s** m68k assembler syntax copper list with no symbols 2. **&lt;output prefix>-copper-list.s** m68k assembler syntax copper list with no symbols
3. **&lt;output prefix>.pal** (optional) palette file listing the palette colors as hex 3. **&lt;output prefix>.pal** palette file listing the palette colors as hex
3. **&lt;output prefix>-mask.bin** binary interleave bitplane mask
options options
------- -------
**--input** i&ltnput1.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** &lt;output prefix> **--output** &lt;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. 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. 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** **--output-palette**
Generate a palette file of the final palette used. Output will be the output file with the ".pal" extension. 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 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
``` ```
+157 -70
View File
@@ -18,22 +18,28 @@ imagecon_config_t config = {
.maxColors = MAX_PALETTE, .maxColors = MAX_PALETTE,
.outputPalette = 0, .outputPalette = 0,
.outputMask = 0, .outputMask = 0,
.outputBitplanes = 0,
.outputCopperList = 0,
.quantize = 0, .quantize = 0,
.overridePalette = 0 .overridePalette = 0
}; };
typedef struct {
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a;
} amiga_color_t;
void void
usage() usage()
{ {
fprintf(stderr, "%s: --input <input.png> [options]\nOptions:\n --output <output prefix>\n --colors <max colors>\n --quantize\n --output-mask\n --output-palette\n --override-palette <palette file>\n --verbose\n", config.argv[0]); fprintf(stderr,
"%s: --input <input1.png,input2.png...> [options]\n"\
"options:\n"\
" --output <output prefix>\n"\
" --colors <max colors>\n"\
" --quantize\n --output-mask\n"\
" --output-bitplanes\n"\
" --output-copperlist\n"\
" --output-mask\n"\
" --output-palette\n"\
" --override-palette <palette file>\n"\
" --verbose\n", config.argv[0]);
exit(1); exit(1);
} }
@@ -90,14 +96,19 @@ openFileRead(const char * s, ...)
void void
outputPalette(char* outFilename, amiga_color_t* palette, int numColors) outputPalette(char* outFilename, imagecon_image_t* ic)
{ {
if (config.verbose) { if (config.verbose) {
printf("outputPalette...\n"); printf("outputPalette...\n");
} }
FILE* fp = openFileWrite("%s-copper-list.s", outFilename); FILE* fp = 0;
FILE* paletteFP = 0; FILE* paletteFP = 0;
if (config.outputCopperList) {
fp = openFileWrite("%s-copper-list.s", outFilename);
}
if (config.outputPalette) { if (config.outputPalette) {
paletteFP = openFileWrite("%s.pal", outFilename); paletteFP = openFileWrite("%s.pal", outFilename);
} }
@@ -106,20 +117,25 @@ outputPalette(char* outFilename, amiga_color_t* palette, int numColors)
printf("outputPalette:\n"); printf("outputPalette:\n");
} }
for (int i = 0; i < numColors; i++) { for (int i = 0; i < ic->numColors; i++) {
if (config.verbose) { 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) { 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) { if (paletteFP) {
fclose(paletteFP); fclose(paletteFP);
} }
fclose(fp); if (fp) {
fclose(fp);
}
if (config.verbose) { if (config.verbose) {
printf("done\n\n"); printf("done\n\n");
@@ -127,15 +143,15 @@ outputPalette(char* outFilename, amiga_color_t* palette, int numColors)
} }
int void
generateQuantizedPalette(unsigned char* amigaImage, png_bytep* rowPointers, amiga_color_t* palette) generateQuantizedPalette(imagecon_image_t* ic)
{ {
if (config.verbose) { if (config.verbose) {
printf("generateQuantizedPalette...\n"); printf("generateQuantizedPalette...\n");
} }
liq_attr *attr = liq_attr_create(); 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) { if (config.overridePalette) {
FILE* fp = openFileRead(config.overridePalette); FILE* fp = openFileRead(config.overridePalette);
@@ -163,48 +179,49 @@ generateQuantizedPalette(unsigned char* amigaImage, png_bytep* rowPointers, amig
config.maxColors = paletteIndex; config.maxColors = paletteIndex;
} }
liq_set_max_colors(attr, config.maxColors); liq_set_max_colors(attr, config.maxColors);
liq_set_speed(attr, 1); liq_set_speed(attr, 1);
liq_result *res = liq_quantize_image(attr, image); 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); const liq_palette *pal = liq_get_palette(res);
if (config.verbose) { if (config.verbose) {
printf("pal->count = %d\n", pal->count); printf("pal->count = %d\n", pal->count);
printf("generateQuantizedPalette: post liq_write_remapped_image\n"); printf("generateQuantizedPalette: post liq_write_remapped_image\n");
} }
for (unsigned i = 0; i < pal->count; i++) { for (unsigned i = 0; i < pal->count; i++) {
if (config.verbose) { 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); 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; ic->palette[i].r = pal->entries[i].r >> 4;
palette[i].g = pal->entries[i].g >> 4; ic->palette[i].g = pal->entries[i].g >> 4;
palette[i].b = pal->entries[i].b >> 4; ic->palette[i].b = pal->entries[i].b >> 4;
palette[i].a = pal->entries[i].a >> 4; ic->palette[i].a = pal->entries[i].a >> 4;
} }
if (config.verbose) { if (config.verbose) {
printf("done\n\n"); printf("done\n\n");
} }
return pal->count; ic->numColors = pal->count;
} }
int void
generatePalette(unsigned char* amigaImage, png_bytep* rowPointers, amiga_color_t* palette) generatePalette(imagecon_image_t* ic)
{ {
if (config.verbose) { if (config.verbose) {
printf("generatePalette...\n"); printf("generatePalette...\n");
} }
int paletteIndex = 0; int paletteIndex = 0;
for (int y=0; y<config.height; y++) { for (int y=0; y< ic->height; y++) {
png_byte* row = rowPointers[y]; png_byte* row = ic->rowPointers[y];
for (int x=0; x < config.width; x++) { for (int x=0; x < ic->width; x++) {
png_byte* ptr = &(row[x*4]); png_byte* ptr = &(row[x*4]);
amiga_color_t color; amiga_color_t color;
@@ -215,7 +232,7 @@ generatePalette(unsigned char* amigaImage, png_bytep* rowPointers, amiga_color_t
int index = -1; int index = -1;
for (int i = 0; i < paletteIndex; i++) { 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; index = i;
break; break;
} }
@@ -229,8 +246,8 @@ generatePalette(unsigned char* amigaImage, png_bytep* rowPointers, amiga_color_t
abort_("Too many colors. Use --quantize.\n"); abort_("Too many colors. Use --quantize.\n");
} }
palette[index] = color ; ic->palette[index] = color ;
amigaImage[(config.width*y)+x] = index; 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"); printf("done\n\n");
} }
return paletteIndex; ic->numColors = paletteIndex;
} }
void void
outputBitplanes(char* outFilename, unsigned char* amigaImage, int numColors) outputBitplanes(char* outFilename, imagecon_image_t* ic)
{ {
if (config.verbose) { if (config.verbose) {
printf("outputBitplanes...\n"); 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) { 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); 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); char** bitplanes = malloc(sizeof(void*)*numBitPlanes);
for (int i = 0; i < numBitPlanes; i++) { 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 byte = 0;byte < byteWidth; byte++) {
for (int bit = 0; bit < 8; bit++) { for (int bit = 0; bit < 8; bit++) {
int x = byte * 8 + 7 - 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++) { for (int plane_index = 0; plane_index < numBitPlanes; plane_index++) {
char* plane = bitplanes[plane_index]; char* plane = bitplanes[plane_index];
plane[writeIndex] |= ((palette_index >> plane_index) & 1) << bit; 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); 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++) { for (int plane_index = 0; plane_index < numBitPlanes; plane_index++) {
char* plane = bitplanes[plane_index]; char* plane = bitplanes[plane_index];
fwrite(&plane[y*byteWidth], byteWidth, 1, fp); fwrite(&plane[y*byteWidth], byteWidth, 1, fp);
@@ -293,28 +310,28 @@ outputBitplanes(char* outFilename, unsigned char* amigaImage, int numColors)
} }
} }
void void
outputMask(char* outFilename, unsigned char* amigaImage, amiga_color_t* palette, int numColors) outputMask(char* outFilename, imagecon_image_t* ic)
{ {
if (config.verbose) { if (config.verbose) {
printf("outputMask...\n"); 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); char** bitplanes = malloc(sizeof(void*)*numBitPlanes);
for (int i = 0; i < numBitPlanes; i++) { 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 < ic->height; y++) {
for (int y = 0, writeIndex = 0; y < config.height; y++) {
for (int byte = 0;byte < byteWidth; byte++) { for (int byte = 0;byte < byteWidth; byte++) {
for (int bit = 0; bit < 8; bit++) { for (int bit = 0; bit < 8; bit++) {
int x = byte * 8 + 7 - bit; int x = byte * 8 + 7 - bit;
int paletteIndex = amigaImage[(config.width*y)+x]; int paletteIndex = ic->amigaImage[(ic->width*y)+x];
int bitmask = palette[paletteIndex].a > 0 ? 0xFF : 0; int bitmask = ic->palette[paletteIndex].a > 0 ? 0xFF : 0;
for (int plane_index = 0; plane_index < numBitPlanes; plane_index++) { for (int plane_index = 0; plane_index < numBitPlanes; plane_index++) {
char* plane = bitplanes[plane_index]; char* plane = bitplanes[plane_index];
plane[writeIndex] |= ((bitmask >> plane_index) & 1) << bit; 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); 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++) { for (int plane_index = 0; plane_index < numBitPlanes; plane_index++) {
char* plane = bitplanes[plane_index]; char* plane = bitplanes[plane_index];
fwrite(&plane[y*byteWidth], byteWidth, 1, fp); fwrite(&plane[y*byteWidth], byteWidth, 1, fp);
@@ -339,38 +356,91 @@ outputMask(char* outFilename, unsigned char* amigaImage, amiga_color_t* palette,
} }
} }
void void
processFile(char* outFilename, png_bytep* rowPointers) processFile(char* outFilename, imagecon_image_t* ic)
{ {
if (config.verbose) { if (config.verbose) {
printf("processFile...\n"); 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) { if (config.quantize || config.overridePalette) {
numColors = generateQuantizedPalette(amigaImage, rowPointers, palette); generateQuantizedPalette(ic);
} else { } else {
numColors = generatePalette(amigaImage, rowPointers, palette); generatePalette(ic);
} }
outputBitplanes(outFilename, amigaImage, numColors); if (config.outputBitplanes) {
outputBitplanes(outFilename, ic);
}
if (config.outputMask) { if (config.outputMask) {
outputMask(outFilename, amigaImage, palette, numColors); outputMask(outFilename, ic);
} }
outputPalette(outFilename, palette, numColors);
outputPalette(outFilename, ic);
if (config.verbose) { if (config.verbose) {
printf("done\n\n"); 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 int
@@ -384,6 +454,8 @@ main(int argc, char **argv)
static struct option long_options[] = { static struct option long_options[] = {
{"verbose", no_argument, &config.verbose, 1}, {"verbose", no_argument, &config.verbose, 1},
{"quantize", no_argument, &config.quantize, 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-palette", no_argument, &config.outputPalette, 1},
{"output-mask", no_argument, &config.outputMask, 1}, {"output-mask", no_argument, &config.outputMask, 1},
{"override-palette", required_argument, 0, 'p'}, {"override-palette", required_argument, 0, 'p'},
@@ -444,11 +516,26 @@ main(int argc, char **argv)
usage(); usage();
} }
if (config.verbose) { if (strchr(inputFile, ',') == 0) {
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); 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; return 0;
} }
+22 -3
View File
@@ -3,17 +3,36 @@
#define MAX_PALETTE 32 #define MAX_PALETTE 32
typedef struct { typedef struct {
int width;
int height;
int maxColors; int maxColors;
int outputPalette; int outputPalette;
int outputMask; int outputMask;
int outputBitplanes;
int outputCopperList;
char* overridePalette; char* overridePalette;
int quantize; int quantize;
int verbose; int verbose;
char** argv; char** argv;
} imagecon_config_t; } 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 imagecon_config_t config;
extern void abort_(const char * s, ...); 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);
+21 -19
View File
@@ -16,8 +16,8 @@
#include "imagecon.h" #include "imagecon.h"
png_bytep* void
png_read(char* file_name) png_read(char* file_name, imagecon_image_t* ic)
{ {
png_structp png_ptr; png_structp png_ptr;
png_byte color_type; png_byte color_type;
@@ -51,14 +51,14 @@ png_read(char* file_name)
png_read_info(png_ptr, info_ptr); png_read_info(png_ptr, info_ptr);
config.width = png_get_image_width(png_ptr, info_ptr); ic->width = png_get_image_width(png_ptr, info_ptr);
config.height = png_get_image_height(png_ptr, info_ptr); ic->height = png_get_image_height(png_ptr, info_ptr);
color_type = png_get_color_type(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr);
bit_depth = png_get_bit_depth(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr);
if (config.verbose) { if (config.verbose) {
printf("width = %d\n", config.width); printf("width = %d\n", ic->width);
printf("height = %d\n", config.height); printf("height = %d\n", ic->height);
printf("color_type = %d (palette = %s)\n", color_type, color_type == PNG_COLOR_TYPE_PALETTE ? "yes" : "no"); 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("bit_depth = %d\n", bit_depth);
printf("number_of_passes = %d\n", number_of_passes); 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); number_of_passes = png_set_interlace_handling(png_ptr);
png_read_update_info(png_ptr, info_ptr); png_read_update_info(png_ptr, info_ptr);
config.width = png_get_image_width(png_ptr, info_ptr); ic->width = png_get_image_width(png_ptr, info_ptr);
config.height = png_get_image_height(png_ptr, info_ptr); ic->height = png_get_image_height(png_ptr, info_ptr);
color_type = png_get_color_type(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr);
bit_depth = png_get_bit_depth(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr);
if (setjmp(png_jmpbuf(png_ptr))) if (setjmp(png_jmpbuf(png_ptr)))
abort_("Error during read_image"); 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) if (bit_depth == 16)
rowbytes = config.width*8; rowbytes = ic->width*8;
else else */
rowbytes = config.width*4; rowbytes = ic->width*4;
for (int y=0; y< ic->height; y++)
ic->rowPointers[y] = (png_byte*) malloc(rowbytes);
for (int y=0; y<config.height; y++) png_read_image(png_ptr, ic->rowPointers);
rowPointers[y] = (png_byte*) malloc(rowbytes);
png_read_image(png_ptr, rowPointers);
fclose(fp); fclose(fp);
if (config.verbose) { if (config.verbose) {
printf("width = %d\n", config.width); printf("width = %d\n", ic->width);
printf("height = %d\n", config.height); printf("height = %d\n", ic->height);
printf("color_type = %d (palette = %s)\n", color_type, color_type == PNG_COLOR_TYPE_PALETTE ? "yes" : "no"); 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("bit_depth = %d\n", bit_depth);
printf("number_of_passes = %d\n", number_of_passes); printf("number_of_passes = %d\n", number_of_passes);
} }
return rowPointers; ic->amigaImage = calloc(ic->width*ic->height, 1);
} }