/***********************************************************************/
/* 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>


#ifndef HELPERCODE

/*---------------------------------------------------------------------------*\
$Header: /home/gda/dxcvs/dx/src/exec/hwrender/opengl/hwPortUtilOGL.c,v 1.3 1999/05/10 15:45:37 gda Exp $

Author:  Ellen Ball

Based on hwrender/gl/hwPortUtil.c

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

#include <math.h>

#ifdef DXD_WIN
#include <windows.h>
#include <wingdi.h>
#endif

#include <GL/gl.h>

#ifdef DEBUG
#define TIMER(s) glFlush(); DXMarkTime(s);
#else
#define TIMER(s)
#endif

#include "hwDeclarations.h"
#include "hwXfield.h"
#include "hwWindow.h"
#include "hwPortLayer.h"
#include "hwPortOGL.h"
#include "hwTmesh.h"
#include "hwObjectHash.h"
#include "hwSort.h"

#include "hwDebug.h"

static void loadTexture(xfieldP);
static void startTexture();
static void endTexture();

static int doesTrans;
/* screen door half-transparency pattern */
static GLubyte screen_door_50[] =
{
  0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
  0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
  0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
  0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
  0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
  0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
  0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
  0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
  0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
  0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
  0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
  0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
  0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
  0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
  0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
  0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55
} ;

#define Cull(xf)                       \
   if(xf->cullFace == DXHW_CULL_BACK)  \
   {                                   \
      glEnable(GL_CULL_FACE);          \
      glCullFace(GL_BACK);             \
   }                                   \
   else                                \
   if(xf->cullFace == DXHW_CULL_FRONT) \
   {                                   \
      glEnable(GL_CULL_FACE);          \
      glCullFace(GL_FRONT);            \
   }                                   \
   else                                \
   if(xf->cullFace != DXHW_CULL_OFF)   \
      glDisable(GL_CULL_FACE);         \




static int globStart,
	   globEnd;

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


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 ALL_PRIMS         0
#define OPAQUE_PRIMS      1
#define TRANSLUCENT_PRIMS 2


/*-------- These happen once per field -- outside glBegin/glEnd -------*/

#define	SENDPOSITION(offset) 						\
{ 								       	\
  const GLfloat *position ;						\
  position = (const GLfloat *)DXGetArrayEntry(xf->positions,offset,fscratch) ;\
  if(xf->shape < 3)							\
    glVertex2fv(position) ;  	/* When only x and y are specified   	\
				 * z defaults to 0.0 */			\
  else									\
    glVertex3fv(position) ;						\
}

#define	SENDUV(offset) 							\
{ 								       	\
  const GLfloat *uv ;							\
  uv = (const GLfloat *)DXGetArrayEntry(xf->uv,offset,uvscratch) ;	\
  glTexCoord2fv(uv) ;							\
}

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

#if defined(alphax)
#undef _dxf_SERVICES_FLAGS
extern hwFlags _dxf_SERVICES_FLAGS();
#define OPACITY_STIPPLE							\
{									\
if (!_dxf_isFlagsSet(_dxf_SERVICES_FLAGS(),				\
                        SF_TRANSPARENT_OFF)) {				\
     if((xf->opacitiesDep != dep_none && OPACITY(0) < .75) ||		\
         xf->attributes.flags & CONTAINS_VOLUME) { 			\
        glEnable (GL_POLYGON_STIPPLE) ;					\
        glPolygonStipple (screen_door_50) ;				\
      }									\
  }									\
  }
#else
#define OPACITY_STIPPLE							\
{									\
  if((xf->opacitiesDep != dep_none && OPACITY(0) < .75) ||		\
      xf->attributes.flags & CONTAINS_VOLUME) { 			\
    glEnable (GL_POLYGON_STIPPLE) ;					\
    glPolygonStipple (screen_door_50) ;					\
  }									\
  }
#endif

static float _opacity = 1.0f;
static float color[4];
static float ambient[4];
static float diffuse[4];

static int separateAmbientAndDiffuse;
static int depthMaskState;
#define DEPTHMASK_SET		0
#define DEPTHMASK_UNSET		1

#define SENDOPACITY(offset)						\
{									\
   if((xf->opacitiesDep != dep_none) ||					\
      (xf->attributes.flags & CONTAINS_VOLUME))				\
   {									\
      float * opT;							\
      if(xf->opacities)							\
      {									\
	 _opacity = OPACITY(offset);					\
	 PRINT(("Opacity per field (%f)", _opacity));			\
      }									\
   }									\
}

#define	SENDNORMAL(offset) 						\
{ 									\
  oglVector *normal; 							\
  normal = (oglVector *)DXGetArrayEntry(xf->normals,offset,fscratch) ;	\
  glNormal3fv((const GLfloat *) normal) ;				\
}

#define SENDSPECCOLOR()                                 		\
{                                                       		\
  oglRGBColor rgbspec ;							\
  rgbspec.r = rgbspec.g = rgbspec.b =                   		\
      (GLfloat) xf->attributes.front.specular ;         		\
  glColorMaterial (GL_FRONT_AND_BACK, GL_SPECULAR) ;    		\
  glColor3fv ((const GLfloat  *)  &rgbspec) ;           		\
}

#define	APPLY_LIGHTING							\
{ 									\
  if (separateAmbientAndDiffuse)					\
  {  									\
       color[0] = xf->attributes.front.ambient * color[0];		\
       color[1] = xf->attributes.front.ambient * color[1];		\
       color[2] = xf->attributes.front.ambient * color[2];		\
  } 									\
  else									\
  { 									\
       color[0] = xf->attributes.front.diffuse * color[0];		\
       color[1] = xf->attributes.front.diffuse * color[1];		\
       color[2] = xf->attributes.front.diffuse * color[2];		\
  }									\
}

