/*
 * cmap.c
 *
 * Copyright (C) 1993-1998 Evan Harris
 *
 * Permission is granted to freely redistribute and modify this code,
 * providing the author(s) get credit for having written it.
 */

/* 	$Id: cmap.c,v 1.5 1998/10/01 02:52:01 evan Exp $	 */

#ifndef lint
static char vcid[] = "$Id: cmap.c,v 1.5 1998/10/01 02:52:01 evan Exp $";
#endif /* lint */

#include "seejpeg.h"
#include <vga.h>


#define HASHTABLESIZE 1024
#define CMAPSIZE 256

/*
 * We probably need a better hash function, but this is better than
 * nothing
 */
#define HASH(r, g, b) (((r) << 4) ^ ((g) << 2) ^ (b))

#define NOENTRY 0x80000000

static unsigned long hashtable[HASHTABLESIZE];

static unsigned long last_colour;
static int next_cmap_entry, black_seen;

void
translate_init(void)
{
    int i;

    last_colour = 0;
    next_cmap_entry = 1;
    black_seen = 0;

    for (i = 0; i < HASHTABLESIZE; i++)
    {
	hashtable[i] = NOENTRY;
    }
}


static JSAMPLE
lookup_colour(JSAMPLE r, JSAMPLE g, JSAMPLE b)
{
    unsigned long colour;
    int key;
    int out_r, out_g, out_b;

    out_r = gamma_table_shift2[r];
    out_g = gamma_table_shift2[g];
    out_b = gamma_table_shift2[b];

    /*
     * VGA colours are 18 bit.
     */
    r >>= 2;
    g >>= 2;
    b >>= 2;

    colour = ((r << 20) | (g << 14) | (b << 8));
    if (colour == (last_colour & 0xffffff00))
    {
	return (last_colour & 0xff);
    }

    key = HASH(r, g, b);
  
    while (hashtable[key] != NOENTRY
	   && colour != (hashtable[key] & 0xffffff00))
    {
	if (++key == HASHTABLESIZE)
	{
	    key = 0;
	}
    }
    if (hashtable[key] == NOENTRY)
    {
	if (colour == 0)
	{
	    hashtable[key] = (colour | 0);
	    vga_setpalette(0, out_r, out_g, out_b);
	    black_seen = 1;
	}
	else
	{
	    if (next_cmap_entry == CMAPSIZE && !black_seen)
	    {
		next_cmap_entry = 0;
	    }
	    else if (next_cmap_entry == CMAPSIZE || next_cmap_entry == 0)
	    {
		error_exit("Colour map full");
	    }

	    hashtable[key] = (colour | next_cmap_entry);
	    vga_setpalette(next_cmap_entry, out_r, out_g, out_b);

	    if (next_cmap_entry > 0)
	    {
		next_cmap_entry++;
	    }
	}
    }
    last_colour = hashtable[key];

    return (last_colour & 0xff);
}


void
translate_row(int width, JSAMPARRAY rgb_row, JSAMPARRAY cmap_row)
{
    JSAMPROW in, out;
    int i;

    /*
     * Assume there are three components in the input and one in the output
     */
    in = rgb_row[0];
    out = cmap_row[0];
  
    for (i = 0; i < width; i++)
    {
	*out++ = lookup_colour(*in, *(in + 1), *(in + 2));
	in += 3;
    }
}
