/***********************************************************************/
/* Open Visualization Data Explorer                                    */
/* (C) Copyright IBM Corp. 1989,1999                                   */
/* ALL RIGHTS RESERVED                                                 */
/* This code licensed under the                                        */
/*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
/***********************************************************************/

#include <dxconfig.h>


/*---------------------------------------------------------------------------*\
 $Source: /home/gda/dxcvs/dx/src/exec/hwrender/gl/hwPortUtil.c,v $

\*---------------------------------------------------------------------------*/

#ifndef HELPERCODE

#include <math.h>

#define X_H
#define Cursor glCursor
#define String glString
#define Boolean glBoolean
#define Object glObject
#include <gl/gl.h>
#undef Object
#undef Boolean
#undef String
#undef Cursor
#undef X_H

#include "hwDeclarations.h"
#include "hwPortLayer.h"
#include "hwXfield.h"
#include "hwWindow.h"
#include "hwPortGL.h"
#include "hwTmesh.h"
#include "hwSort.h"

#define String dxString
#define Object dxObject
#define Angle dxAngle
#define Matrix dxMatrix
#define Screen dxScreen
#define Boolean dxBoolean
#include "internals.h"
#undef String
#undef Object
#undef Angle
#undef Matrix
#undef Screen
#undef Boolean

#define TIMER(s) finish(); DXMarkTime(s);
#include "hwDebug.h"

#if 0
#define DXGetArrayEntry(x,y,z) (&zeroFloat)
static float zeroFloat[] = {0.57, 0.57, 0.57};
#endif

#ifdef DOPV
#include "pv/pv.h"
#else
#define PHASE_START(x)	{}
#define PHASE_END(y)	{}
#endif

#define NOTUSED	0

typedef void (*helperFunc) (xfieldP xf, int posPerConn, 
			    int ctIndex, int *translation, float *rgba);

static helperFunc
  getHelper(dependencyT colorsDep, 
	    dependencyT normalsDep, 
	    dependencyT opacitiesDep,
	    int texture);

static Error
  points (xfieldP xf, helperFunc helper,
	  int firstConnection, int lastConnection, int face,
	  enum approxE approx, int skip);

static Error
  bbox (xfieldP xf);

static void
_deleteGLObject(xfieldP xf);
#define RENDER_OPAQUE 1
#define RENDER_TRANSPARENT 2

#define	SENDPOSITION(offset) 						\
{ 								       	\
  float *position; 							\
  position = (float*)DXGetArrayEntry(xf->positions,offset,fscratch); 	\
  if(xf->shape < 3)							\
    v2f(position);	/* gl default z = 0.0 if 2d data */ 		\
  else									\
    v3f(position);							\
}

#ifdef sgi

#define SENDUV(offset)                                                  \
{                                                                       \
  float *uv ;                                                   	\
  uv = (float *)DXGetArrayEntry(xf->uv,offset,uvscratch) ;      	\
  t2f(uv) ;                                                   		\
}

#endif


#define	OPACITY(offset)								\
  ((xf->nomap) ?								\
	  *(float *)DXGetArrayEntry(xf->omap,					\
				    *(char *)DXGetArrayEntry(xf->opacities,	\
								offset,		\
								&iscratch),	\
				    fscratch)					\
      :										\
	  *(float *)DXGetArrayEntry(xf->opacities, offset, fscratch))


#define SENDOPACITY(offset) 					\
  if((xf->opacitiesDep != dep_none && GETOPACITY(0) < .75) ||	\
       xf->attributes.flags & CONTAINS_VOLUME) 			\
      setpattern(PATTERN_INDEX)
     

#define	SENDNORMAL(offset) \
{ \
  Vector normal; \
  normal = *(Vector*)DXGetArrayEntry(xf->normals,offset,fscratch); \
  n3f((float*)&normal); \
}

#define SENDSPECCOLOR()  				\
{							\
  RGBColor rgbspec; 					\
  rgbspec.r = rgbspec.g = rgbspec.b = 			\
    xf->attributes.front.specular;			\
  lmcolor (LMC_SPECULAR); 				\
  c3f((float *)&rgbspec); 				\
}

#define GETCOLOR(offset)							\
{										\
  Vector  rgbvec;								\
										\
  if(xf->ncmap) 							      	\
     rgbvec = *(Vector*)DXGetArrayEntry(xf->cmap, 			      	\
					*(ubyte *)DXGetArrayEntry(xf->fcolors, 	\
							       offset, 	      	\
							       &iscratch),    	\
					fscratch);			      	\
  else									      	\
     rgbvec = *(Vector*)DXGetArrayEntry(xf->fcolors,offset,fscratch);        	\
										\
  rgba[0] = rgbvec.x;								\
  rgba[1] = rgbvec.y;								\
  rgba[2] = rgbvec.z;								\
}

#define GETOPACITY(offset)							\
{										\
  rgba[3] = OPACITY(offset);							\
}

#define	SENDLITCOLOR(transp)  						      	\
{ 									      	\
  lmcolor(LMC_AD); 							      	\
  if (transp)									\
      c4f(rgba);								\
  else 										\
      c3f(rgba);								\
}

#define	SENDCOLOR(transp)  						      	\
{ 									      	\
  lmcolor(LMC_COLOR); 							\
  if (transp)									\
      c4f(rgba);								\
  else 										\
      c3f(rgba);								\
}

#define PERFIELD(lit, transp)							\
{ 										\
  int _lit = lit && xf->normalsDep != dep_none;					\
  int sendc = (xf->colorsDep == dep_field &&					\
		(!transp || xf->opacitiesDep == dep_field));			\
										\
  if (xf->colorsDep == dep_field)						\
      GETCOLOR(0);								\
										\
  if (transp && xf->opacitiesDep == dep_field)					\
      GETOPACITY(0);								\
										\
  if(_lit) {									\
      SENDSPECCOLOR(); 								\
      lmcolor(LMC_AD); 								\
      if(xf->normalsDep == dep_field) 						\
        SENDNORMAL(0); 								\
      if (sendc)								\
	  SENDLITCOLOR(transp);							\
  } else {									\
      lmcolor(LMC_COLOR); 							\
      if (sendc)								\
	  SENDCOLOR(transp);							\
  }										\
										\
  if (doesPattern)								\
      if ((xf->opacitiesDep != dep_none) && (OPACITY(0) < 0.75))		\
	  setpattern(PATTERN_INDEX);						\
}


#define ENDPERFIELD() 								\
    if (doesPattern) setpattern(0);


/*
 * For cubes each face of the cube is drawn as a quad with 
 * face = [4..9] and posPerCon = 4.
 * For Tetras, triangles with face=[0..3] and posPerCon = 3
 */
static int faceList[][4] = {
  {0,1,2,0},	/* Tetra front */	/* <- also all triangles */
  {1,3,2,0},	/* Tetra right */
  {0,2,3,0},	/* Tetra left */
  {0,1,3,0},	/* Tetra bottom */

  {2,3,1,0},	/* Cube front */ 	/* <- also all quads */
  {0,1,5,4},	/* Cube bottom */
  {0,4,6,2},	/* Cube left */
  {1,5,7,3},	/* Cube right */
  {3,7,6,2},	/* Cube top */
  {4,5,7,6},	/* Cube back */
};
#define TRANSLATE(new,old,face) \
{  \
    int i;  \
    for(i=xf->posPerConn-1;i>=0;i--)  { \
      new[i] = old[faceList[face][i]]; \
    } \
}

#define GET_CONNECTION(ctIndex)	\
{					\
  static int	cscratch[8];		\
  static int	*connection;		\
                                        \
  connection = (int*)DXGetArrayEntry(xf->connections,ctIndex,cscratch);	\
  TRANSLATE(translation,connection,face); \
}