#define	GETCOLOR(offset) 						\
{ 									\
  float *cPtr;								\
									\
  if(xf->ncmap) 							\
  {									\
    cPtr = DXGetArrayEntry(xf->cmap,					\
	   *(ubyte  *) DXGetArrayEntry(xf->fcolors, offset, &iscratch),	\
	   fscratch);							\
  }									\
  else 									\
  {									\
    cPtr = DXGetArrayEntry(xf->fcolors, offset,fscratch);		\
  }									\
  									\
  color[0] = *cPtr;							\
  color[1] = *(cPtr+1);							\
  color[2] = *(cPtr+2);							\
}

#define SENDCOLOR							\
{									\
    glColor3fv(color);						\
}

#define SENDCOLOROPACITY						\
{									\
    glColor4fv(color);							\
}

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

#define SENDPERFIELD(lit) 						\
{ 									\
  int _lit = lit && xf->normalsDep != dep_none;				\
 									\
  if (xf->attributes.front.ambient == xf->attributes.front.diffuse) 	\
  {									\
    separateAmbientAndDiffuse = 0;					\
  }									\
  else									\
      separateAmbientAndDiffuse = 1;					\
									\
  if(xf->colorsDep == dep_field)              				\
    GETCOLOR(0);							\
  if(xf->opacitiesDep == dep_field)            				\
  {									\
    GETOPACITY(0);							\
    if (color[3] < 0.5)							\
    {									\
      glDepthMask(GL_FALSE);						\
      OGL_FAIL_ON_ERROR(glDepthMask);					\
      depthMaskState = DEPTHMASK_UNSET;					\
    }									\
    else								\
    {									\
      glDepthMask(GL_TRUE);						\
      OGL_FAIL_ON_ERROR(glDepthMask);					\
      depthMaskState = DEPTHMASK_SET;					\
    }									\
  }									\
  									\
  if(! _lit)								\
  {									\
    glDisable(GL_LIGHTING);						\
  }									\
  else 									\
  { 									\
    glEnable(GL_LIGHTING);						\
    SENDSPECCOLOR(); 							\
    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);		\
    if(xf->normalsDep == dep_field) 					\
    {									\
      SENDNORMAL(0); 							\
      if (xf->colorsDep == dep_field)					\
	APPLY_LIGHTING;							\
    }									\
  } 									\
									\
  if(doesTrans)								\
  {									\
    if (xf->colorsDep == dep_field)					\
      if (xf->opacitiesDep == dep_none) SENDCOLOR			\
      else if (xf->opacitiesDep == dep_field) SENDCOLOROPACITY;		\
  }									\
  else									\
     OPACITY_STIPPLE;							\
}	

#define ENDPERFIELD()							\
{									\
    if (! doesTrans) glDisable (GL_POLYGON_STIPPLE);			\
    if (depthMaskState == DEPTHMASK_UNSET)				\
    {									\
      glDepthMask(GL_TRUE);						\
      OGL_FAIL_ON_ERROR(glDepthMask);					\
      depthMaskState = DEPTHMASK_SET;					\
    }									\
}

/*
 * 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); \
}

#define NOT_LIT 0
#define LIT 1

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

  SENDPERFIELD(NOT_LIT);

  for(p = i = 0; p < xf->npositions; p += skip)
      if(!xf->invPositions || !DXIsElementInvalid(xf->invPositions, p))
      {
	if (i == 0)
	    glBegin(GL_POINTS);

	SENDCOLOR(p);
	SENDPOSITION(p);

	if (i++ == 256)
	{
	    glEnd();
	    i = 0;
	}
  }

  if (i != 0)
      glEnd();

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

error:
  return ERROR;
}

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 = 0, c, c1;

  glBegin(GL_POINTS);

  for(c = 0; c < n; c++)
  {
    if (i == 256)
    {
	glEnd();
	glBegin(GL_POINTS);
        SENDPERFIELD(NOT_LIT);
    }

    if (xf->connections)
	c1 = *(int*)DXGetArrayEntry(xf->connections,list[c].poly,(Pointer)iscratch);
    else
	c1 = list[c].poly;
	
    (*helper)(xf,1,list[c].poly,&c1);

    i++;
  }

  if (i)
    glEnd();

  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		i = 0, c;
  dependencyT   odep;
  int 		translu;

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

  SENDPERFIELD(NOT_LIT);

  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))
		    continue;

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

		if (! translu)
		{
		    if (i == 0)
			glBegin(GL_POINTS);

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

			if (++i == 256)
		    {
			i = 0;
			glEnd();
		    }
		}
	    }
	  }

	  if (i)
	    glEnd();
      }
  }
  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))
		continue;

	    if (i == 0)
		glBegin(GL_POINTS);

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

	    if (++i == 256)
	    {
		i = 0;
		glEnd();
	    }
	}
      }

      if (i)
	glEnd();
  }

  ENDPERFIELD();

  EXIT((""));
  return OK;

error:
    return ERROR;
}


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;

  glBegin(GL_LINES);

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

  glEnd();

  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;
  dependencyT   odep;
  int 		translu;

  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);
  }

  SENDPERFIELD(NOT_LIT);

  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)
	  {
	    glBegin(GL_LINES);
	    (*helper)(xf,xf->posPerConn,c,translation);
	    glEnd();
	  }
	}
      }
  }
  else
  {
      for(c=firstConnection;c<lastConnection;c+=skip)
      {
	if(!xf->invCntns || ! DXIsElementInvalid(xf->invCntns,c))
	{
	  glBegin(GL_LINES);
	  GET_CONNECTION(c);
	  (*helper)(xf,xf->posPerConn,c,translation);
	  glEnd();
	}
      }
  }

  ENDPERFIELD();

  EXIT((""));
  return OK;

error:
  return ERROR;
}

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;

  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);
  }

  SENDPERFIELD(NOT_LIT);

  for(c=firstConnection;c<lastConnection;c+=skip)
  {
    if(!xf->invCntns || ! DXIsElementInvalid(xf->invCntns,c))
    {
      glBegin (GL_LINE_LOOP);
      GET_CONNECTION(c);
      (*helper)(xf,xf->posPerConn,c,translation);
      glEnd();
    }
  }

  ENDPERFIELD();

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



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		c1, translu;
   float	vec[3][4], *orig, depth;
   int		ii;
   int 		i;

   for (i = 0; i < n; i++)
   {
      GET_CONNECTION(list[i].poly);
      glBegin(GL_POLYGON);
         (*helper)(xf,xf->posPerConn,list[i].poly,translation);
      glEnd();
   }

   EXIT((""));
   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;
   register int	c;
   register int	c1, translu = 0;
   float	vec[3][4], *orig, depth;
   register int	ii;
   dependencyT   odep;


   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,xf->texture != NULL);
        EXIT(("calling closedlines"));
        return closedlines(xf,helper,0,xf->nconnections,face,approx,skip);
        break;
   }

   SENDPERFIELD(LIT);

   if(doesTrans)
   {
      if(xf->posPerConn > 4)
      {
         PRINT(("Error..."));
         DXSetError(ERROR_BAD_PARAMETER, "Positions", "");
         return(ERROR);
      }
 
      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_positions)
             {
	        translu = 0;
	        for(c1 = 0; c1 < xf->posPerConn; c1 ++)
	        {
	           PRINT(("(translation[%d] = %d) = %f",
		         c1, translation[c1], OPACITY(translation[c1])));
	           translu |= OPACITY(translation[c1]) < 1.0f;
	        }
             }
             else if (odep == dep_connections)
	     {
		translu = OPACITY(c) < 1.0f;
	     }
   
             if(!translu)
             {
                glBegin(GL_POLYGON);
                   (*helper)(xf,xf->posPerConn,c,translation);
                glEnd();
             }
         }
      }
   }
   else /* !doesTrans */
   {
      for(c=firstConnection;c<lastConnection;c+=skip)
      {
         GET_CONNECTION(c);
         glBegin(GL_POLYGON);
            (*helper)(xf,xf->posPerConn,c,translation);
         glEnd();
      }
   }

   ENDPERFIELD();

   EXIT((""));
   return OK;

   error:
      return ERROR;
}


