Tried to do sliced ham

This commit is contained in:
alpine9000 2016-03-11 18:46:00 +11:00
parent 53e105117a
commit 4737a5eb74
12 changed files with 719 additions and 33 deletions

View File

@ -1,5 +1,5 @@
IMAGECON=./out/imagecon
OBJS=out/imagecon.o out/png.o out/color.o out/dither.o out/ham.o out/palette.o out/file.o
OBJS=out/imagecon.o out/png.o out/color.o out/dither.o out/ham.o out/palette.o out/file.o out/sliced_ham.o out/quant.o
WARN_ERROR=-Werror
HOST_WARNINGS=$(WARN_ERROR) -pedantic-errors -Wfatal-errors -Wall -Wextra -Wno-unused-parameter -Wshadow -limagequant
HOST_CFLAGS=$(HOST_WARNINGS) -O3
@ -39,7 +39,7 @@ out/%.o: %.c
gcc -c $(HOST_CFLAGS) $< -o $@
@gcc -MM $(HOST_CFLAGS) $*.c > out/$*.d
@mv -f out/$*.d out/$*.d.tmp
@sed -e 's/.*/out\/&/' < out/$*.d.tmp > out/$*.d
@sed 's/^.*\:/out\/&/' < out/$*.d.tmp > out/$*.d
@rm -f out/$*.d.tmp
out:

View File

@ -110,6 +110,12 @@ color_setDitheredPixel(imagecon_image_t* ic, int x, int y, dither_color_t color)
if (color.b < 0) {
color.b = 0;
}
if (color.a > 255) {
color.a = 255;
}
if (color.a < 0) {
color.a = 0;
}
d->r = color.r;
d->g = color.g;

View File