static int doesTrans, doesPattern;

static Error
dots (xfieldP xf, enum approxE approx, int skip)
{
  static float	fscratch[3];
  static int	iscratch;
  int		p,i;
  helperFunc	helper;
  float 	rgba[4];

  PERFIELD(0, 0);

  for(p=0;p<xf->npositions;) {
    bgnpoint();
    for(i=0;p<xf->npositions && i<256;) {
      if(! xf->invPositions || ! DXIsElementInvalidSequential(xf->invPositions,
							      p)) {
        SENDCOLOR(p);

	SENDPOSITION(p);
	i++;
	p+= skip;
      } else {
	p++;
      }
    }
    endpoint();
  }

  EXIT(("OK"));
  return OK;
}

static Error
translucentPoints (xfieldP xf, helperFunc helper,
	SortD list, int n, int face,
	enum approxE approx, int skip)
{
  static int	translation[8];
  static float	fscratch[3];
  static int	iscratch;
  int		i, c, c1;
  dependencyT   odep = xf->opacitiesDep;
  dependencyT   cdep = xf->colorsDep;
  float		opacity;
  float 	rgba[4];

  PERFIELD(0, 1);

  if (!n)
      return OK;
      
  bgnpoint();
  for (c = 0; c < n; c ++)
  {
    if (xf->connections)
        c1 = *(int*)DXGetArrayEntry(xf->connections,
			list[c].poly,(Pointer)iscratch);
    else
        c1 = list[c].poly;
    
    if (odep == dep_connections)
	GETOPACITY(list[c].poly);
    
    if (cdep == dep_connections)
	GETCOLOR(list[c].poly);

    (*helper)(xf,1,list[c].poly,&c1,rgba);
  }
  endpoint();

  ENDPERFIELD();

  return OK;
}

static Error
points (xfieldP xf, helperFunc helper,
	int firstConnection, int lastConnection, int face,
	enum approxE approx, int skip)
{
  static int	translation[8];
  static float	fscratch[3];
  static int	iscratch;
  int		c, i=0, translu = 0;
  dependencyT   odep = xf->opacitiesDep;
  dependencyT   cdep = xf->colorsDep;
  float		opacity;
  float 	rgba[4];

  ENTRY(("points(0x%x, 0x%x, %d, %d, %d, %d, %d)",
	xf, helper, firstConnection, lastConnection, face, approx, skip));

  PERFIELD(0, 0);

  if (doesTrans)
  {
      switch(odep = xf->opacitiesDep)
      {
         case dep_none:
	     translu = 0;
	     break;
         case dep_field:
	     translu = OPACITY(0) < 1.0f;
             break;
         default:
	     break;
      }

      if (! translu)
      {
	  for(c=firstConnection;c<lastConnection;c+=skip)
	  {
	    if(!xf->invCntns || ! DXIsElementInvalid(xf->invCntns,c))
	    {
		int c1;

		if (xf->connections)
		    c1 = *(int*)DXGetArrayEntry(xf->connections, c, (Pointer)iscratch);
		else
		    c1 = c;

		if(xf->invPositions && DXIsElementInvalid(xf->invPositions, c1))
		    break;

		if (odep == dep_connections)
		    translu |= OPACITY(c) < 1.0f;
		else if (odep == dep_positions)
		    translu |= OPACITY(c1) < 1.0f;

		if (! translu)
		{
		    if (i++ == 0)
		        bgnpoint();
		    
		    if (cdep == dep_connections)
			GETCOLOR(c1);

		    (*helper)(xf,1,c,&c1,rgba);
		}
	    }
	  }

	  if (i)
	    endpoint();
      }
  }
  else
  {
      for(c=firstConnection;c<lastConnection;c+=skip)
      {
	if(!xf->invCntns || ! DXIsElementInvalid(xf->invCntns,c))
	{
	    int c1;

	    if (xf->connections)
		c1 = *(int*)DXGetArrayEntry(xf->connections,
					c, (Pointer)iscratch);
	    else
		c1 = c;

	    if(xf->invPositions && DXIsElementInvalid(xf->invPositions, c1))
		break;

	    if (i++ == 0)
		bgnpoint();
	    
	    if (cdep == dep_connections)
		GETCOLOR(c1);

	    (*helper)(xf,xf->posPerConn,c,translation,rgba);
	}
      }

      if (i)
	    endpoint();
  }

  ENDPERFIELD();

  EXIT(("OK"));
  return OK;

error:
  return ERROR;
}


static int noLines = 0;

static Error translucentLines (xfieldP xf, helperFunc helper,
                                 SortD list, int n, int face,
				enum approxE approx, int skip)
{
  static int	translation[8];
  static float	fscratch[3];
  static int	iscratch;
  int		c;
  dependencyT   odep = xf->opacitiesDep;
  dependencyT   cdep = xf->colorsDep;
  float		opacity;
  float 	rgba[4];

  if (noLines)
      return OK;

  PERFIELD(0, 1);

  for(c = 0; c < n; c++)
  {
    if(!xf->invCntns || ! DXIsElementInvalid(xf->invCntns,c))
    {
	bgnline();
	GET_CONNECTION(list[c].poly);

	if (odep == dep_connections)
	    GETOPACITY(list[c].poly);

	if (cdep == dep_connections)
	    GETCOLOR(list[c].poly);

	(*helper)(xf,xf->posPerConn,list[c].poly,translation,rgba);
	endline();
    }
  }

  ENDPERFIELD();

  return OK;
}

static Error
lines (xfieldP xf, helperFunc helper,
       int firstConnection, int lastConnection,int face,
       enum approxE approx, int skip)
{
  static int	translation[8];
  static float	fscratch[3];
  static int	iscratch;
  int		c, translu = 0;
  int		doliting = _dxf_xfieldAttributes(xf)->shade ? 1 : 0;
  dependencyT   odep = xf->opacitiesDep;
  dependencyT   cdep = xf->colorsDep;
  float		opacity;
  float 	rgba[4];

  if (noLines)
      return OK;

  ENTRY(("lines(0x%x, 0x%x, %d, %d, %d, %d, %d)",
	 xf, helper, firstConnection, lastConnection, face, approx, skip));

  if (approx == approx_box) {
    EXIT(("calling bbox"));
    return bbox(xf);
  }

  PERFIELD(doliting, 0);

  if (doesTrans)
  {
      switch(odep = xf->opacitiesDep)
      {
         case dep_none:
	     translu = 0;
	     break;
         case dep_field:
	     translu = OPACITY(0) < 1.0f;
             break;
         default:
	     break;
      }

      for(c=firstConnection;c<lastConnection;c+=skip)
      {
	if(!xf->invCntns || ! DXIsElementInvalid(xf->invCntns,c))
	{
	  GET_CONNECTION(c);
	  if (odep == dep_connections)
	      translu |= OPACITY(c) < 1.0f;
	  else if (odep == dep_positions)
	      translu |= (OPACITY(translation[0]) < 1.0f) ||
				(OPACITY(translation[1]) < 1.0f);

	  if (! translu)
	  {
	    if (cdep == dep_connections)
		GETCOLOR(c);

	    bgnline();
	    (*helper)(xf,xf->posPerConn,c,translation,rgba);
            endline();
	  }
	}
      }
  }
  else
  {
      for(c=firstConnection;c<lastConnection;c+=skip)
      {
	if(!xf->invCntns || ! DXIsElementInvalid(xf->invCntns,c))
	{
          bgnline();
	  GET_CONNECTION(c);
	  (*helper)(xf,xf->posPerConn,c,translation,rgba);
          endline();
	}
      }
  }
  for(c=firstConnection;c<lastConnection;c+=skip) {
    if(!xf->invCntns || ! DXIsElementInvalid(xf->invCntns,c)) {
      GET_CONNECTION(c);
      (*helper)(xf,xf->posPerConn,c,translation,rgba);
    }
  }

