#ifndef lint
static char *sccsid = "@(#)color.c 1.3 91/09/14";
#endif

/*
 * Copyright (c) 1990 by Sun Microsystems, Inc.
 */

/*
 * Referernce:
 * Hearn/Baker, "Computer Graphics", Prentice Hall, Section 14-4.
 */

#include <X11/Xlib.h>
#include "color.h"

static int
max3(x, y, z)
    register int x,
                y,
                z;
{
    if (y > x)
	x = y;
    if (z > x)
	x = z;
    return x;
}

static int
min3(x, y, z)
    register int x,
                y,
                z;
{
    if (y < x)
	x = y;
    if (z < x)
	x = z;
    return x;
}

void
hsv_to_rgb(hsv, rgb)
    HSV        *hsv;
    RGB        *rgb;
{
    int         h = hsv->h;
    int         s = hsv->s;
    int         v = hsv->v;
    int         r,
                g,
                b;
    int         i,
                f;
    int         p,
                q,
                t;

    s = (s * MAXRGB) / MAXSV;
    v = (v * MAXRGB) / MAXSV;
    if (h == 360)
	h = 0;

    if (s == 0) {
	h = 0;
	r = g = b = v;
    }
    i = h / 60;
    f = h % 60;
    p = v * (MAXRGB - s) / MAXRGB;
    q = v * (MAXRGB - s * f / 60) / MAXRGB;
    t = v * (MAXRGB - s * (60 - f) / 60) / MAXRGB;

    switch (i) {
    case 0:
	r = v, g = t, b = p;
	break;
    case 1:
	r = q, g = v, b = p;
	break;
    case 2:
	r = p, g = v, b = t;
	break;
    case 3:
	r = p, g = q, b = v;
	break;
    case 4:
	r = t, g = p, b = v;
	break;
    case 5:
	r = v, g = p, b = q;
	break;
    }
    rgb->r = r;
    rgb->g = g;
    rgb->b = b;
}

void
rgb_to_hsv(rgb, hsv)
    RGB        *rgb;
    HSV        *hsv;
{
    int         r = rgb->r;
    int         g = rgb->g;
    int         b = rgb->b;
    register int maxv = max3(r, g, b);
    register int minv = min3(r, g, b);
    int         h;
    int         s;
    int         v;

    v = maxv;

    if (maxv) {
	s = (maxv - minv) * MAXRGB / maxv;
    } else {
	s = 0;
    }

    if (s == 0) {
	h = 0;
    } else {
	int         rc;
	int         gc;
	int         bc;
	int         hex;

	rc = (maxv - r) * MAXRGB / (maxv - minv);
	gc = (maxv - g) * MAXRGB / (maxv - minv);
	bc = (maxv - b) * MAXRGB / (maxv - minv);

	if (r == maxv) {
	    h = bc - gc, hex = 0;
	} else if (g == maxv) {
	    h = rc - bc, hex = 2;
	} else if (b == maxv) {
	    h = gc - rc, hex = 4;
	}
	h = hex * 60 + (h * 60 / MAXRGB);
	if (h < 0)
	    h += 360;
    }
    hsv->h = h;
    hsv->s = (s * MAXSV) / MAXRGB;
    hsv->v = (v * MAXSV) / MAXRGB;
}

/*
 * Load an XColor with an RGB.
 */
void
rgb_to_xcolor(r, x)
    RGB        *r;
    XColor     *x;
{
    x->red = (unsigned short) r->r << 8;
    x->green = (unsigned short) r->g << 8;
    x->blue = (unsigned short) r->b << 8;
    x->flags = DoRed | DoGreen | DoBlue;
}

/*
 * Load an XColor with an HSV.
 */
void
hsv_to_xcolor(h, x)
    HSV        *h;
    XColor     *x;
{
    RGB         r;
    hsv_to_rgb(h, &r);
    rgb_to_xcolor(&r, x);
}

/*
 * Load an HSV with an XColor.
 */
void
xcolor_to_hsv(x, h)
    XColor     *x;
    HSV        *h;
{
    RGB         r;
    r.r = (int) x->red >> 8;
    r.g = (int) x->green >> 8;
    r.b = (int) x->blue >> 8;
    rgb_to_hsv(&r, h);
}

/*
 * Take an HSV and generate the 3 OpenLook 3D colors into XColor structures.
 */
void
olgx_hsv_to_3D(bg1, bg2, bg3, white)
    HSV        *bg1;
    XColor     *bg2,
               *bg3,
               *white;
{
    HSV         hsv;
    int         h = bg1->h;
    int         s = bg1->s;
    int         v = bg1->v;

    v = (v * VMUL) / 10;
    if (v > MAXSV) {
	s /= SDIV;
	v = MAXSV;
    }
    if (v < VMIN)
	v = VMIN;

    hsv.h = h;
    hsv.s = s;
    hsv.v = v;
    hsv_to_xcolor(&hsv, white);

    hsv.h = bg1->h;
    hsv.s = bg1->s;
    hsv.v = (bg1->v * 9) / 10;			/* 90% */
    hsv_to_xcolor(&hsv, bg2);

    hsv.h = bg1->h;
    hsv.s = bg1->s;
    hsv.v = bg1->v >> 1;			/* 50% */
    hsv_to_xcolor(&hsv, bg3);
}

/*
 * Take an XColor (BG1) and generate the 3 OpenLook 3D colors into XColor structures.
 */
void
olgx_calculate_3Dcolors(fg, bg1, bg2, bg3, white)
    XColor     *fg;
    XColor     *bg1,
               *bg2,
               *bg3,
               *white;
{
    HSV         base;

    xcolor_to_hsv(bg1, &base);
    olgx_hsv_to_3D(&base, bg2, bg3, white);
}
