#pragma ident "@(#)cgpcolor.c 1.3 97/10/28 SMI"

/*
 * Copyright (c) 1997 by Sun Microsystems, Inc.
 * All Rights Reserved
 */


/******************************************************************************
 * cgpcolor.c
 *
 * This file contains all the color compressed geometry routines.
 *
 *  List of functions in this file:
 *      cgColor3f
 *      cgColor3fv
 *      cgColor3b
 *      cgColor3v
 *      cgColor3ub
 *      cgColor3ubv
 *      cgColor3d
 *      cgColor3dv
 *      cgColor3i
 *      cgColor3iv
 *      cgColor3ui
 *      cgColor3uiv
 *      cgColor3s
 *      cgColor3sv
 *      cgColor3us
 *      cgColor3usv
 *      cgColor4f
 *      cgColor4fv
 *      cgColor4b
 *      cgColor4v
 *      cgColor4ub
 *      cgColor4ubv
 *      cgColor4d
 *      cgColor4dv
 *      cgColor4i
 *      cgColor4iv
 *      cgColor4ui
 *      cgColor4uiv
 *      cgColor4s
 *      cgColor4sv
 *      cgColor4us
 *      cgColor4usv
 *
 *****************************************************************************/

#include "cgpi.h"


/* these reside in cgpmisc.c */
extern CGenum           CgError;

extern CGbitfield       CurrentState;           /* state of CG library       */

extern CGenum           CurFrontFace;
extern CGfloat          CurNX;                  /* global normal             */
extern CGfloat          CurNY;
extern CGfloat          CurNZ;
extern CGfloat          CurRed;                 /* global color              */
extern CGfloat          CurGreen;
extern CGfloat          CurBlue;
extern CGfloat          CurAlpha;

extern CGPprimlist*     Prims;                  /* list of primitives        */
extern CGPprimlist*     CurPrim;                /* current primitive         */
extern CGuint           NumPrims;               /* total number of primitives*/

extern CGPptbuffer*     CurPtBuffer;            /* Buffer being filled       */
extern CGPpoint*        CurPt;                  /* Point being processed     */
extern CGuint           NumPts;                 /* number of points in       */
                                                /*  current buffer           */

/*******************
 * cgColor3f
 *
 *  Used to update the current color using CGfloat values.
 *
 *  Input:
 *    CGfloat red.
 *    CGfloat green.
 *    CGfloat blue.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor3f (CGfloat red, CGfloat green, CGfloat blue)
{
    CGPprimitive*    prim = &CurPrim->primitive;

    /* must be within a BeginStream for this to be valid */
    if (!(CurrentState & CGP_CS_LIB_IN_BEGIN_STREAM))
    {
        cgiSetError(CG_INVALID_OPERATION);
        return;
    }

    /* if within a cgBegin add to point list */
    if (CurrentState & CGP_CS_LIB_IN_CGBEGIN)
    {
        /* if no cgVertex command yet, update point type as well */
        if (CurrentState & CGP_CS_LIB_NO_VERTEX)
        {
            /* no vertex yet so our ptType at least has color info */
            prim->primFlags |= CGP_PT_TYPE_VTX_COLOR;

            /* this also means the global color won't be used */
            prim->primFlags &=
              ~(CGP_GLOBAL_COLOR_VALID | CGP_GLOBAL_ALPHA_VALID);

            CurPt->r = red;
            CurPt->g = green;
            CurPt->b = blue;

            CurrentState |= CGP_CS_VTX_HAS_COLOR;
        }
        else
        {
            /* already have at least one vertex, check for proper point type */
            if (prim->primFlags & CGP_PT_TYPE_VTX_COLOR &&
                !(prim->primFlags & CGP_PT_TYPE_VTX_COLOR_ALPHA))
            {
                CurPt->r = red;
                CurPt->g = green;
                CurPt->b = blue;

                CurrentState |= CGP_CS_VTX_HAS_COLOR;
            }
            else
            {
                cgiSetError(CG_DATA_INCONSISTENT);
                return;
            }
        }
    }

    /* new current color value */
    CurRed = red;
    CurGreen = green;
    CurBlue = blue;
    CurAlpha = 1.0;

    CurrentState |= CGP_CS_CURRENT_COLOR_VALID;
}