  ENDPERFIELD();

  EXIT((""));
  return OK;

error:  
  return ERROR;
}

#define MAXGLPLINEVERT 100

static Error polylines (xfieldP xf, helperFunc helper,
		    enum approxE approx, int skip)
{
    static float fscratch[3];
    static int	 iscratch;
    int		 c, i;
    int	         start, end, knt, max, thisknt;
    int		 doliting = _dxf_xfieldAttributes(xf)->shade ? 1 : 0;
    dependencyT  cdep = xf->colorsDep;
    float	 opacity;
    float	 rgba[4];

    if (approx == approx_box)
    {
	EXIT(("calling bbox"));
	return bbox(xf);
    }

    PERFIELD(doliting, 0);

    if (skip > 1)
    {
	for(c = 0; c < xf->npolylines; c ++)
	{
	    if(!xf->invCntns || ! DXIsElementInvalid(xf->invCntns,c))
	    {
		start = xf->polylines[c];
		end   = (c == xf->npolylines-1) ? xf->nedges :
						    xf->polylines[c+1];
		knt = (end - start) - 1;

		if (cdep == dep_polylines)
		    GETCOLOR(c);

		bgnline();
		while (knt > 0)
		{
		    thisknt = (knt > max) ? max : knt;
			
		    (*helper)(xf, 2, c, xf->edges+start,rgba);

		    start += skip;
		    knt -= skip;
		}
		endline();

	    }
	}
    }
    else
    {

	max = MAXGLPLINEVERT;

	for(c = 0; c < xf->npolylines; c ++)
	{
	    if(!xf->invCntns || ! DXIsElementInvalid(xf->invCntns,c))
	    {
		start = xf->polylines[c];
		end   = (c == xf->npolylines-1) ? xf->nedges :
						    xf->polylines[c+1];
		knt = end - start;

		if (cdep == dep_polylines)
		    GETCOLOR(c);

		bgnline();
		while (knt)
		{
		    thisknt = (knt > max) ? max : knt;

		    (*helper)(xf, thisknt, c, xf->edges+start,rgba);

		    start += (thisknt-1);
		    knt -= (thisknt-1);
		    if(thisknt == 1)
		       knt = 0;
		}
		endline();
	    }
	}
    }

    ENDPERFIELD();

    EXIT((""));
    return OK;
}

static Error
closedlines (xfieldP xf, helperFunc helper,
       int firstConnection, int lastConnection,int face,
       enum approxE approx, int skip)
{
  static int	translation[8];
  static float	fscratch[3];
  static int	iscratch;
  int		c;
  dependencyT   cdep = xf->colorsDep;
  float		opacity;
  float 	rgba[4];

  ENTRY(("closedlines(0x%x, 0x%x, %d, %d, %d, %d, %d)",
	 xf, helper, firstConnection, lastConnection, face, approx, skip));

  if (approx == approx_box) {
    EXIT(("calling bbox"));
    return bbox(xf);
  }

  PERFIELD(0, 0);

#ifdef sgi

  if(xf->texture)    /*  (:Q=   */
  {
     static float Holder[3] = { 0.5f, 0.7f, 1.0f };
     c3f(Holder);
  }

#endif

  for(c=firstConnection;c<lastConnection;c+=skip) {
    if(!xf->invCntns || ! DXIsElementInvalid(xf->invCntns,c)) {

      GET_CONNECTION(c);

      bgnclosedline();

      if (cdep == dep_connections)
	  GETCOLOR(c);

      (*helper)(xf,xf->posPerConn,c,translation,rgba);

      endclosedline();
    }
  }

  ENDPERFIELD();

  EXIT(("OK"));
  return OK;
}


static Error
polygons (xfieldP xf, helperFunc helper,
	  int firstConnection, int lastConnection, int face,
	  enum approxE approx, int skip)
{
  static int	translation[8];
  static float	fscratch[3];
  static int	iscratch;
  int		c;
  int		translu = 0;
  dependencyT   odep = xf->opacitiesDep;
  dependencyT   cdep = xf->colorsDep;
  float		opacity;
  float 	rgba[4];

  ENTRY(("polygons(0x%x, 0x%x, %d, %d, %d, %d, %d)",
	 xf, helper, firstConnection, lastConnection, face, approx, skip));

  switch(approx) {
  case approx_dots:
    EXIT(("calling dots"));
    return dots(xf,approx,skip);
    break;
  case approx_box:
    EXIT(("calling bbox"));
    return bbox(xf);
    break;
  case approx_lines:
    helper = getHelper(xf->colorsDep,dep_none,dep_none,NULL);
    EXIT(("calling closedlines"));
    return closedlines(xf,helper,0,xf->nconnections,face,approx,skip);
    break;
  }


  if (doesTrans)
  {
     switch(odep)
     {
	case dep_none:
	    translu = 0;
	    break;
	case dep_field:
	    translu = OPACITY(0) < 1.0f;
	    break;
	default:
	    break;
     }

     for(c=firstConnection;c<lastConnection;c+=skip)
     {
       if(!xf->invCntns || ! DXIsElementInvalid(xf->invCntns,c))
       {

	   GET_CONNECTION(c);

	   if (odep == dep_connections)
	   {
		translu = OPACITY(c) < 1.0f;
	   }
	   else if (odep == dep_positions)
	   {
	      int i;
	      for (i = 0; !translu && i < xf->posPerConn; i++)
		  if (OPACITY(translation[i]) < 1.0f)
		      translu = 1;
	   }

	   if (! translu)
	   {
	      bgnpolygon();

	      PERFIELD(1, 0);

	      if (cdep == dep_connections)
		  GETCOLOR(c);

	      (*helper)(xf,xf->posPerConn,c,translation,rgba);
	      endpolygon();
	   }
	}
     }
  }
  else
  {
     PERFIELD(1, 0);

     for(c=firstConnection;c<lastConnection;c+=skip)
     {
       if(!xf->invCntns || ! DXIsElementInvalid(xf->invCntns,c))
       {
	   GET_CONNECTION(c);

	   if (cdep == dep_connections)
	      GETCOLOR(c);

	   bgnpolygon();
	   (*helper)(xf,xf->posPerConn,c,translation,rgba);
	   endpolygon();
       }
     }
  }

  ENDPERFIELD();

  EXIT(("OK"));
  return OK;

error:
  return ERROR;
}

static Error
translucentPolygons (xfieldP xf, helperFunc helper,
	  SortD list, int n, int face,
	  enum approxE approx, int skip)
{
  static int	translation[8];
  static float	fscratch[3];
  static int	iscratch;
  int		c;
  int		translu = 0;
  dependencyT   odep = xf->opacitiesDep;
  dependencyT   cdep = xf->colorsDep;
  float		rgba[4];
  float		opacity;

  PERFIELD(1, 1);

  for(c = 0; c < n; c ++)
  {
       if(!xf->invCntns || ! DXIsElementInvalid(xf->invCntns,c))
       {
	   GET_CONNECTION(list[c].poly);
	   bgnpolygon();
	   (*helper)(xf,xf->posPerConn,list[c].poly,translation,rgba);
	   endpolygon();
       }
  }

  ENDPERFIELD();

  EXIT(("OK"));
  return OK;

error:
  return ERROR;
}

#define NOTUSED	0

static Error
tmeshlines (xfieldP xf, helperFunc helper, enum approxE approx, int skip);