static int _drawTranslucentPrimitives(tdmPortHandleP portHandle, xfieldP xf,
	SortD list, int n, enum approxE approx, int density)
{
   helperFunc	helper;

   ENTRY(("_drawTranslucentPrims(0x%x, 0x%x, %d, %d)",
	  portHandle, xf, approx, density));

   switch (xf->connectionType)
   {
      case ct_none :
	 PRINT((" translucent points:"));
	 helper = getHelper(xf->colorsDep,xf->normalsDep,xf->opacitiesDep,
			    xf->texture != NULL) ;
         TIMER("> translucent points") ;
	 translucentPoints(xf,helper,list,n,0,approx,density) ;
	 TIMER("< translucent points") ;
	 break;
      case ct_lines :
	 PRINT((" translucent lines:"));
         if(xf->attributes.aalines) {
            glEnable(GL_LINE_SMOOTH);
            glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
         }
	 helper = getHelper(xf->colorsDep,xf->normalsDep,xf->opacitiesDep,
			    xf->texture != NULL) ;
         TIMER("> translucent lines") ;
	 translucentLines(xf,helper,list,n,0,approx,density) ;
	 TIMER("< translucent lines") ;
         glDisable(GL_LINE_SMOOTH);
	 break;
      case ct_triangles :
	 PRINT((" tris:"));
	 helper = getHelper(xf->colorsDep,xf->normalsDep,xf->opacitiesDep,
			    xf->texture != NULL) ;
         TIMER("> triangles") ;
	 translucentPolygons(xf,helper,list,n,0,approx,density) ;
	 TIMER("< triangles") ;
	 break;
      case ct_quads:
	 PRINT((" quads:"));
	 helper = getHelper(xf->colorsDep,xf->normalsDep,xf->opacitiesDep,
                            xf->texture != NULL) ;
         TIMER("> quads") ;
         translucentPolygons(xf,helper,list,n,4,approx,density) ;
         TIMER("< quads") ;
         break;
      case ct_tetrahedra:
         PRINT((" tetra:"));
         helper = getHelper(xf->colorsDep,xf->normalsDep,xf->opacitiesDep, 0) ;
         TIMER("> tetras") ;
         translucentPolygons(xf,helper,list,n,0,approx,density) ;
         translucentPolygons(xf,helper,list,n,1,approx,density) ;
         translucentPolygons(xf,helper,list,n,2,approx,density) ;
         translucentPolygons(xf,helper,list,n,3,approx,density) ;
         TIMER("< tetras") ;
         break;
      case ct_cubes:
         PRINT((" cubes:"));
         helper = getHelper(xf->colorsDep,xf->normalsDep,xf->opacitiesDep, 0) ;
         TIMER("> cubes") ;
         translucentPolygons(xf,helper,list,n,4,approx,density) ;
         translucentPolygons(xf,helper,list,n,5,approx,density) ;
         translucentPolygons(xf,helper,list,n,6,approx,density) ;
         translucentPolygons(xf,helper,list,n,7,approx,density) ;
         translucentPolygons(xf,helper,list,n,8,approx,density) ;
         translucentPolygons(xf,helper,list,n,9,approx,density) ;
         TIMER("< cubes") ;
         break;
      default:
         goto error;
         break;
   }
   done:

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

 error:

  EXIT(("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;

  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,
			    xf->texture != NULL);
         points (xf, helper,0,xf->nconnections,0,approx,skip);
         PRINT(("called points"));
         goto done;
       }
       else
       {
         dots(xf,approx,skip);
         PRINT(("called dots"));
         goto done;
       }
       break;
     case approx_box:
       bbox(xf);
       PRINT(("called bbox"));
       goto done;
       break;
     case approx_lines:
       helper = getHelper(xf->colorsDep,dep_none,dep_none,xf->texture != NULL);
       tmeshlines(xf, helper, approx, skip);
       PRINT(("called tmeshlines"));
       goto done;
       break;
  }

  SENDPERFIELD(LIT);

  /* 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++)
    {
      glBegin (GL_TRIANGLE_STRIP);
      (*helper)(xf,meshes[meshI].count,NOTUSED,
		&translation[meshes[meshI].start]);
      glEnd();
    }
  }
  else
  {  /* skipping */
    skipDelta = 0;
    for(meshI=0;meshI<xf->nmeshes;meshI++)
    {
      strip = &translation[meshes[meshI].start];

      glBegin(GL_TRIANGLES);
      for(count=skipDelta;
	  count < meshes[meshI].count-2;
	  count += skipDelta)
      {
	(*helper)(xf,3,NOTUSED,&strip[count]);
	skipDelta = skip;
      }
      glEnd();
      skipDelta = count - (meshes[meshI].count-2);
    }
  }

  ENDPERFIELD();

 done:
  
  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;
  struct  {
    int start;
    int count;
  }  *meshes;

  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);

  SENDPERFIELD(NOT_LIT);

  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 */
      glBegin (GL_LINE_STRIP);
      (*helper)(xf, meshes[meshI].count, NOTUSED, strip);
      glEnd();

      /* 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)
      {
	glBegin (GL_LINE_STRIP);
	(*helper)(xf,edgeI,NOTUSED,edge);
	glEnd();
      }

      /* 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)
      {
	glBegin (GL_LINE_STRIP);
	(*helper)(xf,edgeI,NOTUSED,edge);
	glEnd();
      }
    }
  }
  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)
      {
	glBegin (GL_LINE_LOOP);
	(*helper)(xf,3,NOTUSED,&strip[count]);
	glEnd ();
	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 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;

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

    SENDPERFIELD(NOT_LIT);

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

		glBegin(GL_LINES);
		while (knt > 0)
		{
		    thisknt = (knt > max) ? max : knt;

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

		    start += skip;
		    knt -= skip;
		}
		glEnd();
	    }
	}
    }
    else
    {

	max = 100;

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

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

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

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

    ENDPERFIELD();

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


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;
  struct  {
    int start;
    int count;
  }  *meshes;

  ENTRY(("polylines(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);

  SENDPERFIELD(NOT_LIT);

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

#if defined(alphax)
/* This temporary fix is because DEC's Xserver core dumps when
   given more than 60 points per begin/end when rendering lines
   and there is a clipping plane active. */