/*******************
 * cgColor3fv
 *
 *  Used to update the current color using a CGfloat array.
 *  Converts values to CGfloat and calls cgColor3f.
 *
 *  Input:
 *    CGfloat *v.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor3fv (const CGfloat *v)
{
    cgColor3f(*v++, *v++, *v);
}


/*******************
 * cgColor3b
 *
 *  Used to update the current color using CGbyte values.
 *  Converts values to CGfloat and calls cgColor3f.
 *
 *  Input:
 *    CGbyte red.
 *    CGbyte green.
 *    CGbyte blue.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor3b (CGbyte red, CGbyte green, CGbyte blue)
{
    CGfloat fRed, fGreen, fBlue;

    /* for complete accuracy should have 1.0 / 127.0 as well */
    CGfloat maxInverse = 1.0 / 128.0;

    fRed = (CGfloat) red * maxInverse;
    fGreen = (CGfloat) green * maxInverse;
    fBlue = (CGfloat) blue * maxInverse;

    cgColor3f(fRed, fGreen, fBlue);
}


/*******************
 * cgColor3bv
 *
 *  Used to update the current color using a CGbyte array.
 *  Converts values to CGbyte and calls cgColor3b.
 *
 *  Input:
 *    CGbyte *v.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor3bv (const CGbyte *v)
{
    cgColor3b(*v++, *v++, *v);
}


/*******************
 * cgColor3ub
 *
 *  Used to update the current color using CGubyte values.
 *  Converts values to CGfloat and calls cgColor3f.
 *
 *  Input:
 *    CGubyte red.
 *    CGubyte green.
 *    CGubyte blue.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor3ub (CGubyte red, CGubyte green, CGubyte blue)
{
    CGfloat fRed, fGreen, fBlue;

    CGfloat maxInverse = 1.0 / 256.0;  /* 2^8 */

    fRed = (CGfloat) red * maxInverse;
    fGreen = (CGfloat) green * maxInverse;
    fBlue = (CGfloat) blue * maxInverse;

    cgColor3f(fRed, fGreen, fBlue);
}


/*******************
 * cgColor3ubv
 *
 *  Used to update the current color using a CGubyte array.
 *  Converts values to CGubyte and calls cgColor3ub.
 *
 *  Input:
 *    CGubyte *v.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor3ubv (const CGubyte *v)
{
    cgColor3ub(*v++, *v++, *v);
}


/*******************
 * cgColor3d
 *
 *  Used to update the current color using CGdouble values.
 *  Converts values to CGfloat and calls cgColor3f.
 *
 *  Input:
 *    CGdouble red.
 *    CGdouble green.
 *    CGdouble blue.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor3d (CGdouble red, CGdouble green, CGdouble blue)
{
    cgColor3f((CGfloat) red, (CGfloat) green, (CGfloat) blue);
}


/*******************
 * cgColor3dv
 *
 *  Used to update the current color using a CGdouble array.
 *  Converts values to CGfloat and calls cgColor3f.
 *
 *  Input:
 *    CGdouble *v.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor3dv (const CGdouble *v)
{
    cgColor3f((CGfloat) *v++, (CGfloat) *v++, (CGfloat) *v);
}


/*******************
 * cgColor3i
 *
 *  Used to update the current color using CGint values.
 *  Converts values to CGfloat and calls cgColor3f.
 *
 *  Input:
 *    CGint red.
 *    CGint green.
 *    CGint blue.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor3i (CGint red, CGint green, CGint blue)
{
    CGfloat fRed, fGreen, fBlue;

    /* for complete accuracy should have 1.0 / 2147483647.0 as well */
    CGfloat maxInverse = 1.0 / 2147483648.0;  /* 2^31 = 2147483648 */

    fRed = (CGfloat) red * maxInverse;
    fGreen = (CGfloat) green * maxInverse;
    fBlue = (CGfloat) blue * maxInverse;

    cgColor3f(fRed, fGreen, fBlue);
}


/*******************
 * cgColor3iv
 *
 *  Used to update the current color using a CGint array.
 *  Converts values to CGint and calls cgColor3i.
 *
 *  Input:
 *    CGint *v.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor3iv (const CGint *v)
{
    cgColor3i(*v++, *v++, *v);
}


/*******************
 * cgColor3ui
 *
 *  Used to update the current color using CGuint values.
 *  Converts values to CGfloat and calls cgColor3f.
 *
 *  Input:
 *    CGuint red.
 *    CGuint green.
 *    CGuint blue.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor3ui (CGuint red, CGuint green, CGuint blue)
{
    CGfloat fRed, fGreen, fBlue;

    CGfloat maxInverse = 1.0 / 4294967296.0;  /* 2^32 */

    fRed = (CGfloat) red * maxInverse;
    fGreen = (CGfloat) green * maxInverse;
    fBlue = (CGfloat) blue * maxInverse;

    cgColor3f(fRed, fGreen, fBlue);
}


