mirror of
https://frontier.innolan.net/github/AmigaExamples.git
synced 2026-09-11 23:11:37 +00:00
Simple blit
This commit is contained in:
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
Binary file not shown.
@@ -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;*/
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -6,24 +6,32 @@ Generate amiga data/files from a PNG image file.
|
||||
usage
|
||||
-----
|
||||
```
|
||||
imagecon: --input <input.png> [options]
|
||||
Options:
|
||||
imagecon: --input <input1.png,input2.png...> [options]
|
||||
options:
|
||||
--output <output prefix>
|
||||
--colors <max colors>
|
||||
--quantize
|
||||
--output-palette
|
||||
--output-bitplanes
|
||||
--output-mask
|
||||
--output-copperlist
|
||||
--override-palette <palette file>
|
||||
--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
|
||||
```
|
||||
|
||||
+157
-70
@@ -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 <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);
|
||||
}
|
||||
|
||||
@@ -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; y<config.height; y++) {
|
||||
png_byte* row = rowPointers[y];
|
||||
for (int x=0; x < config.width; x++) {
|
||||
for (int y=0; y< ic->height; 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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
+21
-19
@@ -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; y<config.height; y++)
|
||||
rowPointers[y] = (png_byte*) malloc(rowbytes);
|
||||
|
||||
png_read_image(png_ptr, rowPointers);
|
||||
png_read_image(png_ptr, ic->rowPointers);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user