#define MAX_PLINE_VERTS MaxTstripSize
  if(skip <= 1) {	/* NOT skipping */
    /* For each mesh....*/
    for(meshI=0;meshI<xf->nmeshes;meshI++) {
      count = meshes[meshI].count;
      start = meshes[meshI].start;
      /* DEC X server core dumps with too many verts/line when clipping */
      for(step = 0; step < count; step += MAX_PLINE_VERTS-1) {
	glBegin(GL_LINE_STRIP);
	(*helper)(xf, 
		  (((step + MAX_PLINE_VERTS) < count) ?
		   MAX_PLINE_VERTS :
		   (count - step)), 
		  NOTUSED, &translation[step+start]);
	glEnd();
      }
    }
  } else { /* skipping */
    skipDelta = 0;
    for(meshI=0;meshI<xf->nmeshes;meshI++) {
      strip = &translation[meshes[meshI].start];
      /* this is really bogus but we'll take two point lines here
	 because of DEC's X server's tendency to core dump when
	 given more */
      for(count=skipDelta;
	  count < meshes[meshI].count-1;
	  count += skipDelta) {
	glBegin (GL_LINES);
	(*helper)(xf,2,NOTUSED,&strip[count]);
	skipDelta = skip;
	glEnd ();
      }
      skipDelta = count - (meshes[meshI].count-1);
    }
  }
#else
  if(skip <= 1) {	/* NOT skipping */
    for(meshI=0;meshI<xf->nmeshes;meshI++) {
      /* This is for normal implementations */
      glBegin(GL_LINE_STRIP);
      (*helper)(xf, meshes[meshI].count, NOTUSED, 
		&translation[meshes[meshI].start]);
      glEnd();
    }
  } else { /* skipping */
    skipDelta = 0;
    for(meshI=0;meshI<xf->nmeshes;meshI++) {
      strip = &translation[meshes[meshI].start];
      glBegin (GL_LINES);
      for(count=skipDelta;
	  count < meshes[meshI].count-1;
	  count += skipDelta) {
	(*helper)(xf,2,NOTUSED,&strip[count]);
	skipDelta = skip;
      }
      glEnd ();
      skipDelta = count - (meshes[meshI].count-1);
    }
  }
#endif
  
  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};

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

  SENDPERFIELD(NOT_LIT);

  glColor3fv ((const GLfloat *) &yellow[0]) ;
  glBegin (GL_LINE_STRIP);
  glVertex3fv((GLfloat*)&xf->box[0]);
  glVertex3fv((GLfloat*)&xf->box[1]);
  glVertex3fv((GLfloat*)&xf->box[3]);
  glVertex3fv((GLfloat*)&xf->box[2]);
  glVertex3fv((GLfloat*)&xf->box[0]);
  glVertex3fv((GLfloat*)&xf->box[4]);
  glVertex3fv((GLfloat*)&xf->box[5]);
  glVertex3fv((GLfloat*)&xf->box[7]);
  glVertex3fv((GLfloat*)&xf->box[6]);
  glVertex3fv((GLfloat*)&xf->box[4]);
  glEnd ();

  glBegin (GL_LINES);
  glVertex3fv((GLfloat*)&xf->box[2]);
  glVertex3fv((GLfloat*)&xf->box[6]);

  glVertex3fv((GLfloat*)&xf->box[3]);
  glVertex3fv((GLfloat*)&xf->box[7]);

  glVertex3fv((GLfloat*)&xf->box[1]);
  glVertex3fv((GLfloat*)&xf->box[5]);
  glEnd ();

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


/*
 * texture-mapping helpers
 */

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;

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

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

  EXIT((""));
}

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


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

  SENDNORMAL(ctIndex);
  glColor3ub(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;
  GLubyte c = 0xff;

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

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

  EXIT((""));
}

#include "hwPortUtilOGL.help"

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

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

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

#if 0
  if(colorsDep == dep_none) colorsDep = dep_field;
  if(opacitiesDep == dep_none) opacitiesDep = dep_field;
  opacitiesDep = dep_field;

  index = (( (int)opacitiesDep-1) * 3 + ((int)normalsDep)) * 3 + 
    ((int)colorsDep-1);
  ret = helperTable[index];

  EXIT(("ret = 0x%x",ret));