/*******************
 * cgColor3uiv
 *
 *  Used to update the current color using a CGuint array.
 *  Converts values to CGuint and calls cgColor3ui.
 *
 *  Input:
 *    CGuint *v.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor3uiv (const CGuint *v)
{
    cgColor3i(*v++, *v++, *v);
}


/*******************
 * cgColor3s
 *
 *  Used to update the current color using CGshort values.
 *  Converts values to CGfloat and calls cgColor3f.
 *
 *  Input:
 *    CGshort red.
 *    CGshort green.
 *    CGshort blue.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor3s (CGshort red, CGshort green, CGshort blue)
{
    CGfloat fRed, fGreen, fBlue;

    /* for complete accuracy should have 1.0 / 32767.0 as well */
    CGfloat maxInverse = 1.0 / 32768.0;  /* 2^15 = 32768; */

    fRed = (CGfloat) red * maxInverse;
    fGreen = (CGfloat) green * maxInverse;
    fBlue = (CGfloat) blue * maxInverse;

    cgColor3f(fRed, fGreen, fBlue);
}


/*******************
 * cgColor3sv
 *
 *  Used to update the current color using a CGshort array.
 *  Converts values to CGshort and calls cgColor3s.
 *
 *  Input:
 *    CGshort *v.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor3sv (const CGshort *v)
{
    cgColor3s(*v++, *v++, *v);
}


/*******************
 * cgColor3us
 *
 *  Used to update the current color using CGushort values.
 *  Converts values to CGfloat and calls cgColor3f.
 *
 *  Input:
 *    CGushort red.
 *    CGushort green.
 *    CGushort blue.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor3us (CGushort red, CGushort green, CGushort blue)
{
    CGfloat fRed, fGreen, fBlue;

    CGfloat maxInverse = 1.0 / 65536.0;  /* 2^16 */

    fRed = (CGfloat) red * maxInverse;
    fGreen = (CGfloat) green * maxInverse;
    fBlue = (CGfloat) blue * maxInverse;

    cgColor3f(fRed, fGreen, fBlue);
}


/*******************
 * cgColor3usv
 *
 *  Used to update the current color using a CGushort array.
 *  Converts values to CGushort and calls cgColor3us.
 *
 *  Input:
 *    CGushort *v.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor3usv (const CGushort *v)
{
    cgColor3us(*v++, *v++, *v);
}


/*******************
 * cgColor4f
 *
 *  Used to update the current color using CGfloat values.
 *
 *  Input:
 *    CGfloat red.
 *    CGfloat green.
 *    CGfloat blue.
 *    CGfloat alpha.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor4f (CGfloat red, CGfloat green, CGfloat blue, CGfloat alpha)
{
    CGPprimitive*	prim = &CurPrim->primitive;

    /* must be within a BeginStream for this to be valid */
    if (!(CurrentState & CGP_CS_LIB_IN_BEGIN_STREAM))
    {
        cgiSetError(CG_INVALID_OPERATION);
        return;
    }

    /* if within a cgBegin add to point list */
    if (CurrentState & CGP_CS_LIB_IN_CGBEGIN)
    {
        /* if no cgVertex command yet, update point type as well */
        if (CurrentState & CGP_CS_LIB_NO_VERTEX)
        {
            /* no vertex yet so our ptType at least has color info */
            prim->primFlags |= CGP_PT_TYPE_VTX_COLOR |
                               CGP_PT_TYPE_VTX_COLOR_ALPHA;

            /* this also means the global color won't be used */
            prim->primFlags &=
              ~(CGP_GLOBAL_COLOR_VALID | CGP_GLOBAL_ALPHA_VALID);

            CurPt->r = red;
            CurPt->g = green;
            CurPt->b = blue;
            CurPt->a = alpha;

            CurrentState |= CGP_CS_VTX_HAS_COLOR;
        }
        else
        {
            /* already have at least one vertex, check for proper point type */
            if (prim->primFlags &
 		(CGP_PT_TYPE_VTX_COLOR | CGP_PT_TYPE_VTX_COLOR_ALPHA))
            {
                CurPt->r = red;
                CurPt->g = green;
                CurPt->b = blue;
                CurPt->a = alpha;

                CurrentState |= CGP_CS_VTX_HAS_COLOR;
            }
            else
            {
                cgiSetError(CG_DATA_INCONSISTENT);
                return;
            }
        }
    }

    /* new current color value */
    CurRed = red;
    CurGreen = green;
    CurBlue = blue;
    CurAlpha = alpha;

    CurrentState |= CGP_CS_CURRENT_COLOR_VALID |  CGP_CS_CURRENT_ALPHA_VALID;
}


