#pragma ident "@(#)cgpnormal.c 1.2 97/10/28 SMI"

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


/******************************************************************************
 * cgpnormal.c
 *
 * This file contains all the normal compressed geometry routines.
 *
 *  List of functions in this file:
 *      cgNormal3f
 *      cgNormal3fv
 *      cgNormal3b
 *      cgNormal3bv
 *	cgNormal3d
 *	cgNormal3dv
 *	cgNormal3i
 *	cgNormal3iv
 *	cgNormal3s
 *	cgNormal3sv
 *
 *****************************************************************************/

#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           */
/*******************
 * cgNormal3f
 *
 *  Used to update the current normal using CGfloat values
 *
 *  Input:
 *    CGbyte nx.
 *    CGbyte ny.
 *    CGbyte nz.
 *
 *  Output:
 *    None.
 *
 */
void
cgNormal3f (CGfloat nx, CGfloat ny, CGfloat nz)
{
    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 (CurrentState & CGP_CS_LIB_NO_VERTEX)
        {
            /* no vertex yet so our ptType at least has normal info */
            prim->primFlags |= CGP_PT_TYPE_VTX_NORMAL;

            /* this also means the global color won't be used */
            prim->primFlags &= ~CGP_GLOBAL_NORMAL_VALID;

            CurPt->nX = nx;
            CurPt->nY = ny;
            CurPt->nZ = nz;

            CurrentState |= CGP_CS_VTX_HAS_NORMAL;
        }
        else
        {
            /* already have at least one vertex, check for proper point type */
            if (prim->primFlags & CGP_PT_TYPE_VTX_NORMAL)
            {
                CurPt->nX = nx;
                CurPt->nY = ny;
                CurPt->nZ = nz;

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

    /* new current normal value */
    CurNX = nx;
    CurNY = ny;
    CurNZ = nz;

    CurrentState |= CGP_CS_CURRENT_NORMAL_VALID;
}


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


/*******************
 * cgNormal3b
 *
 *  Used to update the current normal using CGbyte values.
 *  Converts values to CGfloat and calls cgNormal3f.
 *
 *  Input:
 *    CGbyte nx.
 *    CGbyte ny.
 *    CGbyte nz.
 *
 *  Output:
 *    None.
 *
 */
void
cgNormal3b (CGbyte nx, CGbyte ny, CGbyte nz)
{
    CGfloat fNx, fNy, fNz;

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

    fNx = (CGfloat) nx * maxInverse;
    fNy = (CGfloat) ny * maxInverse;
    fNz = (CGfloat) nz * maxInverse;

    cgNormal3f(fNx, fNy, fNz);
}


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


/*******************
 * cgNormal3d
 *
 *  Used to update the current normal using CGdouble values.
 *  Converts values to CGfloat and calls cgNormal3f.
 *
 *  Input:
 *    CGdouble nx.
 *    CGdouble ny.
 *    CGdouble nz.
 *
 *  Output:
 *    None.
 *
 */
void
cgNormal3d (CGdouble nx, CGdouble ny, CGdouble nz)
{
    cgNormal3f((CGfloat) nx, (CGfloat) ny, (CGfloat) nz);
}


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


/*******************
 * cgNormal3i
 *
 *  Used to update the current normal using CGint values.
 *  Converts values to CGfloat and calls cgNormal3f.
 *
 *  Input:
 *    CGint nx.
 *    CGint ny.
 *    CGint nz.
 *
 *  Output:
 *    None.
 *
 */
void
cgNormal3i (CGint nx, CGint ny, CGint nz)
{
    CGfloat fNx, fNy, fNz;

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

    fNx = (CGfloat) nx * maxInverse;
    fNy = (CGfloat) ny * maxInverse;
    fNz = (CGfloat) nz * maxInverse;

    cgNormal3f(fNx, fNy, fNz);
}


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


/*******************
 * cgNormal3s
 *
 *  Used to update the current normal using CGshort values.
 *  Converts values to CGfloat and calls cgNormal3f.
 *
 *  Input:
 *    CGshort nx.
 *    CGshort ny.
 *    CGshort nz.
 *
 *  Output:
 *    None.
 *
 */
void
cgNormal3s (CGshort nx, CGshort ny, CGshort nz)
{
    CGfloat fNx, fNy, fNz;

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


    fNx = (CGfloat) nx * maxInverse;
    fNy = (CGfloat) ny * maxInverse;
    fNz = (CGfloat) nz * maxInverse;

    cgNormal3f(fNx, fNy, fNz);
}


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