static Error
tmesh (xfieldP xf, helperFunc helper, enum approxE approx, int skip)
{
  static int	*translation,*strip;
  static float	fscratch[3];
  static int	iscratch;
  int		count;
  int		meshI,i;
  int		skipDelta;
  InvalidComponentHandle tmpic,tmpip;
  struct  {
    int start;
    int count;
  }  *meshes;
  dependencyT   odep = xf->opacitiesDep;
  dependencyT   cdep = xf->colorsDep;
  float		opacity;
  float 	rgba[4];
 
  ENTRY(("tmesh(0x%x, 0x%x, %d, %d)", xf, helper, approx, skip));

  tmpic = xf->invCntns;
  tmpip = xf->invPositions;
  xf->invCntns = NULL;
  xf->invPositions = NULL;

  switch(approx) {
  case approx_dots:
    if (tmpic || tmpip) {
      helper = getHelper(xf->colorsDep,dep_none,dep_none,NULL);
      points (xf, helper,0,xf->nconnections,0,approx,skip);
      goto done;
    } else {
      dots(xf,approx,skip);
      goto done;
    }
    break;
  case approx_box:
    bbox(xf);
    goto done;
    break;
  case approx_lines:
    helper = getHelper(xf->colorsDep,dep_none,dep_none,NULL);
    tmeshlines(xf, helper, approx, skip);
    goto done;
    break;
  }

  PERFIELD(1, 0);

#ifdef sgi

  if(xf->texture)
     glStartTexture(xf);

#endif

  /* NOTE:
   * The code below is optimized for tmesh. It depends on two 
   * qualities of our tmesh generator.
   * 1) tmeshes are NOT generated for Npc or Cpc
   * 2) tmeshes create a regular array in xf->connections_array;
   */
  translation = DXGetArrayData(xf->connections_array);
  if(!(meshes = DXGetArrayData(xf->meshes))) goto error;
  /* Not Skipping */
  if(skip <= 1) {
    for(meshI=0;meshI<xf->nmeshes;meshI++) {


      bgntmesh();

      PERFIELD(1, 0);

#if defined(DXD_HW_TMESH_SWAP_OK)
      {
	int remainder = meshes[meshI].count;
	int *startPtr,*endPtr;
	
	startPtr = endPtr = &translation[meshes[meshI].start];
	{
	  for(i=0;i<remainder;i++) {
	    if (*(endPtr++) < 0) {
	      (*helper)(xf,i,NOTUSED,startPtr,rgba);
	      swaptmesh();
	      remainder -= (i + 1);
	      i = -1;	/* allow for loop increment */
	      startPtr = endPtr;
	    }
	  }
	}  while (i<remainder);
	if(remainder) (*helper)(xf,remainder,NOTUSED,startPtr,rgba);
      }
#else
      (*helper)(xf,meshes[meshI].count,NOTUSED,
		&translation[meshes[meshI].start],rgba);
#endif
      endtmesh();
    }
  } else {  /* skipping */

    PERFIELD(1, 0);

    skipDelta = 0;
    for(meshI=0;meshI<xf->nmeshes;meshI++) {

      strip = &translation[meshes[meshI].start];

      for(count=skipDelta;
	  count < meshes[meshI].count-2;
	  count += skipDelta) {
	bgnpolygon();

#if defined(DXD_HW_TMESH_SWAP_OK)
	{
	  int	tri[3];
	  int	i,j;

	  for (i=0,j=0;i<3;i++,j++) {
	    /* if we have a swap in the triangle */
	    if (strip[count+i] < 0)
	      {
	      if(i==1)	/* swap in middle of tri requires special treatment */
		tri[0] = strip[count-1];
	      j++;
	      }
	    tri[i] = strip[count+j];
	  }
	  (*helper)(xf,3,NOTUSED,tri,rgba);
	}
#else
	(*helper)(xf,3,NOTUSED,&strip[count],rgba);
#endif
	endpolygon();
	skipDelta = skip;
      }
      skipDelta = count - (meshes[meshI].count-2);
    }
  }

  ENDPERFIELD();

 done:

#ifdef sgi

  if(xf->texture)
     glEndTexture();

#endif

  xf->invCntns = tmpic;
  xf->invPositions = tmpip;

  EXIT(("OK"));
  return OK;

 error:
/*
XXX 
print error message
*/
  ENDPERFIELD();

  xf->invCntns = tmpic;
  xf->invPositions = tmpip;

  EXIT(("ERROR"));
  return ERROR;
}

static Error
tmeshlines (xfieldP xf, helperFunc helper, enum approxE approx, int skip)
{
  static int	*translation,*strip;
  static int	edge[MaxTstripSize+1];
  static float	fscratch[3];
  static int	iscratch;
  int		count;
  int		meshI;
  int		edgeI;
  int		skipDelta;
  dependencyT	odep;
  float 	opacity;	
  struct  {
    int start;
    int count;
  }  *meshes;
  float		rgba[4];

  ENTRY(("tmeshlines(0x%x, 0x%x, %d, %d)", xf, helper, approx, skip));

  /* NOTE:
   * The code below is optimized for tmesh. It depends on two 
   * qualities of our tmesh generator.
   * 1) tmeshes are NOT generated for Npc or Cpc
   * 2) tmeshes create a regular array in xf->connections_array;
   */
  translation = DXGetArrayData(xf->connections_array);

  PERFIELD(0, 0);

#ifdef sgi

  if(xf->texture)    /*  (:Q=   */
  { 
     static float Holder[3] = { 0.5f, 0.7f, 1.0f };
     c3f(Holder);
  }

#endif

  if(!(meshes = DXGetArrayData(xf->meshes))) goto error;

  if(skip <= 1) {	/* NOT skipping */
    for(meshI=0;meshI<xf->nmeshes;meshI++) {

      strip = &translation[meshes[meshI].start];

      /* Draw zigzap */
#if defined(DXD_HW_TMESH_SWAP_OK)
      for(edgeI=0,count=0;
	   count < meshes[meshI].count;
	    count++, edgeI++) 
	{
	  if(strip[count] < 0)	/* for swap */
	    edge[edgeI] = edge[edgeI-2];
	  else
	    edge[edgeI] = strip[count];
	}
      if(edgeI > 1) {
	bgnline();
	(*helper)(xf,edgeI,NOTUSED,edge,rgba);
	endline();
      }
#else
      bgnline();
      (*helper)(xf, meshes[meshI].count, NOTUSED, strip,rgba);
      endline();
#endif
      /* close boundary of zigzags with even indices */
      for(edgeI=0,count=0;
	   count < meshes[meshI].count;
	    count+=2) 
	{
	  if(strip[count] < 0) continue;	/* for swap */
	  edge[edgeI++] = strip[count];
	}
      if(edgeI > 1){
	bgnline();
	(*helper)(xf,edgeI,NOTUSED,edge,rgba);
	endline();
      }

      /* close boundary of zigzags with odd indices */
      for(edgeI=0,count=1;
	   count < meshes[meshI].count;
	    count+=2) 
	{
	  if(strip[count] < 0) continue;	/* for swap */
	  edge[edgeI++] = strip[count];
	}
      if(edgeI > 1) {
	bgnline();
	(*helper)(xf,edgeI,NOTUSED,edge,rgba);
	endline();
      }
    }
  } else { /* skipping */
    skipDelta = 0;
    for(meshI=0;meshI<xf->nmeshes;meshI++) {

      strip = &translation[meshes[meshI].start];

      for(count=skipDelta;
	  count < meshes[meshI].count-2;
	  count += skipDelta) {
	bgnclosedline();
	
#if defined(DXD_HW_TMESH_SWAP_OK)
	{
	  int	tri[3];
	  int	i,j;

	  for (i=0,j=0;i<3;i++,j++) {
	    /* if we have a swap in the triangle */
	    if (strip[count+i] < 0)
	      {
		if(i==1)/* swap in middle of tri requires special treatment */
		  tri[0] = strip[count-1];
		j++;
	      }
	    tri[i] = strip[count+j];
	  }
	  (*helper)(xf,3,NOTUSED,tri,rgba);
	}
#else
	(*helper)(xf,3,NOTUSED,&strip[count],rgba);
#endif
	endclosedline();
	skipDelta = skip;
      }
      skipDelta = count - (meshes[meshI].count-2);
    }
  }

  ENDPERFIELD();
  EXIT(("OK"));
  return OK;

 error:
/*
XXX 
print error message
*/
  ENDPERFIELD();
  EXIT(("ERROR"));
  return ERROR;
}