/*******************
 * cgColor4fv
 *
 *  Used to update the current color using a CGfloat array.
 *  Converts values to CGfloat and calls cgColor4f.
 *
 *  Input:
 *    CGfloat *v.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor4fv (const CGfloat *v)
{
    cgColor4f(*v++, *v++, *v++, *v);
}


/*******************
 * cgColor4b
 *
 *  Used to update the current color using CGbyte values.
 *  Converts values to CGfloat and calls cgColor4f.
 *
 *  Input:
 *    CGbyte red.
 *    CGbyte green.
 *    CGbyte blue.
 *    CGbyte alpha.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor4b (CGbyte red, CGbyte green, CGbyte blue, CGbyte alpha)
{
    CGfloat fRed, fGreen, fBlue, fAlpha;

    /* for complete accuracy should have 1.0 / 127.0 as well */
    CGfloat maxInverse = 1.0 / 128.0;

    fRed = (CGfloat) red * maxInverse;
    fGreen = (CGfloat) green * maxInverse;
    fBlue = (CGfloat) blue * maxInverse;
    fAlpha = (CGfloat) alpha * maxInverse;

    cgColor4f(fRed, fGreen, fBlue, fAlpha);
}


/*******************
 * cgColor4bv
 *
 *  Used to update the current color using a CGbyte array.
 *  Converts values to CGbyte and calls cgColor4b.
 *
 *  Input:
 *    CGbyte *v.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor4bv (const CGbyte *v)
{
    cgColor4b(*v++, *v++, *v++, *v);
}


/*******************
 * cgColor4ub
 *
 *  Used to update the current color using CGubyte values.
 *  Converts values to CGfloat and calls cgColor4f.
 *
 *  Input:
 *    CGubyte red.
 *    CGubyte green.
 *    CGubyte blue.
 *    CGubyte alpha.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor4ub (CGubyte red, CGubyte green, CGubyte blue, CGubyte alpha)
{
    CGfloat fRed, fGreen, fBlue, fAlpha;

    CGfloat maxInverse = 1.0 / 256.0;  /* 2^8 */

    fRed = (CGfloat) red * maxInverse;
    fGreen = (CGfloat) green * maxInverse;
    fBlue = (CGfloat) blue * maxInverse;
    fAlpha = (CGfloat) alpha * maxInverse;

    cgColor4f(fRed, fGreen, fBlue, fAlpha);
}


/*******************
 * cgColor4ubv
 *
 *  Used to update the current color using a CGubyte array.
 *  Converts values to CGubyte and calls cgColor4ub.
 *
 *  Input:
 *    CGubyte *v.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor4ubv (const CGubyte *v)
{
    cgColor4ub(*v++, *v++, *v++, *v);
}


/*******************
 * cgColor4d
 *
 *  Used to update the current color using CGdouble values.
 *  Converts values to CGfloat and calls cgColor4f.
 *
 *  Input:
 *    CGdouble red.
 *    CGdouble green.
 *    CGdouble blue.
 *    CGdouble alpha.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor4d (CGdouble red, CGdouble green, CGdouble blue, CGdouble alpha)
{
    cgColor4f((CGfloat) red, (CGfloat) green, (CGfloat) blue, (CGfloat) alpha);
}


/*******************
 * cgColor4dv
 *
 *  Used to update the current color using a CGdouble array.
 *  Converts values to CGfloat and calls cgColor4f.
 *
 *  Input:
 *    CGdouble *v.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor4dv (const CGdouble *v)
{
    cgColor4f((CGfloat) *v++, (CGfloat) *v++, (CGfloat) *v++, (CGfloat) *v);
}


/*******************
 * cgColor4i
 *
 *  Used to update the current color using CGint values.
 *  Converts values to CGfloat and calls cgColor4f.
 *
 *  Input:
 *    CGint red.
 *    CGint green.
 *    CGint blue.
 *    CGint alpha.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor4i (CGint red, CGint green, CGint blue, CGint alpha)
{
    CGfloat fRed, fGreen, fBlue, fAlpha;

    /* for complete accuracy should have 1.0 / 2147483647.0 as well */
    CGfloat maxInverse = 1.0 / 2147483648.0;  /* 2^31 = 2147483648 */

    fRed = (CGfloat) red * maxInverse;
    fGreen = (CGfloat) green * maxInverse;
    fBlue = (CGfloat) blue * maxInverse;
    fAlpha = (CGfloat) alpha * maxInverse;

    cgColor4f(fRed, fGreen, fBlue, fAlpha);
}