#endif

  index = getIndex(colorsDep, normalsDep, opacitiesDep);
  ret = helperTable[index];

  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));
  
  if(xf->invCntns)
    if(! DXInitGetNextInvalidElementIndex(xf->invCntns))
      goto error;

  glGetFloatv(GL_MODELVIEW_MATRIX, (float *)xf->attributes.vm);
  glFinish() ;
  
  switch (xf->connectionType)
  {
  case ct_none:
    PRINT((" points:"));
    TIMER("> points") ;
    helper = getHelper(xf->colorsDep,dep_none,dep_none,xf->texture != NULL);
    points(xf,helper,0,xf->npositions,0,approx,density) ;
    TIMER("< points") ;
    break;
  case ct_lines:
    PRINT((" lines:"));
    if(xf->attributes.linewidth > 0)
       glLineWidth(xf->attributes.linewidth);

    if(xf->attributes.aalines) {
       glEnable(GL_LINE_SMOOTH);
       glEnable(GL_BLEND);
       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
       glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
    }
    helper = getHelper(xf->colorsDep,dep_none,dep_none,xf->texture != NULL);
    TIMER("> lines") ;
    lines(xf,helper,0,xf->nconnections,0,approx,density) ;
    TIMER("< lines") ;
    glDisable(GL_LINE_SMOOTH);
    glDisable(GL_BLEND);
    break;
  case ct_polylines:
     PRINT(("> polylines"));
     if(xf->attributes.linewidth > 0)
        glLineWidth(xf->attributes.linewidth);

     if(xf->attributes.aalines) {
        glEnable(GL_LINE_SMOOTH);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
     }
     helper = getHelper(xf->colorsDep,dep_none,dep_none,NULL);
     TIMER("> polylines");
     polylines(xf, helper, approx, density);
     TIMER("< polylines");
     glDisable(GL_LINE_SMOOTH);
     glDisable(GL_BLEND);
     break;
  case ct_pline:
     PRINT((" plines:"));
     if(xf->attributes.linewidth > 0)
        glLineWidth(xf->attributes.linewidth);

     if(xf->attributes.aalines) {
        glEnable(GL_LINE_SMOOTH);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
     }
     helper = getHelper(xf->colorsDep,dep_none,dep_none, xf->texture != NULL);
     TIMER("> plines");
     plines(xf,helper,approx,density);
     TIMER("< plines");
     glDisable(GL_LINE_SMOOTH);
     glDisable(GL_BLEND);
     break;
  case ct_triangles: 
     PRINT((" tris:"));
     helper = getHelper(xf->colorsDep,xf->normalsDep,xf->opacitiesDep,
				    xf->texture != NULL) ;
     TIMER("> triangles") ;
     polygons(xf,helper,0,xf->nconnections,0,approx,density) ;
     TIMER("< triangles") ;
     break;
  case ct_quads:
     PRINT((" quads:"));
     helper = getHelper(xf->colorsDep,xf->normalsDep,xf->opacitiesDep,
				xf->texture != NULL) ;
     TIMER("> quads") ;
     polygons(xf,helper,0,xf->nconnections,4,approx,density) ;
     TIMER("< quads") ;
     break;
  case ct_tetrahedra:
    PRINT((" tetra:"));
    helper = getHelper(xf->colorsDep,xf->normalsDep,xf->opacitiesDep, 0) ;
    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:
    PRINT((" cubes:"));
    helper = getHelper(xf->colorsDep,xf->normalsDep,xf->opacitiesDep, 0) ;
    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:
    PRINT((" tmesh:"));
    helper = getHelper(xf->colorsDep,xf->normalsDep,xf->opacitiesDep, xf->texture != NULL) ;
    TIMER("> tmesh") ;
    tmesh(xf,helper,approx,density) ;
    TIMER("< tmesh") ;
    break;
  case ct_qmesh:
    PRINT((" qmesh:"));
    helper = getHelper(xf->colorsDep,xf->normalsDep,xf->opacitiesDep, xf->texture != NULL) ;
    TIMER("> qmesh") ;
    tmesh(xf,helper,approx,density) ;
    TIMER("< qmesh") ;
    break;
#if 0
#ifdef DXD_HW_TEXTURE_MAPPING
  case ct_flatGrid:
    if(approx == approx_none) {
      PRINT((" texture:"));
      TIMER("> texture") ;
      if(!hwTextureDraw(portHandle, xf))
	goto error;
      TIMER("< texture") ;
      break;
    } else {
      PRINT((" texture pgons:"));
      helper = getHelper(xf->colorsDep,xf->normalsDep,xf->opacitiesDep, xf->texture != NULL) ;
      TIMER("> quads") ;
      polygons(xf,helper,0,xf->nconnections,4,approx,density) ;
      TIMER("< quads") ;
      break;
    }
#endif
#endif
  default:
    goto error;
    break;
  }

 done:

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

 error:

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