static Error
plines (xfieldP xf, helperFunc helper, enum approxE approx, int skip)
{
  static int	*translation,*strip;
  static int	edge[MaxTstripSize+1];
  static float	fscratch[3];
  static int	iscratch;
  int		count;
  int		start;
  int		step;
  int		meshI;
  int		edgeI;
  int		skipDelta;
  int		doliting = _dxf_xfieldAttributes(xf)->shade ? 1 : 0;
  dependencyT	odep;
  float 	opacity;	
  struct  {
    int start;
    int count;
  }  *meshes;
  float		rgba[4];

  ENTRY(("plines(0x%x, 0x%x, %d, %d)", xf, helper, approx, skip));
  if (approx == approx_box) {
    EXIT(("calling bbox"));
    return bbox(xf);
  }
  translation = DXGetArrayData(xf->connections_array);

  PERFIELD(doliting, 0);

  if(!(meshes = DXGetArrayData(xf->meshes))) goto error;

  if(skip <= 1) {	/* NOT skipping */
    for(meshI=0;meshI<xf->nmeshes;meshI++) {
#if 0
      count = meshes[meshI].count;
      start = meshes[meshI].start;
      for(step = 0; step < count; step += MAXGLPLINEVERT) {
	bgnline();
	(*helper)(xf, 
		  step + MAXGLPLINEVERT < count ?
		     MAXGLPLINEVERT :
		     count - step, 
		  NOTUSED, &translation[step+start],rgba);
	endline();
      }
#else
	bgnline();
	(*helper)(xf, meshes[meshI].count, NOTUSED, 
		  &translation[meshes[meshI].start],rgba);
	endline();
#endif
    }
  } else { /* skipping */
    skipDelta = 0;
    for(meshI=0;meshI<xf->nmeshes;meshI++) {

      strip = &translation[meshes[meshI].start];

      for(count=skipDelta;
	  count < meshes[meshI].count-1;
	  count += skipDelta) {
	bgnline();
	(*helper)(xf,2,NOTUSED,&strip[count],rgba);
	skipDelta = skip;
	endline();
      }
      skipDelta = count - (meshes[meshI].count-1);
    }
  }
  ENDPERFIELD();
  EXIT(("OK"));
  return OK;

 error:
/*
XXX 
print error message
*/
  ENDPERFIELD();
  EXIT(("ERROR"));
  return ERROR;
}


static Error
bbox (xfieldP xf)
{
  static float	fscratch[3];
  static int	iscratch;
  int		p,i;
  static float	yellow[] = {1.0, 1.0, 0.0};
  dependencyT	odep;
  float 	opacity;	
  float		rgba[4];

  ENTRY(("bbox(0x%x)", xf));

  PERFIELD(0, 0);

  lmcolor(LMC_COLOR); 
  c3f((float*)&yellow[0]);
  bgnline();
  v3f((float*)&xf->box[0]);
  v3f((float*)&xf->box[1]);
  v3f((float*)&xf->box[3]);
  v3f((float*)&xf->box[2]);
  v3f((float*)&xf->box[0]);
  v3f((float*)&xf->box[4]);
  v3f((float*)&xf->box[5]);
  v3f((float*)&xf->box[7]);
  v3f((float*)&xf->box[6]);
  v3f((float*)&xf->box[4]);
  endline();
  bgnline();
  v3f((float*)&xf->box[2]);
  v3f((float*)&xf->box[6]);
  endline();
  bgnline();
  v3f((float*)&xf->box[3]);
  v3f((float*)&xf->box[7]);
  endline();
  bgnline();
  v3f((float*)&xf->box[1]);
  v3f((float*)&xf->box[5]);
  endline();

  EXIT(("OK"));
  return OK;
}

#ifdef sgi

static void
TNnone (xfieldP xf, int posPerConn, int ctIndex, int *translation)
{
  static  float fscratch[3];
  static  float uvscratch[2];
  static  int   iscratch;
  static  int   p;
  char c = 0xff;
  RGBcolor(c,c,c);
  for(p=0;p<posPerConn;p++)  {
    SENDUV(translation[p]);
    SENDPOSITION(translation[p]);
  }

  EXIT((""));
}


static void
TNpositions (xfieldP xf, int posPerConn, int ctIndex, int *translation)
{
  static float  fscratch[3];
  static float  uvscratch[2];
  static int    iscratch;
  static int    p;
  char c = 0xff;

  ENTRY(("TNpositions(0x%x, %d, %d, 0x%x)",
         xf, posPerConn, ctIndex, translation));

  RGBcolor(c,c,c);
  for(p=0;p<posPerConn;p++)  {
    int q = translation[p];
    SENDUV(q);
    SENDNORMAL(q);
    SENDPOSITION(q);
  }

  EXIT((""));
}

#endif


/*
 * Helper functions:
 *     colors, normals and opacities may be 
 *     each may be per vertex, per element or per field or none.
 *     code is v, e, f, n
 *
 *		colors
 *	       /normals
 *	      //opacities
 *	     ///
 *   helper_xxx
 *
 * The following program generates the helper table and
 * the helper routines themselves.  If you need to recreate
 * it, cut out the code and run it, sending stdout to "helper.include"
 */

#include "helper.include"

#define DEP2INDEX(dep, index)			\
{						\
  switch(dep)					\
  {						\
      case dep_positions:   index = 0; break;	\
      case dep_connections: index = 1; break;	\
      case dep_field:       index = 2; break;	\
      case dep_none:        index = 3; break;	\
  }						\
}

static helperFunc
getHelper(dependencyT colorsDep, 
	  dependencyT normalsDep, 
	  dependencyT opacitiesDep,
	  int texture)
{
  int		index, c_index, n_index, o_index;
  helperFunc	ret;

  ENTRY(("getHelper(%d, %d, %d)", colorsDep, normalsDep, opacitiesDep));

#ifdef sgi

  if(texture)
  {
#if 0
     if (normalsDep == dep_connections)
	return TNconnections;
     else
#endif
     if(normalsDep == dep_positions)
	return TNpositions;
     else
	return TNnone;
  }

#endif

  DEP2INDEX(colorsDep,    c_index);
  DEP2INDEX(normalsDep,   n_index);
  DEP2INDEX(opacitiesDep, o_index);

  index = ((c_index*4) + n_index)*4 + o_index;

  ret = helperTable[index];

  EXIT(("ret = 0x%x", ret));
  return ret;
}

static void _getLightAttrs(tdmPortHandleP phP, dxObject f,
			   float *k_ambi, float *k_diff,
			   float *k_spec, float *k_shin);

static Error parameters(dxObject o, attributeP new, attributeP old);

static Error
_drawPrimitives(tdmPortHandleP portHandle, xfieldP xf, 
		  enum approxE approx, int density)
{
  helperFunc	helper;
  
  ENTRY(("_drawPrimitives(0x%x, 0x%x, %d, %d)",
	 portHandle, xf, approx, density));