@ -4,9 +4,9 @@ static void
_dither_createDither(imagecon_image_t* ic);
amiga_color_t
dither_getPalettedColor(imagecon_image_t* ic, amiga_color_t color, amiga_color_t last)
dither_getPalettedColor(dither_data_t data)
{
return color_findClosestPalettePixel(ic, color);
return color_findClosestPalettePixel(data.ic, data.color);
}
@ -31,22 +31,28 @@ _propagateError(imagecon_image_t* ic, float factor, int x, int y, dither_color_t
void
dither_image(imagecon_image_t* ic, amiga_color_t (*selector)(imagecon_image_t*, amiga_color_t color, amiga_color_t last))
dither_image(imagecon_image_t* ic, amiga_color_t (*selector)(dither_data_t data))
{
_dither_createDither(ic);
dither_data_t data;
for (int y = 0; y < ic->height; y++) {
amiga_color_t last = {-1, -1, -1, -1};
for (int x = 0; x < ic->width; x++) {
dither_color_t old = color_getDitheredPixel(ic, x, y);
amiga_color_t new = selector(ic, color_ditheredToAmiga(old), last);
data.color = color_ditheredToAmiga(old);
data.last = last;
data.x = x;
data.y = y;
data.ic = ic;
amiga_color_t new = selector(data);
dither_color_t error;
float gamma = 1.0;
error.r = old.r - (new.r*gamma);
error.g = old.g - (new.g*gamma);
error.b = old.b - (new.b*gamma);
error.r = CLAMP(old.r - (new.r*gamma));
error.g = CLAMP(old.g - (new.g*gamma));
error.b = CLAMP(old.b - (new.b*gamma));
color_setDitheredPixel(ic, x, y, color_amigaToDithered(new));
last = new;

View File

@ -1,10 +1,19 @@
#pragma once
typedef struct {
imagecon_image_t* ic;
amiga_color_t color;
amiga_color_t last;
int x;
int y;
} dither_data_t;
amiga_color_t
dither_getPalettedColor(imagecon_image_t* ic, amiga_color_t color, amiga_color_t last);
dither_getPalettedColor(dither_data_t data);
void
dither_image(imagecon_image_t* ic, amiga_color_t (*selector)(imagecon_image_t* ic, amiga_color_t color, amiga_color_t last));
dither_image(imagecon_image_t* ic, amiga_color_t (*selector)(dither_data_t data));
void
dither_transferToPaletted(imagecon_image_t* ic);

View File

@ -1,7 +1,7 @@
#include "imagecon.h"
static ham_control_t
_ham_findClosestPixel(imagecon_image_t* ic, amiga_color_t color, amiga_color_t last)
ham_control_t
ham_findClosestPixel(imagecon_image_t* ic, amiga_color_t color, amiga_color_t last)
{
int delta = INT_MAX;
@ -58,9 +58,9 @@ _ham_findClosestPixel(imagecon_image_t* ic, amiga_color_t color, amiga_color_t l
static amiga_color_t
_ham_getHamColor(imagecon_image_t* ic, amiga_color_t color, amiga_color_t last)
_ham_getHamColor(dither_data_t data)
{
ham_control_t ham = _ham_findClosestPixel(ic, color, last);
ham_control_t ham = ham_findClosestPixel(data.ic, data.color, data.last);
return ham.pixel;
}
@ -74,7 +74,7 @@ _ham_createHams(imagecon_image_t* ic)
amiga_color_t lastPixel = { -1, -1, -1, -1};
for (int x = 0; x < ic->width; x++) {
amiga_color_t orig = color_ditheredToAmiga(color_getDitheredPixel(ic, x, y));
ham_control_t ham = _ham_findClosestPixel(ic, orig, lastPixel);
ham_control_t ham = ham_findClosestPixel(ic, orig, lastPixel);
lastPixel = ham.pixel;
hams[(y*ic->width)+x] = ham;
}
@ -111,7 +111,7 @@ _ham_outputBitplanes(char* outFilename, imagecon_image_t* ic)
amiga_color_t lastPixel = { -1, -1, -1, -1};
for (int x = 0; x < ic->width; x++) {
amiga_color_t orig = color_getOriginalPixel(ic, x, y);
ham_control_t ham = _ham_findClosestPixel(ic, orig, lastPixel);
ham_control_t ham = ham_findClosestPixel(ic, orig, lastPixel);
lastPixel = ham.pixel;
hams[(y*ic->width)+x] = ham;
}
@ -157,7 +157,7 @@ _ham_outputBitplanes(char* outFilename, imagecon_image_t* ic)
}
static int
static int
_score(imagecon_image_t* ic)
{
long error = 0;
@ -165,7 +165,7 @@ _score(imagecon_image_t* ic)
amiga_color_t lastPixel = { -1, -1, -1, -1};
for (int x = 0; x < ic->width; x++) {
amiga_color_t color = color_getOriginalPixel(ic, x, y);
ham_control_t ham = _ham_findClosestPixel(ic, color, lastPixel);
ham_control_t ham = ham_findClosestPixel(ic, color, lastPixel);
error += color_delta(color, color_findClosestPalettePixel(ic, ham.pixel));
lastPixel = ham.pixel;
}
@ -232,7 +232,7 @@ _ham_bruteForcePalette(imagecon_image_t* ic)
void
ham_process(char* outFilename, imagecon_image_t* ic)
ham_process(imagecon_image_t* ic, char* outFilename)
{
config.maxColors = 16;
@ -241,8 +241,7 @@ ham_process(char* outFilename, imagecon_image_t* ic)
_ham_bruteForcePalette(ic);
} else {
config.maxColors = 16;
if (config.overridePalette) {
palette_loadFile(ic);
}

View File

@ -1,4 +1,11 @@
#pragma once
ham_control_t
ham_findClosestPixel(imagecon_image_t* ic, amiga_color_t color, amiga_color_t last);
void
ham_process(char* outFilename, imagecon_image_t* ic);
ham_process(imagecon_image_t* ic, char* outFilename);
void
sham_process(imagecon_image_t* ic, char* outFilename);

View File

@ -15,6 +15,7 @@ imagecon_config_t config = {
.ehbMode = 0,
.hamMode = 0,
.hamBruteForce = 0,
.slicedHam = 0,
.quantize = 0,
.dither = 0,
.overridePalette = 0
@ -39,6 +40,7 @@ usage()
" --extra-half-brite\n"\
" --ham\n"\
" --ham-brute-force\n"\
" --sliced-ham\n"\
" --dither\n"\
" --use-palette <palette file>\n"\
" --verbose\n", config.argv[0]);
@ -120,6 +122,36 @@ generateQuantizedImage(imagecon_image_t* ic, int usePalette)
}
void
generateQuant2(imagecon_image_t* ic)
{
quant_image_t* image = quant_newImage(ic->width, ic->height);
for (int c = 0, 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]);
image->pix[c++] = ptr[0];
image->pix[c++] = ptr[1];
image->pix[c++] = ptr[2];
}
}
quant_quantize(image, config.maxColors, config.dither);
for (int c = 0,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]);
ptr[0] = image->pix[c++];
ptr[1] = image->pix[c++];
ptr[2] = image->pix[c++];
ptr[3] = 255;
}
}
}
void
generatePalettedImage(imagecon_image_t* ic)
{
@ -133,12 +165,11 @@ generatePalettedImage(imagecon_image_t* ic)
for (int x=0; x < ic->width; x++) {
png_byte* ptr = &(row[x*4]);
// TODO: this shift is probably wrong now
amiga_color_t color;
color.r = ptr[0] >> 4;
color.g = ptr[1] >> 4;
color.b = ptr[2] >> 4;
color.a = ptr[3] >> 4;
color.r = ptr[0];
color.g = ptr[1];
color.b = ptr[2];
color.a = ptr[3];
int index = -1;
for (int i = 0; i < paletteIndex; i++) {
@ -321,8 +352,10 @@ processFile(char* outFilename, imagecon_image_t* ic)
printf("processFile...\n");
}
if (config.hamMode) {
ham_process(outFilename, ic);
if (config.slicedHam) {
sham_process(ic, outFilename);
} else if (config.hamMode) {
ham_process(ic, outFilename);
} else {
if (config.quantize || config.overridePalette) {
if (config.ehbMode) {
@ -439,6 +472,7 @@ main(int argc, char **argv)
{"extra-half-brite", no_argument, &config.ehbMode, 1},
{"ham", no_argument, &config.hamMode, 1},
{"ham-brute-force", no_argument, &config.hamBruteForce, 1},
{"sliced-ham", no_argument, &config.slicedHam, 1},
{"dither", no_argument, &config.dither, 1},
{"use-palette", required_argument, 0, 'p'},
{"output", required_argument, 0, 'o'},

View File

@ -13,8 +13,10 @@
#define MAX_PALETTE 32
typedef struct {
#define RGB24TORGB12(x) (x >> 4)
#define CLAMP(x) (x > 255.0 ? 255.0 : (x < -255.0 ? -255.0 : x))
typedef struct {
int maxColors;
int outputPalette;
int outputPaletteAsm;
@ -25,6 +27,7 @@ typedef struct {
int ehbMode;
int hamMode;
int hamBruteForce;
int slicedHam;
int dither;
char* overridePalette;
int quantize;
@ -69,6 +72,7 @@ typedef struct {
#include "ham.h"
#include "file.h"
#include "palette.h"
#include "quant.h"
extern imagecon_config_t config;

View File

@ -23,7 +23,6 @@ void palette_loadFile(imagecon_image_t* ic)
ic->numColors = paletteIndex;
}
#define RGB24TORGB12(x) (x >> 4)
void
palette_output(char* outFilename, imagecon_image_t* ic)

316
tools/imagecon/quant.c Normal file
View File

@ -0,0 +1,316 @@
/*
*
* Originally from: https://rosettacode.org/wiki/Color_quantization/C
* License information http://www.gnu.org/licenses/fdl-1.2.html
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <stdint.h>
#include <math.h>
#include "quant.h"
quant_image_t*
quant_newImage(int w, int h)
{
quant_image_t* im = malloc(sizeof(quant_image_t) + h * w * 3);
im->w = w; im->h = h;
im->pix = (unsigned char *)(im + 1);
return im;
}
#define ON_INHEAP 1
typedef struct oct_node_t oct_node_t, *oct_node;
struct oct_node_t{
int64_t r, g, b; /* sum of all child node colors */
int count, heap_idx;
unsigned char n_kids, kid_idx, flags, depth;
oct_node kids[8], parent;
};
typedef struct {
int alloc, n;
oct_node* buf;
} node_heap;
inline int cmp_node(oct_node a, oct_node b)
{
if (a->n_kids < b->n_kids) return -1;
if (a->n_kids > b->n_kids) return 1;
int ac = a->count >> a->depth;
int bc = b->count >> b->depth;
return ac < bc ? -1 : ac > bc;
}
void down_heap(node_heap *h, oct_node p)
{
int n = p->heap_idx, m;
while (1) {
m = n * 2;
if (m >= h->n) break;
if (m + 1 < h->n && cmp_node(h->buf[m], h->buf[m + 1]) > 0) m++;
if (cmp_node(p, h->buf[m]) <= 0) break;
h->buf[n] = h->buf[m];
h->buf[n]->heap_idx = n;
n = m;
}
h->buf[n] = p;
p->heap_idx = n;
}
void up_heap(node_heap *h, oct_node p)
{
int n = p->heap_idx;
oct_node prev;
while (n > 1) {
prev = h->buf[n / 2];
if (cmp_node(p, prev) >= 0) break;
h->buf[n] = prev;
prev->heap_idx = n;
n /= 2;
}
h->buf[n] = p;
p->heap_idx = n;
}
void heap_add(node_heap *h, oct_node p)
{
if ((p->flags & ON_INHEAP)) {
down_heap(h, p);
up_heap(h, p);
return;
}
p->flags |= ON_INHEAP;
if (!h->n) h->n = 1;
if (h->n >= h->alloc) {
while (h->n >= h->alloc) h->alloc += 1024;
h->buf = realloc(h->buf, sizeof(oct_node) * h->alloc);
}
p->heap_idx = h->n;
h->buf[h->n++] = p;
up_heap(h, p);
}
oct_node pop_heap(node_heap *h)
{
if (h->n <= 1) return 0;
oct_node ret = h->buf[1];
h->buf[1] = h->buf[--h->n];
h->buf[h->n] = 0;
h->buf[1]->heap_idx = 1;
down_heap(h, h->buf[1]);
return ret;
}
static oct_node pool = 0;
oct_node node_new(unsigned char idx, unsigned char depth, oct_node p)
{
static int len = 0;
if (len <= 1) {
oct_node p_ = calloc(sizeof(oct_node_t), 2048);
p_->parent = pool;
pool = p_;
len = 2047;
}
oct_node x = pool + len--;
x->kid_idx = idx;
x->depth = depth;
x->parent = p;
if (p) p->n_kids++;
return x;
}
void node_free()
{
oct_node p;
while (pool) {
p = pool->parent;
free(pool);
pool = p;
}
}
oct_node node_insert(oct_node root, unsigned char *pix)
{
unsigned char i, bit, depth = 0;
for (bit = 1 << 7; ++depth < 8; bit >>= 1) {
i = !!(pix[1] & bit) * 4 + !!(pix[0] & bit) * 2 + !!(pix[2] & bit);
if (!root->kids[i])
root->kids[i] = node_new(i, depth, root);
root = root->kids[i];
}
root->r += pix[0];
root->g += pix[1];
root->b += pix[2];
root->count++;
return root;
}
oct_node node_fold(oct_node p)
{
if (p->n_kids) abort();
oct_node q = p->parent;
q->count += p->count;
q->r += p->r;
q->g += p->g;
q->b += p->b;
q->n_kids --;
q->kids[p->kid_idx] = 0;
return q;
}
void color_replace(oct_node root, unsigned char *pix)
{
unsigned char i, bit;
for (bit = 1 << 7; bit; bit >>= 1) {
i = !!(pix[1] & bit) * 4 + !!(pix[0] & bit) * 2 + !!(pix[2] & bit);
if (!root->kids[i]) break;
root = root->kids[i];
}
pix[0] = root->r;
pix[1] = root->g;
pix[2] = root->b;
}
static oct_node
nearest_color(int *v, node_heap *h) {
int i;
int diff, max = 100000000;
oct_node o = 0;
for (i = 1; i < h->n; i++) {
diff = 3 * abs(h->buf[i]->r - v[0])
+ 5 * abs(h->buf[i]->g - v[1])
+ 2 * abs(h->buf[i]->b - v[2]);
if (diff < max) {
max = diff;
o = h->buf[i];
}
}
return o;
}
void error_diffuse(quant_image_t* im, node_heap *h)
{
#define POS(i, j) (3 * ((i) * im->w + (j)))
int i, j;
int *npx = calloc(sizeof(int), im->h * im->w * 3), *px;
int v[3];
unsigned char *pix = im->pix;
oct_node nd;
#define C10 7
#define C01 5
#define C11 2
#define C00 1
#define CTOTAL (C00 + C11 + C10 + C01)
for (px = npx, i = 0; i < im->h; i++) {
for (j = 0; j < im->w; j++, pix += 3, px += 3) {
px[0] = (int)pix[0] * CTOTAL;
px[1] = (int)pix[1] * CTOTAL;
px[2] = (int)pix[2] * CTOTAL;
}
}
#define clamp(x, i) if (x[i] > 255) x[i] = 255; if (x[i] < 0) x[i] = 0
pix = im->pix;
for (px = npx, i = 0; i < im->h; i++) {
for (j = 0; j < im->w; j++, pix += 3, px += 3) {
px[0] /= CTOTAL;
px[1] /= CTOTAL;
px[2] /= CTOTAL;
clamp(px, 0); clamp(px, 1); clamp(px, 2);
nd = nearest_color(px, h);
v[0] = px[0] - nd->r;
v[1] = px[1] - nd->g;
v[2] = px[2] - nd->b;
pix[0] = nd->r; pix[1] = nd->g; pix[2] = nd->b;
if (j < im->w - 1) {
npx[POS(i, j+1) + 0] += v[0] * C10;
npx[POS(i, j+1) + 1] += v[1] * C10;
npx[POS(i, j+1) + 2] += v[2] * C10;
}
if (i >= im->h - 1) continue;
npx[POS(i+1, j) + 0] += v[0] * C01;
npx[POS(i+1, j) + 1] += v[1] * C01;
npx[POS(i+1, j) + 2] += v[2] * C01;
if (j < im->w - 1) {
npx[POS(i+1, j+1) + 0] += v[0] * C11;
npx[POS(i+1, j+1) + 1] += v[1] * C11;
npx[POS(i+1, j+1) + 2] += v[2] * C11;
}
if (j) {
npx[POS(i+1, j-1) + 0] += v[0] * C00;
npx[POS(i+1, j-1) + 1] += v[1] * C00;
npx[POS(i+1, j-1) + 2] += v[2] * C00;
}
}
}
free(npx);
}
void
quant_quantize(quant_image_t* im, int n_colors, int dither)
{
int i;
unsigned char *pix = im->pix;
node_heap heap = { 0, 0, 0 };
oct_node root = node_new(0, 0, 0), got;
for (i = 0; i < im->w * im->h; i++, pix += 3)
heap_add(&heap, node_insert(root, pix));
while (heap.n > n_colors + 1)
heap_add(&heap, node_fold(pop_heap(&heap)));
double c;
for (i = 1; i < heap.n; i++) {
got = heap.buf[i];
c = got->count;
got->r = got->r / c + .5;
got->g = got->g / c + .5;
got->b = got->b / c + .5;
}
if (dither) error_diffuse(im, &heap);
else
for (i = 0, pix = im->pix; i < im->w * im->h; i++, pix += 3)
color_replace(root, pix);
node_free();
free(heap.buf);
}

12
tools/imagecon/quant.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
typedef struct {
int w, h;
unsigned char *pix;
} quant_image_t;
void
quant_quantize(quant_image_t* im, int n_colors, int dither);
quant_image_t*
quant_newImage(int w, int h);

294
tools/imagecon/sliced_ham.c Normal file
View File

@ -0,0 +1,294 @@
#include "imagecon.h"
static void
_sham_generateLinePalette(imagecon_image_t* ic, int line);
static void
_sham_outputCopperLine(imagecon_image_t* ic, FILE* fp, int line);
static FILE* _copperFP;
static amiga_color_t *combos;
static int totalCombinations = 16*16*16;
static amiga_color_t
_sham_getHamColor(dither_data_t data)
{
static int row = -1;
if (row != data.y) {
row = data.y;
_sham_generateLinePalette(data.ic, row);
_sham_outputCopperLine(data.ic, _copperFP, row);
}
ham_control_t ham = ham_findClosestPixel(data.ic, data.color, data.last);
return ham.pixel;
}
static ham_control_t*
_sham_createHams(imagecon_image_t* ic)
{
ham_control_t* hams = malloc(sizeof(ham_control_t)*ic->width*ic->height);
for (int y = 0; y < ic->height; y++) {
amiga_color_t lastPixel = { -1, -1, -1, -1};
_sham_generateLinePalette(ic, y);
for (int x = 0; x < ic->width; x++) {
amiga_color_t orig = color_ditheredToAmiga(color_getDitheredPixel(ic, x, y));
ham_control_t ham = ham_findClosestPixel(ic, orig, lastPixel);
lastPixel = ham.pixel;
hams[(y*ic->width)+x] = ham;
}
}
return hams;
}
static int
_score(imagecon_image_t* ic, int y)
{
long error = 0;
amiga_color_t lastPixel = { -1, -1, -1, -1};
for (int x = 0; x < ic->width; x++) {
amiga_color_t color = color_getOriginalPixel(ic, x, y);
ham_control_t ham = ham_findClosestPixel(ic, color, lastPixel);
error += color_delta(color, color_findClosestPalettePixel(ic, ham.pixel));
lastPixel = ham.pixel;
}
return error;
}
static void
_sham_bruteForceInit(imagecon_image_t* ic)
{
combos = malloc(sizeof(amiga_color_t)*totalCombinations);
int index = 0;
for (unsigned char r = 0; r <= 0xF; r++) {
for (unsigned char g = 0; g <= 0xF; g++) {
for (unsigned char b = 0; b <= 0xF; b++) {
combos[index].a = 255;
combos[index].r = r<<4;
combos[index].g = g<<4;
combos[index++].b = b<<4;
}
}
}
}
static void
_sham_bruteForceLinePalette(imagecon_image_t* ic, int row)
{
int length = 16;
bzero(ic->palette, sizeof(ic->palette));
ic->numColors = 16;
int step = 1;
long big = totalCombinations*length;
long b = 0;
for (int x = 0; x < length; x++) {
long benchmark = LONG_MAX;
int bmIndex = 0;
for (int i = 0; i < totalCombinations; i+=step, b+=step) {
ic->palette[x] = combos[i];
fflush(stdout);
printf("%c7", 27);
fflush(stdout);
printf(" %03d %05ld/%05ld (%ld%%)", row, b, big, (b*100L)/big);
fflush(stdout);
printf("%c8", 27);
fflush(stdout);
long score = _score(ic, row);
if (score < benchmark) {
benchmark = score;
bmIndex = i;
}
}
ic->palette[x] = combos[bmIndex];
}
}
static void
_sham_generateQuantizedLinePalette(imagecon_image_t* ic, int line)
{
liq_attr *attr = liq_attr_create();
void* ptr[1] = { &ic->rowPointers[line] };
liq_image *image = liq_image_create_rgba_rows(attr, ptr, ic->width, 1, /* gamma */0.0);
liq_set_max_colors(attr, config.maxColors);
liq_color color = {.a = 255, .r = 0, .b = 0, .g = 0};
liq_image_add_fixed_color(image, color);
liq_result *res = liq_quantize_image(attr, image);
const liq_palette *pal = liq_get_palette(res);
if (config.verbose) {
printf("_sham_generateQuantizedLinePalette: pal->count = %d\n", pal->count);
}
for (unsigned i = 0; i < pal->count; i++) {
ic->palette[i].r = pal->entries[i].r;
ic->palette[i].g = pal->entries[i].g;
ic->palette[i].b = pal->entries[i].b;
ic->palette[i].a = pal->entries[i].a;
}
for (unsigned i = 0; i < pal->count; i++) {
if (ic->palette[i].r == 0 &&
ic->palette[i].g == 0 &&
ic->palette[i].b == 0 &&
ic->palette[i].a == 255) {
if (i != 0) {
amiga_color_t black = ic->palette[i];
amiga_color_t other = ic->palette[0];
ic->palette[0] = black;
ic->palette[i] = other;
}
break;
}
}
ic->numColors = pal->count;
for (int i = 0; i < ic->numColors; i++) {
if (config.verbose) {
printf("%02d: r=%03d g=%03d b=%03d a=%03d\n", i, ic->palette[i].r, ic->palette[i].g, ic->palette[i].b, ic->palette[i].a);
}
}
liq_attr_destroy(attr);
liq_image_destroy(image);
liq_result_destroy(res);
}
static void
_sham_generateLinePalette(imagecon_image_t* ic, int line)
{
if (config.hamBruteForce) {
_sham_bruteForceLinePalette(ic, line);
} else {
_sham_generateQuantizedLinePalette(ic, line);
}
}
static void
_sham_outputCopperLine(imagecon_image_t* ic, FILE* fp, int line)
{
int endPos = 0xe1;
line = line+0x2c-1;
if (line <= 255) {
fprintf(fp, "\tdc.w $%x,$fffe\n",(line)<<8|endPos|1);
} else {
fprintf(fp, "\tdc.w $%x,$fffe\n", ((line)-256)<<8|endPos|1);
}
for (int i = 1; i < ic->numColors; i++) {
fprintf(fp, "\tdc.w $%x,$%x\n", 0x180+(i*2), RGB24TORGB12(ic->palette[i].r) << 8 | RGB24TORGB12(ic->palette[i].g) << 4 | RGB24TORGB12(ic->palette[i].b));
}
}
static void
_sham_outputBitplanes(imagecon_image_t* ic, FILE* copperFP, FILE* bitplaneFP)
{
int numBitPlanes = 6;
int byteWidth = (ic->width + 7) / 8;
char** bitplanes = malloc(sizeof(void*)*numBitPlanes);
for (int i = 0; i < numBitPlanes; i++) {
bitplanes[i] = calloc(byteWidth*ic->height, 1);
}
ham_control_t* hams;
if (config.dither) {
dither_image(ic, _sham_getHamColor);
hams = _sham_createHams(ic);
} else {
hams = malloc(sizeof(ham_control_t)*ic->width*ic->height);
for (int y = 0; y < ic->height; y++) {
_sham_generateLinePalette(ic, y);
_sham_outputCopperLine(ic, copperFP, y);
amiga_color_t lastPixel = { -1, -1, -1, -1};
for (int x = 0; x < ic->width; x++) {
amiga_color_t orig = color_getOriginalPixel(ic, x, y);
ham_control_t ham = ham_findClosestPixel(ic, orig, lastPixel);
lastPixel = ham.pixel;
hams[(y*ic->width)+x] = ham;
}
}
}
for (int y = 0, writeIndex = 0; y < ic->height; y++) {
for (int byte = 0;byte < byteWidth; byte++) {
for (int bit = 0; bit < 8; bit++) {
int x = byte * 8 + 7 - bit;
ham_control_t ham = hams[(y*ic->width)+x];
int _numBitPlanes = 4;
for (int plane_index = 0; plane_index < _numBitPlanes; plane_index++) {
char* plane = bitplanes[plane_index];
plane[writeIndex] |= ((ham.data >> plane_index) & 1) << bit;
}
for (int plane_index = 0; plane_index < 2; plane_index++) {
char* plane = bitplanes[4+plane_index];
plane[writeIndex] |= ((ham.control >> plane_index) & 1) << bit;
}
}
writeIndex++;
}
}
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, bitplaneFP);
}
}
if (config.verbose) {
printf("done\n\n");
}
}
void
sham_process(imagecon_image_t* ic, char* outFilename)
{
config.maxColors = 16;
_copperFP = file_openWrite("%s-sham-copper.s", outFilename);
FILE* bitplaneFP = file_openWrite("%s-sham.bin", outFilename);
if (config.hamBruteForce) {
_sham_bruteForceInit(ic);
}
if (config.outputBitplanes) {
_sham_outputBitplanes(ic, _copperFP, bitplaneFP);
}
fclose(_copperFP);
fclose(bitplaneFP);
}