Error _dxf_DrawTranslucentOGL(void *globals, 
		RGBColor * ambientColor, int buttonUp)
{
  DEFGLOBALDATA(globals);
  DEFPORT(PORT_HANDLE);
  SortListP     sl = (SortListP)SORTLIST;
  SortD		sorted = sl->sortList;
  int 		nSorted = sl->itemCount;
  int           p,i,j;
  RGBColor	amCol;

  xfieldP       xf;
  helperFunc	helper;
  char 		cache_id[50];
  Private 	priv;
  int		density;
  enum approxE	approx;
  float		ambientLight;
  Light		newLight;
  float 	fscratch[3];
  int   	iscratch;

  ENTRY(("_dxf_DrawTranslucentOGL(0x%x, 0x%x, 0x%x, 0x%x)",
         PORT_HANDLE, xf, ambientColor, buttonUp));

  glEnable(GL_BLEND);
  OGL_FAIL_ON_ERROR(glEnableBlend);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  OGL_FAIL_ON_ERROR(glBlendFunc);

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

    if(xf->normalsDep != dep_none &&
        xf->attributes.buttonUp.approx == approx_none)
    {
        _dxf_SET_GLOBAL_LIGHT_ATTRIBUTES(PORT_CTX ,1);

        if(!(xf->attributes.flags & CORRECTED_COLORS))
        {
          xf->attributes.front.ambient = 
	       sqrt((double)xf->attributes.front.ambient) ;
          xf->attributes.front.specular = 
	       sqrt((double)xf->attributes.front.specular) ;;
          xf->attributes.flags |= CORRECTED_COLORS;
        } /* end CORRECTED_COLORS */

        /* Beware divide by zero */
        if(xf->attributes.front.diffuse < .001f)
           xf->attributes.front.diffuse = .001f;

        ambientLight = xf->attributes.front.ambient;

        ambientLight = ambientLight / xf->attributes.front.diffuse;
        ambientLight = ambientLight * ambientLight;

        amCol.r = ambientColor->r * ambientLight;
        amCol.g = ambientColor->g * ambientLight;
        amCol.b = ambientColor->b * ambientLight;

        if(!(newLight = DXNewAmbientLight(amCol)))
          goto error;
    
        if(!_dxf_DEFINE_LIGHT (_wdata,1,newLight))
           goto error;

        DXDelete((dxObject)newLight) ;

        _dxf_SET_MATERIAL_SPECULAR(PORT_CTX, 1.0, 1.0, 1.0,
				   (float)xf->attributes.front.shininess);
    } /* end normals & no approximation */

    if(xf->texture)
    {
       loadTexture(xf);
       startTexture();
    }

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

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

    if(xf->colorsDep == dep_positions || xf->normalsDep == dep_positions)
       glShadeModel(GL_SMOOTH);
    else
       glShadeModel(GL_FLAT);

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

    SENDPERFIELD(LIT);

    for (j = i+1; j < nSorted && xf == (xfieldP)sorted[j].xfp; j++);

    if(!_drawTranslucentPrimitives(PORT_HANDLE, xf, sorted+i, j-i, approx, density))
	goto error;

    ENDPERFIELD();

    if (xf->nClips)
      if (! _dxf_REMOVE_CLIP_PLANES(LWIN, xf->nClips))
        goto error;

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

    _dxf_SET_GLOBAL_LIGHT_ATTRIBUTES(PORT_CTX ,0) ;
    _dxf_POP_MATRIX(PORT_CTX) ;

   }

   glDisable(GL_BLEND);

   OGL_FAIL_ON_ERROR(_dxf_DrawTranslucentOGL);
   glFinish();
   EXIT(("OK"));
   return OK;

 error:

#if 0
   if(notFirstPass)
      glCallList(notFirstPass + 1);
#endif

   glDisable(GL_BLEND);


   _dxf_SET_GLOBAL_LIGHT_ATTRIBUTES(PORT_CTX ,0) ;
   _dxf_POP_MATRIX(PORT_CTX) ;

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


Error _dxf_DrawOpaqueOGL(tdmPortHandleP portHandle, xfieldP xf, 
			 RGBColor ambientColor, int buttonUp)
{
  helperFunc	helper;
  Private 	priv;
  int		density;
  enum approxE	approx;
  float		ambient,diffuse;
  Light		newLight;
  dxObject      dlist = NULL;
  DEFPORT(portHandle) ;

  ENTRY(("_dxf_DrawOpaqueOGL(0x%x, 0x%x, 0x%x, 0x%x)",
	 portHandle, xf, ambientColor, buttonUp));

  doesTrans = _dxf_isFlagsSet(_dxf_SERVICES_FLAGS(), SF_DOES_TRANS);

  Cull(xf);

  if(xf->normalsDep != dep_none &&
     xf->attributes.buttonUp.approx == approx_none)
  {
     _dxf_SET_GLOBAL_LIGHT_ATTRIBUTES(PORT_CTX ,1);

    if(!( xf->attributes.flags & CORRECTED_COLORS))
    {
      xf->attributes.front.ambient = 
	   sqrt((double)xf->attributes.front.ambient) ;
      xf->attributes.front.specular = 
	   sqrt((double)xf->attributes.front.specular) ;;
      xf->attributes.flags |= CORRECTED_COLORS;
    }

    /*
     * A major improvement for GL. We will ignore the ambient
     * coef in the device dependent stuff, instead we'll adjust 
     * the ambient light here and use the diffuse coef in place 
     * of the ambient in the device dependent code.
     */

    /* Beware divide by zero */
    if(xf->attributes.front.diffuse < .001f)
      xf->attributes.front.diffuse = .001f;

    ambient = xf->attributes.front.ambient;
    diffuse = xf->attributes.front.diffuse;
      
    ambient = ambient/diffuse;
    /*
     * DEFINE_LIGHT takes the sqrt() of the input, so we need to square 
     * the coeficient here
     */
    ambient = ambient * ambient;
    ambientColor.r *= ambient;
    ambientColor.g *= ambient;
    ambientColor.b *= ambient;

    if(!(newLight = DXNewAmbientLight(ambientColor)))
      goto error;
    
    /*
     * NOTE XXX A little hokey. We don't need the window to define
     * and ambient light, and we don't have it here.
     */
     if (!_dxf_DEFINE_LIGHT (OGLWINT,1,newLight))
      goto error;
    
    DXDelete((dxObject)newLight) ;

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

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

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

  if(xf->colorsDep == dep_positions || xf->normalsDep == dep_positions)
    glShadeModel(GL_SMOOTH);
  else
    glShadeModel (GL_FLAT);

  OGL_FAIL_ON_ERROR(glShadeModel);

  glDepthMask(GL_TRUE);
  OGL_FAIL_ON_ERROR(glDepthMask);

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

  if (xf->texture)
  {
      if (DXGetObjectTag((dxObject)xf->texture_field) != CURTEX)
      {
          CURTEX = DXGetObjectTag((dxObject)xf->texture_field);

          if (DO_DISPLAY_LISTS)
          {
              dlist = _dxf_QueryObject(TEXTURE_HASH, (dxObject)xf->texture_field);
              if (dlist)
                  _dxf_callDisplayListOGL(dlist);
              else
              {
                  dlist = _dxf_openDisplayListOGL();
                  loadTexture(xf);
                  _dxf_endDisplayListOGL();
                  _dxf_InsertObject(TEXTURE_HASH, (dxObject)xf->texture_field, dlist);
		  dlist = NULL;
              }
          }
	  else
	      loadTexture(xf);
      }

      startTexture();
  }
  else
      endTexture();

  if (DO_DISPLAY_LISTS)
  {
      dlist = _dxf_QueryDisplayList(DISPLAY_LIST_HASH, xf, buttonUp);
      if (dlist)
      {
          _dxf_callDisplayListOGL(dlist);
      }
      else
      {
          dlist = _dxf_openDisplayListOGL();
          if(!_drawPrimitives(portHandle, xf, approx, density))
          {
              _dxf_endDisplayListOGL();
              goto error;
          }
          _dxf_endDisplayListOGL();
          _dxf_InsertDisplayList(DISPLAY_LIST_HASH, xf, buttonUp, dlist);
      }

      dlist = NULL;
  }
  else
      if(!_drawPrimitives(portHandle, xf, approx, density))
          goto error;




  OGL_FAIL_ON_ERROR(Back);
 done:
  if(xf->texture)
     endTexture(xf);

  /*
   * Disable lighting, reset matrix stack
   */
  _dxf_SET_GLOBAL_LIGHT_ATTRIBUTES(PORT_CTX ,0) ;
#if defined(DEBUG)
  WriteViewperfFile(portHandle, xf);
#endif
  _dxf_POP_MATRIX(PORT_CTX) ;

  OGL_FAIL_ON_ERROR(_dxf_DrawOpaqueOGL);
  EXIT(("OK"));
  return OK;

 error:

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

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

static void _deleteGLObject(xfieldP xf)
{

  ENTRY(("_deleteGLObject(0x%x)",xf));
  
  if(xf->glObject) {
    glDeleteLists(xf->glObject,1) ;
    xf->glObject = NULL;
  }

  EXIT((""));
}

#if defined(DEBUG)
#define POSITIONS 0
#define CONNECTIONS 1
#define NORMALS 2
WriteViewperfFile(void *instance, xfieldP xf)
{
/*
   static int been_here_done_that=0;
   
   if (been_here_done_that)
   return;
*/
  if (xf->nnormals != xf->npositions) {
    /* Only interested in lit fields */
    return;
  }

  if (getenv("DX_WRITE_VIEWPERF_FILE")) {
    GLfloat mat[4][4];
    char basename[40];

    glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)&mat);

    /*     been_here_done_that=1; */
    sprintf(basename,"dx.%d",(int)instance);

    WriteToFile(basename, xf, POSITIONS, &mat);
    WriteToFile(basename, xf, CONNECTIONS, &mat);
    WriteToFile(basename, xf, NORMALS, &mat);
  }
}