  TIMER("> drawPrimitives");

  if(xf->invCntns)
    if(! DXInitGetNextInvalidElementIndex(xf->invCntns))
      goto error;

  finish(); /* Flush Geometry Pipeline */

  PHASE_START("Primitives");

  switch (xf->connectionType) {
  case ct_none:
    TIMER("> points");
    helper = getHelper(xf->colorsDep,dep_none,dep_none,NULL);
    points(xf,helper,0,xf->npositions,0,approx,density);
    TIMER("< points");
    break;
  case ct_lines:
    if(xf->attributes.linewidth > 0)
       linewidth((int)xf->attributes.linewidth);

    if(xf->attributes.aalines) 
        linesmooth(SML_ON);

    helper = getHelper(xf->colorsDep,dep_none,dep_none,NULL);
    TIMER("> lines");
    lines(xf,helper,0,xf->nconnections,0,approx,density);
    TIMER("< lines");
    linesmooth(SML_OFF);
    break;
  case ct_polylines:
    if(xf->attributes.linewidth > 0)
       linewidth((int)xf->attributes.linewidth);

    if(xf->attributes.aalines) 
        linesmooth(SML_ON);

    helper = getHelper(xf->colorsDep,dep_none,dep_none,NULL);
    TIMER("> plines");
    polylines(xf,helper,approx,density);
    TIMER("< plines");
    linesmooth(SML_OFF);
    break;
  case ct_pline:
    if(xf->attributes.linewidth > 0)
       linewidth((int)xf->attributes.linewidth);

    if(xf->attributes.aalines) 
        linesmooth(SML_ON);

    helper = getHelper(xf->colorsDep,dep_none,dep_none,NULL);
    TIMER("> plines");
    plines(xf,helper,approx,density);
    TIMER("< plines");
    linesmooth(SML_OFF);
    break;
  case ct_triangles: 
    helper = getHelper(xf->colorsDep,xf->normalsDep,dep_none,
		       (xf->texture != NULL) && (approx == approx_none));
    TIMER("> triangles");
    polygons(xf,helper,0,xf->nconnections,0,approx,density);
    TIMER("< triangles");
    break;
  case ct_quads:
    helper = getHelper(xf->colorsDep,xf->normalsDep,dep_none,
		       (xf->texture != NULL) && (approx == approx_none));
    TIMER("> quads");
    polygons(xf,helper,0,xf->nconnections,4,approx,density);
    TIMER("< quads");
    break;
/* 
 * XXX NOTE:
 * The volume code below is very inefficient for screen door rendering.
 * It draws a vast number of completely obscure faces. This is to make
 * sure that all the boundary faces are drawn. It would be far better
 * to do a show boundary and store the result of that in the xfield.
 * Next pass.
 */
  case ct_tetrahedra:
    helper = getHelper(xf->colorsDep,xf->normalsDep,dep_none,
		       (xf->texture != NULL) && (approx == approx_none));
    TIMER("> tetras");
    polygons(xf,helper,0,xf->nconnections,0,approx,density);
    polygons(xf,helper,0,xf->nconnections,1,approx,density);
    polygons(xf,helper,0,xf->nconnections,2,approx,density);
    polygons(xf,helper,0,xf->nconnections,3,approx,density);
    TIMER("< tetras");
    break;
  case ct_cubes:
    helper = getHelper(xf->colorsDep,xf->normalsDep,dep_none,
		       (xf->texture != NULL) && (approx == approx_none));
    TIMER("> cubes");
    polygons(xf,helper,0,xf->nconnections,4,approx,density);
    polygons(xf,helper,0,xf->nconnections,5,approx,density);
    polygons(xf,helper,0,xf->nconnections,6,approx,density);
    polygons(xf,helper,0,xf->nconnections,7,approx,density);
    polygons(xf,helper,0,xf->nconnections,8,approx,density);
    polygons(xf,helper,0,xf->nconnections,9,approx,density);
    TIMER("< cubes");
    break;
  case ct_tmesh:
    helper = getHelper(xf->colorsDep,xf->normalsDep,dep_none,
		       (xf->texture != NULL) && (approx == approx_none));
    TIMER("> tmesh");
    tmesh(xf,helper,approx,density);
    TIMER("< tmesh");
    break;
  case ct_qmesh:
    helper = getHelper(xf->colorsDep,xf->normalsDep,dep_none,
		       (xf->texture != NULL) && (approx == approx_none));
    TIMER("> qmesh");
    tmesh(xf,helper,approx,density);
    TIMER("< qmesh");
    break;
#if 0
#ifdef DXD_HW_TEXTURE_MAPPING
  case ct_flatGrid:
    if((approx == approx_none) &&
       (density == 1)) {
      TIMER("> texture");
      if(!hwTextureDraw(portHandle, xf))
	goto error;
      TIMER("< texture");
      break;
    } else {
      helper = getHelper(xf->colorsDep,xf->normalsDep,dep_none,
			 xf->texture != NULL);
      TIMER("> quads");
      polygons(xf,helper,0,xf->nconnections,4,approx,density);
      TIMER("< quads");
      break;
    }
	  
#endif
#endif
  default:
    DXErrorGoto (ERROR_INTERNAL, "invalid xfield connections type") ;
    break;
  }
  PHASE_END("Primitives");
  
 done:
  TIMER("< drawPrimitives");
  EXIT(("OK"));
  return OK;

 error:
  TIMER("< drawPrimitives");
  EXIT(("ERROR"));
  return ERROR;
}

