/*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */

#include "video.h"
#include "dither.h"
#include "proto.h"

/*
 * We'll define the "ConvertColor" macro here to do fixed point arithmetic
 * that'll convert from YCrCb to RGB using:
 *	R = L + 1.40200*Cr;
 *	G = L - 0.34414*Cb - 0.71414*Cr
 *	B = L + 1.77200*Cb;
 *
 * We'll use fixed point by adding two extra bits after the decimal.
 */

#define BITS	8
#define ONE     ((int) 1)
#define CONST_SCALE	(ONE << BITS)
#define ROUND_FACTOR	(ONE << (BITS-1))

/* Macro to convert integer to fixed. */
#define UP(x)	(((int)(x)) << BITS)

/* Macro to convert fixed to integer (with rounding). */
#define DOWN(x)	(((x) + ROUND_FACTOR) >> BITS)

/* Macro to convert a float to a fixed */
#define FIX(x)  ((int) ((x)*CONST_SCALE + 0.5))

#define CLAMP(ll,x,ul)	( ((x)<(ll)) ?(ll):( ((x)>(ul)) ?(ul):(x)))

static int *Cb_r_tab, *Cr_g_tab, *Cb_g_tab, *Cr_b_tab;

/*
 *--------------------------------------------------------------
 *
 * InitColorDither --
 *
 *	To get rid of the multiply and other conversions in color
 *	dither, we use a lookup table.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The lookup tables are initialized.
 *
 *--------------------------------------------------------------
 */

void
InitColorDither()
{
    int CR, CB, i;

    Cr_b_tab = (int *)malloc(256*sizeof(int));
    Cr_g_tab = (int *)malloc(256*sizeof(int));
    Cb_g_tab = (int *)malloc(256*sizeof(int));
    Cb_r_tab = (int *)malloc(256*sizeof(int));

    for (i=0; i<256; i++) {
	CB = CR = i;

	CB -= 128; CR -= 128;

	Cb_r_tab[i] = FIX(1.40200) * CB;
	Cr_g_tab[i] = -FIX(0.34414) * CR;
	Cb_g_tab[i] = -FIX(0.71414) * CB;   
	Cr_b_tab[i] = FIX(1.77200) * CR;
    }
}


/*
 *--------------------------------------------------------------
 *
 * ColorDitherImage --
 *
 *	Converts image into 24 bit color.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */

void
ColorDitherImage(lum, cr, cb, out, rows, cols)
  unsigned char *lum;
  unsigned char *cr;
  unsigned char *cb;
  unsigned char *out;
  int cols, rows;

{
    int L, CR, CB;
    unsigned int *row1, *row2;
    unsigned char *lum2;
    int x, y;
    unsigned int r, b, g;
    int cb_r;
    int cr_g;
    int cb_g;
    int cr_b;

    row1 = (unsigned int *)out;
    row2 = row1 + cols;
    lum2 = lum + cols;
    for (y=0; y<rows; y+=2) {
	for (x=0; x<cols; x+=2) {
	    int R, G, B;

	    CR = *cr++;
	    CB = *cb++;
	    cb_r = Cb_r_tab[CB];
	    cr_g = Cr_g_tab[CR];
	    cb_g = Cb_g_tab[CB];
	    cr_b = Cr_b_tab[CR];

	    L = *lum++;
	    L = UP(L);
	    R = L + cb_r;
	    G = L + cr_g + cb_g;
	    B = L + cr_b;
#ifndef RS6000
	    r = CLAMP(0,R,UP(255)) >> BITS;
	    g = CLAMP(0,G,UP(255)) & 0xff00;
	    b = (CLAMP(0,B,UP(255)) & 0xff00) << BITS;
#else
	    b = CLAMP(0,B,UP(255)) >> BITS;
	    g = CLAMP(0,G,UP(255)) & 0xff00;
	    r = (CLAMP(0,R,UP(255)) & 0xff00) << BITS;
#endif
	    *row1++ = r | g | b;

	    L = *lum++;
	    L = UP(L);
	    R = L + cb_r;
	    G = L + cr_g + cb_g;
	    B = L + cr_b;
#ifndef RS6000
	    r = CLAMP(0,R,UP(255)) >> BITS;
	    g = CLAMP(0,G,UP(255)) & 0xff00;
	    b = (CLAMP(0,B,UP(255)) & 0xff00) << BITS;
#else
	    b = CLAMP(0,B,UP(255)) >> BITS;
	    g = CLAMP(0,G,UP(255)) & 0xff00;
	    r = (CLAMP(0,R,UP(255)) & 0xff00) << BITS;
#endif
	    *row1++ = r | g | b;

	    /*
	     * Now, do second row.
	     */
	    L = *lum2++;
	    L = UP(L);
	    R = L + cb_r;
	    G = L + cr_g + cb_g;
	    B = L + cr_b;
#ifndef RS6000
	    r = CLAMP(0,R,UP(255)) >> BITS;
	    g = CLAMP(0,G,UP(255)) & 0xff00;
	    b = (CLAMP(0,B,UP(255)) & 0xff00) << BITS;
#else
	    b = CLAMP(0,B,UP(255)) >> BITS;
	    g = CLAMP(0,G,UP(255)) & 0xff00;
	    r = (CLAMP(0,R,UP(255)) & 0xff00) << BITS;
#endif
	    *row2++ = r | g | b;

	    L = *lum2++;
	    L = UP(L);
	    R = L + cb_r;
	    G = L + cr_g + cb_g;
	    B = L + cr_b;
#ifndef RS6000
	    r = CLAMP(0,R,UP(255)) >> BITS;
	    g = CLAMP(0,G,UP(255)) & 0xff00;
	    b = (CLAMP(0,B,UP(255)) & 0xff00) << BITS;
#else
	    b = CLAMP(0,B,UP(255)) >> BITS;
	    g = CLAMP(0,G,UP(255)) & 0xff00;
	    r = (CLAMP(0,R,UP(255)) & 0xff00) << BITS;
#endif
	    *row2++ = r | g | b;
	}
	lum += cols;
	lum2 += cols;
	row1 += cols;
	row2 += cols;
    }
}