float *multMatrix(float *vec, float mat[4][4])
{
  float new[4];
  int i,j;


  for (i=0;i<3;i++) {
    new[i] = 0.0;
    for (j=0;j<3;j++) {
      new[i] += vec[j]*mat[j][i];
    }
    new[i] += mat[3][i];
  }

  for(i=0;i<3;i++)
    vec[i] = new[i];

  return vec;
}


#define DET33(s) \
        (( s[0][0] * ((s[1][1] * s[2][2]) - (s[2][1] * s[1][2])) ) + \
         (-s[0][1] * ((s[1][0] * s[2][2]) - (s[2][0] * s[1][2])) ) + \
         ( s[0][2] * ((s[1][0] * s[2][1]) - (s[2][0] * s[1][1])) ) )

float Mycofac (float s0[4][4], int s1, int s2)
{
  int i, j, I, J ;
  float cofac[4][4] ;

  for (i = 0, I = 0 ; i < 4 ; i++)
    if (i != s1) {
      for (j = 0, J = 0 ; j < 4 ; j++)
	if (j != s2)
	  cofac[I][J++] = s0[i][j] ;
      I++ ;
    }

  return DET33(cofac) ;
}


void adjointTranspose (float s1[4][4], float s0[4][4])
{
  int i, j ;

  for (i = 0 ; i < 3 ; i++)
    for (j = 0 ; j < 3 ; j++)
      s1[i][j] = ((((i + j + 1) % 2) * 2) - 1) * Mycofac(s0, i, j);

  for(i = 0; i < 3 ; i++) {
    s1[3][i] = 0.0; 
    s1[i][3] = 0.0;
  }

  s1[3][3] = 1.0;
}

WriteToFile(char *s, xfieldP xf, int type, float mat[4][4])
{
  int i, j;
  static int tot=0;
  float *pos;
  float fscratch[3];
  struct  {
    int start;
    int count;
  } *meshes;
  int *trans, meshI;
  int *con;
  int iscratch[3];
  FILE *fp = NULL;
  char filename[256];
  char extention[][8] = {
    ".coor",
    ".elem",
    ".vnorm"
  };
  float newmat[4][4];
  float *newpos;

  strcpy(filename, s);
  
  strcat(filename, extention[type]);
  
  fp = fopen(filename,"a+");

  if (!fp) {
    printf("Can not open input file: %s\n", filename);
    exit(0);
  }

  switch (type) {
  case POSITIONS:
    for (i=0;i<xf->npositions;i++) {
      pos = DXGetArrayEntry(xf->positions,i,fscratch);
      newpos = multMatrix(pos, mat);
      fprintf(fp,"%4d,% 7.6f,% 7.6f,% 7.6f\n", i+tot,
	      newpos[0], newpos[1], newpos[2]);
    }
    break;
  case CONNECTIONS:
    if (xf->connectionType == ct_tmesh ||
	xf->connectionType == ct_qmesh) {
      trans = DXGetArrayData(xf->connections_array); /* A list of all conns */
      meshes = DXGetArrayData(xf->meshes); /* a list of meshes */
      /* For all meshes */
      for(meshI=0;meshI<xf->nmeshes;meshI++) {
	/* print out all connections */
	fprintf(fp,"thing ");
	for (j=0;j<meshes[meshI].count;j++) {
	  fprintf(fp,"%4d ", trans[meshes[meshI].start+j]+tot);
	}
	fprintf(fp,"\n");
      }
    } else {
      for (i=0;i<xf->nconnections;i++) {
	con = (int*)DXGetArrayEntry(xf->connections,i,iscratch);
	fprintf(fp,"thing ");
	for (j=0;j<xf->posPerConn;j++) {
	  fprintf(fp,"%4d ",con[j]+tot);
	}
	fprintf(fp,"\n");
      }
    }
    break;
  case NORMALS:
    for (i=0;i<xf->npositions;i++) {
      pos = DXGetArrayEntry(xf->normals,i,fscratch);
      adjointTranspose(&newmat, mat);
      newpos = multMatrix(pos, &newmat);
      fprintf(fp,"% 7.6f % 7.6f % 7.6f\n",
	      newpos[0], newpos[1], newpos[2]);
    }
    tot+=xf->npositions;
    break;
  }
  fclose(fp);
}
#endif