Error
_dxf_DrawOpaque (tdmPortHandleP portHandle, xfieldP xf,	
		 RGBColor ambientColor, int buttonUp)
{
  int		density;
  enum approxE	approx;
  dxObject Obj;
  int      DisplayList;
  DEFPORT(portHandle);

  ENTRY(("_dxf_DrawOpaque(0x%x, 0x%x, 0x%x, %d)",
	 portHandle, xf, &ambientColor, buttonUp));
  
  TIMER("> DrawOpaque");
  
  PHASE_START("DrawOpaque");

  if (_dxf_isFlagsSet(_dxf_SERVICES_FLAGS(), SF_DOES_TRANS))
  {
      if (getgdesc(GD_BLEND))
      {
	  doesTrans   = 1;
	  doesPattern = 0;
      }
      else
      {
	  doesTrans   = 0;
	  doesPattern = 1;
      }
  }
  else
  {
      doesTrans = 0;
      doesPattern = 0;
  }

  if(xf->deletePrivate == NULL)
     xf->deletePrivate = _deleteGLObject;

  if(xf->normalsDep != dep_none &&
     (buttonUp &&xf->attributes.buttonUp.approx == approx_none) ||
     (!buttonUp &&xf->attributes.buttonDown.approx == approx_none)) {

    _dxf_SET_GLOBAL_LIGHT_ATTRIBUTES(PORT_CTX ,1);

    _dxf_SET_MATERIAL_SPECULAR (PORT_CTX, 1.0 /*R*/, 1.0 /*G*/, 1.0 /*B*/,
				(float) xf->attributes.front.shininess
				/* specular power */) ;
  }


  _dxf_PUSH_MULTIPLY_MATRIX(PORT_CTX,xf->attributes.mm);

  if(xf->colorsDep == dep_positions || xf->normalsDep == dep_positions)
    shademodel(GOURAUD);
  else
    shademodel(FLAT);

  blendfunction(BF_ONE, BF_ZERO);

  if(buttonUp) {
    density = xf->attributes.buttonUp.density;
    approx = xf->attributes.buttonUp.approx;
  } else {
    density = xf->attributes.buttonDown.density;
    approx = xf->attributes.buttonDown.approx;
  }
  /* 
   * indigos get better performance from globjects, so try to 
   * use one
   */
  PHASE_START("DrawPrimitives");

/*
#ifdef DXD_HW_API_DISPLAY_LIST_MEMORY

  if(Obj = DXGetIntegerAttribute((dxObject)(xf), "hwDisplayList", &DisplayList))
  {
     if(DisplayList)
     {
	printf("hwDisplayList Set.\n");fflush(stdout);
     }
     else
     {
	printf("hwDisplayList !Set.\n");fflush(stdout);
     }
  }
*/
if(xf->UseDisplayList)
{
  /*
   * Building an object is expensive, so only build one if we think we can
   * reuse it. i.e. for button down or button up where approx is equal 
   * to button down.
   */
  if(!buttonUp)
  {
    if (!xf->glObject)
    {
      xf->glObject = genobj();
      xf->deletePrivate = _deleteGLObject;
      TIMER("> makeobj");
      printf("A");
      makeobj(xf->glObject);
      if(!_drawPrimitives(portHandle, xf, approx, density))
      {
	closeobj();
	_deleteGLObject(xf);
	goto error;
      }
      closeobj();
    }
    TIMER("< makeobj");
    TIMER("> callobj");
    printf(".");
    callobj(xf->glObject);
    TIMER("< callobj");
  } /* !buttonUp */
  else
  if(xf->UseFastClip)
  {
     if(!xf->glObject)
     {
        xf->glObject = genobj();
        xf->deletePrivate = _deleteGLObject;
        TIMER("> makeobj");
	printf("B");
        makeobj(xf->glObject);
        if (!_drawPrimitives(portHandle, xf, approx, density)) {
	  closeobj();
	  _deleteGLObject(xf);
	  goto error;
        }
        closeobj();
     }
     printf(",");
     callobj(xf->glObject);
  } /* !xf->UseFastClip */
  else
  {
    if (!_drawPrimitives(portHandle, xf, approx, density))
      goto error;
  }
} /* !xf->UseDisplayList */
else
  if(xf->UseFastClip)
  {
     if(!xf->glObject)
     {
        xf->glObject = genobj();
        xf->deletePrivate = _deleteGLObject;
        TIMER("> makeobj");
	printf("C");
        makeobj(xf->glObject);
        if (!_drawPrimitives(portHandle, xf, approx, density))
	{
	  closeobj();
	  _deleteGLObject(xf);
	  goto error;
        }
        closeobj();
     }
     printf("//");
     callobj(xf->glObject);
  } /* !xf->UseFastClip */
  /*
  else
  {
    if (!_drawPrimitives(portHandle, xf, approx, density))
      goto error;
  }
  */
else
/*
#else
*/

  if (!_drawPrimitives(portHandle, xf, approx, density))
    goto error;
/*
#endif
*/
  PHASE_END("DrawPrimitives");
  fflush(stdout);

 done:
  /*
   * Disable lighting, reset matrix stack
   */
  _dxf_SET_GLOBAL_LIGHT_ATTRIBUTES(PORT_CTX ,0);

  _dxf_POP_MATRIX(PORT_CTX);

  PHASE_END("DrawOpaque");

  TIMER("< DrawOpaque");
  EXIT(("OK"));
  return OK;

 error:

  /*
   * Disable lighting, reset matrix stack
   */
  _dxf_SET_GLOBAL_LIGHT_ATTRIBUTES(PORT_CTX ,0);
  _dxf_POP_MATRIX(PORT_CTX);

  PHASE_END("DrawOpaque");
  TIMER("< DrawOpaque");

  EXIT(("ERROR"));
  return ERROR;
}

_drawTranslucentPrimitives(tdmPortHandleP portHandle, xfieldP xf, 
		SortD list, int n,
		enum approxE approx, int density)
{
  helperFunc	helper;
  
  ENTRY(("_drawPrimitives(0x%x, 0x%x, %d, %d)",
	 portHandle, xf, approx, density));

  TIMER("> drawTranslucentPrimitives");

  if(xf->invCntns)
    if(! DXInitGetNextInvalidElementIndex(xf->invCntns))
      goto error;

  finish(); /* Flush Geometry Pipeline */

  PHASE_START("TranslucentPrimitives");

  blendfunction(BF_SA, BF_MSA);

  switch (xf->connectionType) {
  case ct_none:
    TIMER("> translucent points");
    translucentPolygons(xf,helper,list,n,0,approx,density);
    TIMER("< dots");
    break;
  case ct_lines:
    if(xf->attributes.aalines) 
        linesmooth(SML_ON);
    helper = getHelper(xf->colorsDep,dep_none,xf->opacitiesDep,NULL);
    TIMER("> lines");
    translucentLines(xf,helper,list,n,0,approx,density);
    TIMER("< lines");
    linesmooth(SML_OFF);
    break;
  case ct_triangles: 
    helper = getHelper(xf->colorsDep,xf->normalsDep,xf->opacitiesDep,
		       (xf->texture != NULL) && (approx == approx_none));
    TIMER("> triangles");
    translucentPolygons(xf,helper,list,n,0,approx,density);
    TIMER("< triangles");
    break;
  case ct_quads:
    helper = getHelper(xf->colorsDep,xf->normalsDep,xf->opacitiesDep,
		       (xf->texture != NULL) && (approx == approx_none));
    TIMER("> quads");
    translucentPolygons(xf,helper,list,n,4,approx,density);
    TIMER("< quads");
    break;
    break;
  default:
    DXErrorGoto (ERROR_INTERNAL, "invalid xfield connections type in translucent") ;
    break;
  }
  PHASE_END("TranslucentPrimitives");
  
 done:
  TIMER("< drawTranslucentPrimitives");
  EXIT(("OK"));
  return OK;

 error:
  TIMER("< drawTranslucentPrimitives");
  EXIT(("ERROR"));
  return ERROR;
}