/*******************
 * cgColor4iv
 *
 *  Used to update the current color using a CGint array.
 *  Converts values to CGint and calls cgColor4i.
 *
 *  Input:
 *    CGint *v.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor4iv (const CGint *v)
{
    cgColor4i(*v++, *v++, *v++, *v);
}


/*******************
 * cgColor4ui
 *
 *  Used to update the current color using CGuint values.
 *  Converts values to CGfloat and calls cgColor4f.
 *
 *  Input:
 *    CGuint red.
 *    CGuint green.
 *    CGuint blue.
 *    CGuint alpha.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor4ui (CGuint red, CGuint green, CGuint blue, CGuint alpha)
{
    CGfloat fRed, fGreen, fBlue, fAlpha;

    CGfloat maxInverse = 1.0 / 4294967296.0;  /* 2^32 */

    fRed = (CGfloat) red * maxInverse;
    fGreen = (CGfloat) green * maxInverse;
    fBlue = (CGfloat) blue * maxInverse;
    fAlpha = (CGfloat) alpha * maxInverse;

    cgColor4f(fRed, fGreen, fBlue, fAlpha);
}


/*******************
 * cgColor4uiv
 *
 *  Used to update the current color using a CGuint array.
 *  Converts values to CGuint and calls cgColor4ui.
 *
 *  Input:
 *    CGuint *v.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor4uiv (const CGuint *v)
{
    cgColor4ui(*v++, *v++, *v++, *v);
}


/*******************
 * cgColor4s
 *
 *  Used to update the current color using CGshort values.
 *  Converts values to CGfloat and calls cgColor4f.
 *
 *  Input:
 *    CGshort red.
 *    CGshort green.
 *    CGshort blue.
 *    CGshort alpha.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor4s (CGshort red, CGshort green, CGshort blue, CGshort alpha)
{
    CGfloat fRed, fGreen, fBlue, fAlpha;

    /* for complete accuracy should have 1.0 / 32767.0 as well */
    CGfloat maxInverse = 1.0 / 32768.0;  /* 2^15 = 32768; */

    fRed = (CGfloat) red * maxInverse;
    fGreen = (CGfloat) green * maxInverse;
    fBlue = (CGfloat) blue * maxInverse;
    fAlpha = (CGfloat) alpha * maxInverse;

    cgColor4f(fRed, fGreen, fBlue, fAlpha);
}


/*******************
 * cgColor4sv
 *
 *  Used to update the current color using a CGshort array.
 *  Converts values to CGshort and calls cgColor4s.
 *
 *  Input:
 *    CGshort *v.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor4sv (const CGshort *v)
{
    cgColor4s(*v++, *v++, *v++, *v);
}


/*******************
 * cgColor4us
 *
 *  Used to update the current color using CGushort values.
 *  Converts values to CGfloat and calls cgColor4f.
 *
 *  Input:
 *    CGushort red.
 *    CGushort green.
 *    CGushort blue.
 *    CGushort alpha.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor4us (CGushort red, CGushort green, CGushort blue, CGushort alpha)
{
    CGfloat fRed, fGreen, fBlue, fAlpha;

    CGfloat maxInverse = 1.0 / 65536.0;  /* 2^16 */

    fRed = (CGfloat) red * maxInverse;
    fGreen = (CGfloat) green * maxInverse;
    fBlue = (CGfloat) blue * maxInverse;
    fAlpha = (CGfloat) alpha * maxInverse;

    cgColor4f(fRed, fGreen, fBlue, fAlpha);
}


/*******************
 * cgColor4usv
 *
 *  Used to update the current color using a CGushort array.
 *  Converts values to CGushort and calls cgColor4us.
 *
 *  Input:
 *    CGushort *v.
 *
 *  Output:
 *    None.
 *
 */
void
cgColor4usv (const CGushort *v)
{
    cgColor4us(*v++, *v++, *v++, *v);
}