static void
loadTexture(xfieldP xf)
{
    glTexImage2D(GL_TEXTURE_2D, 0, 3, xf->textureWidth,
		xf->textureHeight, 0, GL_RGB, GL_UNSIGNED_BYTE,
		(GLubyte *)xf->texture);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
}

static void
startTexture()
{
    glEnable(GL_TEXTURE_2D);
}

static void
endTexture()
{  
    glDisable(GL_TEXTURE_2D);
}
    
#else

#include <stdio.h>

#define NONE		0
#define PER_FIELD	1
#define PER_POSITION	2
#define PER_CONNECTION	3

int cDeps[]     = {NONE, PER_FIELD, PER_POSITION, PER_CONNECTION};
int ncDeps      = 4;

int nDeps[]     = {NONE, PER_FIELD, PER_POSITION, PER_CONNECTION};
int nnDeps      = 4;

int oDeps[]     = {NONE, PER_FIELD, PER_POSITION, PER_CONNECTION};
int noDeps      = 4;

int getIndex(int c, int n, int o)
{
    return ((c*nnDeps)+n)*noDeps + o;
}

char *strings[] =
{
    "none",
    "pf",
    "pp",
    "pc"
};

int printGetIndex()
{
  printf("static int\n");
  printf("depToInt(dependencyT d)\n");
  printf("{\n");
  printf("  switch(d) {\n");
  printf("    case dep_none:        return %d;\n", NONE);
  printf("    case dep_field:       return %d;\n", PER_FIELD);
  printf("    case dep_positions:   return %d;\n", PER_POSITION);
  printf("    case dep_connections: return %d;\n", PER_CONNECTION);
  printf("    default:              return -1;\n");
  printf("  }\n");
  printf("}\n\n");
  printf("static int\n");
  printf("getIndex(dependencyT c, dependencyT n, dependencyT o)\n");
  printf("{\n");
  printf("  int ci = depToInt(c);\n");
  printf("  int ni = depToInt(n);\n");
  printf("  int oi = depToInt(o);\n");
  printf("  if (ci == -1 || ni == -1 || oi == -1)\n");
  printf("    return -1;\n");
  printf("  else return ((ci*%d)+ni)*%d+oi;\n", nnDeps, noDeps);
  printf("}\n\n");

  return;
}

printLabel(int cd, int nd, int od)
{
  printf("C%sN%sO%s", strings[cd], strings[nd], strings[od]);
}

printTable()
{
  int c, n, o;

  printf("static helperFunc helperTable[] = {\n");
  for (c = 0; c < ncDeps; c++)
    for (n = 0; n < nnDeps; n++)
      for (o = 0; o < noDeps; o++)
      {
	printf("    ");
	printLabel(cDeps[c], nDeps[n], oDeps[o]);
	printf("%c\n",
	      (c == ncDeps-1)&&(n == nnDeps-1)&&(o == noDeps-1) ? ' ' : ',');
      }
  printf("};\n\n");
}

printCase(int cd, int nd, int od)
{
  printf("static void\n");
  printLabel(cd, nd, od);
  printf("(xfieldP xf, int ppc, int ci, int *trans)\n{\n");
  printf("  static float  fscratch[3];\n");
  printf("  static int    iscratch;\n");
  printf("  static int    p;\n");

  if (od == PER_CONNECTION)
      printf("  GETOPACITY(ci);\n");
  
  if (cd == PER_CONNECTION)
  {
    printf("  GETCOLOR(ci);\n");
    if (nd != NONE)
      printf("  APPLY_LIGHTING;\n");

    if (od == NONE)
      printf("  SENDCOLOR;\n");
    else if (od == PER_FIELD || od == PER_CONNECTION)
      printf("  SENDCOLOROPACITY\n");
  }
  
  if (nd == PER_CONNECTION)
    printf("  SENDNORMAL(ci);\n");
  
  printf("\n  for (p = 0; p < ppc; p++) {\n");

  if (od == PER_POSITION)
    printf("    GETOPACITY(trans[p]);\n");
    
  if (cd == PER_POSITION)
  {
    printf("    GETCOLOR(trans[p]);\n");
    if (nd != NONE)
      printf("    APPLY_LIGHTING;\n");
  }
  
  if (cd == PER_POSITION)
  {
    if (od != NONE)
      printf("    SENDCOLOROPACITY;\n");
    else
      printf("    SENDCOLOR;\n");
  }
  else if (od == PER_POSITION)
    printf("    SENDCOLOROPACITY;\n");
  
  if (nd == PER_POSITION)
    printf("    SENDNORMAL(trans[p]);\n");

  printf("    SENDPOSITION(trans[p]);\n");

  printf("  }\n}\n\n");
}

main()
{
    int c, n, o;

    printGetIndex();

    for (c = 0; c < ncDeps; c++)
	for (n = 0; n < nnDeps; n++)
	    for (o = 0; o < noDeps; o++)
	        printCase(cDeps[c], nDeps[n], oDeps[o]);

    printTable();

    exit(0);
}
		
		
#endif