Error
_dxf_DrawTranslucent (void *globals,
		 RGBColor ambientColor, int buttonUp)
{
  int		density;
  enum approxE	approx;
  dxObject 	Obj;
  int      	DisplayList;
  int  		i, j;
  xfieldP       xf;
  DEFGLOBALDATA(globals);
  DEFPORT(PORT_HANDLE);
  SortListP     sl = (SortListP)SORTLIST;
  SortD         sorted = sl->sortList;
  int           nSorted = sl->itemCount;

  TIMER("> DrawTranslucent");

  for (i = 0; i < nSorted; i = j)
  {
    xf = (xfieldP)sorted[i].xfp;

    if(xf->normalsDep != dep_none &&
       (buttonUp &&xf->attributes.buttonUp.approx == approx_none) ||
       (!buttonUp &&xf->attributes.buttonDown.approx == approx_none)) {

      _dxf_SET_GLOBAL_LIGHT_ATTRIBUTES(PORT_CTX ,1);

      _dxf_SET_MATERIAL_SPECULAR (PORT_CTX, 1.0 /*R*/, 1.0 /*G*/, 1.0 /*B*/,
				(float) xf->attributes.front.shininess
				/* specular power */) ;
    }

    _dxf_PUSH_MULTIPLY_MATRIX(PORT_CTX,xf->attributes.mm);

    if(xf->colorsDep == dep_positions || xf->normalsDep == dep_positions || xf->opacitiesDep == dep_positions)
      shademodel(GOURAUD);
    else
      shademodel(FLAT);

    if (xf->nClips)
      if (! _dxf_ADD_CLIP_PLANES(LWIN, xf->clipPts, xf->clipVecs, xf->nClips))
	  goto error;


    if(buttonUp) {
      density = xf->attributes.buttonUp.density;
      approx = xf->attributes.buttonUp.approx;
    } else {
      density = xf->attributes.buttonDown.density;
      approx = xf->attributes.buttonDown.approx;
    }

    /*
     * Count the successive primitives from th same xfield
     */
    for (j = i+1; j < nSorted && xf == (xfieldP)sorted[j].xfp; j++);

    /* 
     * indigos get better performance from globjects, so try to 
     * use one
     */
    if(xf->UseFastClip)
    {
       if(!xf->glObject)
       {
	  xf->glObject = genobj();
	  xf->deletePrivate = _deleteGLObject;
	  TIMER("> makeobj");
	  printf("C");
	  makeobj(xf->glObject);
	  if (!_drawTranslucentPrimitives(PORT_HANDLE, xf, sorted+i, j-i, approx, density))
	  {
	    closeobj();
	    _deleteGLObject(xf);
	    goto error;
	  }
	  closeobj();
       }
       printf("//");
       callobj(xf->glObject);
    } 
    else
      if (!_drawTranslucentPrimitives(PORT_HANDLE, xf, sorted+i, j-i, approx, density))
	goto error;
    
    if (xf->nClips)
      if (! _dxf_REMOVE_CLIP_PLANES(LWIN, xf->nClips))
	  goto error;

    _dxf_POP_MATRIX(PORT_CTX) ;
  }

  PHASE_END("DrawPrimitives");
  fflush(stdout);

done:
  /*
   * Disable lighting, reset matrix stack
   */
  _dxf_SET_GLOBAL_LIGHT_ATTRIBUTES(PORT_CTX ,0);

  TIMER("< DrawTranslucent");
  EXIT(("OK"));
  return OK;

error:

  /*
   * Disable lighting, reset matrix stack
   */
  _dxf_SET_GLOBAL_LIGHT_ATTRIBUTES(PORT_CTX ,0);
  _dxf_POP_MATRIX(PORT_CTX);

  PHASE_END("DrawOpaque");
  TIMER("< DrawOpaque");

  EXIT(("ERROR"));
  return ERROR;
}

   
static void
_deleteGLObject(xfieldP xf)
{
  ENTRY(("_deleteGLObject(0x%x)", xf));

  if(xf->glObject)
  {
    delobj(xf->glObject);
    xf->glObject = NULL;
  }

#ifdef sgi
  if(xf->FlatGridTexture.Index)
  {
  /* (:Q=  Only Needed if LRU Paging Is Undesirable
     if(xf->FlatGridTexture.Index > 0)
        texbind(TX_TEXTURE_IDLE, xf->FlatGridTexture.Index);
  */
     xf->FlatGridTexture.Index = 0;
     xf->FlatGridTexture.Address = NULL;
  }
#endif

  EXIT((""));
}

#ifdef sgi

Error
glStartTexture(xfieldP xf)
{
   unsigned long * Tex = NULL;
   unsigned char * Char;
   unsigned char * CharOrig;
   unsigned long R, G, B;
   unsigned long CtrWidth, CtrHeight;
   unsigned long Out;
   unsigned long Tmp;

   static float TexType[5] = { TX_MINFILTER, TX_BILINEAR,
			       TX_MAGFILTER, TX_BILINEAR,
			       TX_NULL };
   static float TevType[2] = { TV_MODULATE, TV_NULL };

   Matrix Ident = { 1.0f, 0.0f, 0.0f,
                    0.0f, 1.0f, 0.0f,
                    0.0f, 0.0f, 1.0f };
   if((Tex = DXAllocate(xf->textureWidth * xf->textureHeight * 4)) == NULL)
   {
      DXSetError(ERROR_NO_MEMORY,
		 "Falied to Allocate Texture Translation Space");
      return ERROR;
   }

   Char = (unsigned char *)Tex;
   CharOrig = (unsigned char *)xf->texture;

   for(CtrHeight = 0; CtrHeight < xf->textureHeight; CtrHeight ++)
   {
      for(CtrWidth = 0; CtrWidth < xf->textureWidth; CtrWidth ++)
      {
	 Out = (*(CharOrig) << 24) + (*(CharOrig + 1) << 16) +
	       (*(CharOrig + 2) << 8) + *(CharOrig + 3);
         R = ((Out & 0x000000ff));
         G = ((Out & 0x0000ff00) >> 8);
         B = ((Out & 0x00ff0000) >> 16);
	 *Char++ = (char)G;
	 *Char++ = (char)B;
	 *Char++ = (char)R;
	 CharOrig += 3;
      }
      for(Tmp = (xf->textureWidth * 3); (Tmp % 4) != 0; Tmp ++)
      {
	 *Char++ = 0;
	 CharOrig ++;
      }
   }

   texdef2d(1, 3, xf->textureWidth, xf->textureHeight,
	    (unsigned long *)Tex, 5, TexType);

   DXFree(Tex);

   tevdef(1, 3, TevType);
   mmode(MTEXTURE);
   tevbind(TV_ENV0, 1);
   texbind(TX_TEXTURE_0, 1);
   mmode(MVIEWING);

   return OK;
}

Error
glEndTexture()
{
    tevbind(TV_ENV0, 0);
}
#endif


#else


/*
 * HELPERCODE
 * code to generate helper routines and table
 */

#include <stdio.h>
main()
{
     int i;
     char c, n, o, tbl[] = {'v', 'e', 'f', 'n'};
     for (i = 0; i < 64; i++)
     {
  	  c = tbl[i>>4];
  	  n = tbl[0x3&(i>>2)];
  	  o = tbl[0x3&(i)];
  	  printf("static void\n"
		 "helper_%c%c%c(xfieldP xf, int ppc,"
		 " int c, int *t, float *rgba)\n"
		 "{\n"
		 "    static float fscratch[3];\n"
		 "    static int p, iscratch;\n\n",
  		 c, n, o);
	  if (c == 'e')
	      printf("    GETCOLOR(c);\n");
	  if (o == 'e')
	      printf("    GETOPACITY(c);\n");
	  if (n == 'e')
	      printf("    SENDNORMAL(c);\n");
	  if ((o == 'e' || o == 'n') && c == 'e' && (n == 'e' || n == 'n' || n == 'f'))
	      if (n == 'n')
		  printf("    SENDCOLOR(%d);\n", o != 'n' ? 1 : 0);
	      else
		  printf("    SENDLITCOLOR(%d);\n", o != 'n' ? 1 : 0);

	  printf("    for (p = 0; p < ppc; p++) {\n");

	  if (n == 'v')
	      printf("        SENDNORMAL(t[p]);\n");
#if 0
	  else if (n == 'f')
	      printf("        SENDNORMAL(0);\n");
#endif
	  if (c == 'v')
	      printf("        GETCOLOR(t[p]);\n");
	  if (o == 'v')
	      printf("        GETOPACITY(t[p]);\n");
	  if (c == 'v' || o == 'v' || n == 'v')
	      if (n == 'n')
		  printf("        SENDCOLOR(%d);\n", o != 'n' ? 1 : 0);
	      else
		  printf("        SENDLITCOLOR(%d);\n", o != 'n' ? 1 : 0);
	  printf("        SENDPOSITION(t[p]);\n");
	  printf("    }\n");
	  printf("    return;\n");
	  printf("}\n\n");
     }
    
     printf("static helperFunc helperTable[] = {\n");
     for (i = 0; i < 64; i++)
     {
  	  c = tbl[i>>4];
  	  n = tbl[0x3&(i>>2)];
  	  o = tbl[0x3&(i)];
  	  printf("%shelper_%c%c%c%c%c",
    	         ((i%4) == 0) ? "    " : " ",
  		 c, n, o, (i == 63) ? ' ' : ',',
  		 ((i%4) == 3) ? '\n' : ' ');
     }
     printf("};\n\n");
}
  
#endif
