/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkOpenGLPolyDataMapper.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkOpenGLPolyDataMapper.h"

#include "vtkCellArray.h"
#include "vtkCellData.h"
#include "vtkCommand.h"
#include "vtkDataArray.h"
#include "vtkFloatArray.h"
#include "vtkMatrix4x4.h"
#include "vtkObjectFactory.h"
#include "vtkOpenGLRenderer.h"
#include "vtkPlane.h"
#include "vtkPlaneCollection.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkPolygon.h"
#include "vtkProperty.h"
#include "vtkTimerLog.h"
#include "vtkTriangle.h"
#include "vtkOpenGLRenderWindow.h"
#include "vtkOpenGLTexture.h"
#include "vtkImageData.h"

#ifndef VTK_IMPLEMENT_MESA_CXX
# include "vtkOpenGL.h"
#endif

#include <math.h>


#ifndef VTK_IMPLEMENT_MESA_CXX
vtkCxxRevisionMacro(vtkOpenGLPolyDataMapper, "1.106");
vtkStandardNewMacro(vtkOpenGLPolyDataMapper);
#endif

// some definitions for what the polydata has in it
#define VTK_PDM_NORMALS            0x01
#define VTK_PDM_COLORS             0x02
#define VTK_PDM_TCOORDS            0x04
#define VTK_PDM_CELL_COLORS        0x08
#define VTK_PDM_CELL_NORMALS       0x10
#define VTK_PDM_POINT_TYPE_FLOAT   0x20
#define VTK_PDM_POINT_TYPE_DOUBLE  0x40
#define VTK_PDM_NORMAL_TYPE_FLOAT  0x80
#define VTK_PDM_NORMAL_TYPE_DOUBLE 0x100
#define VTK_PDM_TCOORD_TYPE_FLOAT  0x200
#define VTK_PDM_TCOORD_TYPE_DOUBLE 0x400
#define VTK_PDM_TCOORD_1D          0x800
#define VTK_PDM_OPAQUE_COLORS      0x1000
#define VTK_PDM_USE_FIELD_DATA     0x2000
      
// Construct empty object.
vtkOpenGLPolyDataMapper::vtkOpenGLPolyDataMapper()
{
  this->ListId = 0;
  this->TotalCells = 0;
  this->InternalColorTexture = 0;
}

// Destructor (don't call ReleaseGraphicsResources() since it is virtual
vtkOpenGLPolyDataMapper::~vtkOpenGLPolyDataMapper()
{
  if (this->LastWindow)
    {
    this->ReleaseGraphicsResources(this->LastWindow);
    }
  if (this->InternalColorTexture)
    { // Resources released previously.
    this->InternalColorTexture->Delete();
    this->InternalColorTexture = 0;
    }
}

// Release the graphics resources used by this mapper.  In this case, release
// the display list if any.
void vtkOpenGLPolyDataMapper::ReleaseGraphicsResources(vtkWindow *win)
{
  if (this->ListId && win)
    {
    win->MakeCurrent();
    glDeleteLists(this->ListId,1);
    this->ListId = 0;
    }
  this->LastWindow = NULL; 
  // We may not want to do this here.
  if (this->InternalColorTexture)
    {
    this->InternalColorTexture->ReleaseGraphicsResources(win);
    }
}

//
// Receives from Actor -> maps data to primitives
//
void vtkOpenGLPolyDataMapper::RenderPiece(vtkRenderer *ren, vtkActor *act)
{
  vtkPolyData *input= this->GetInput();
  vtkPlaneCollection *clipPlanes;
  vtkPlane *plane;
  int i, numClipPlanes;
  double planeEquation[4];

  //
  // make sure that we've been properly initialized
  //
  if (ren->GetRenderWindow()->CheckAbortStatus())
    {
    return;
    }
  
  if ( input == NULL ) 
    {
    vtkErrorMacro(<< "No input!");
    return;
    }
  else
    {
    this->InvokeEvent(vtkCommand::StartEvent,NULL);
    if (!this->Static)
      {
      input->Update();
      }
    this->InvokeEvent(vtkCommand::EndEvent,NULL);

    vtkIdType numPts = input->GetNumberOfPoints();
    if (numPts == 0)
      {
      vtkDebugMacro(<< "No points!");
      return;
      }
    } 

  if ( this->LookupTable == NULL )
    {
    this->CreateDefaultLookupTable();
    }

  // make sure our window is current
  ren->GetRenderWindow()->MakeCurrent();

  clipPlanes = this->ClippingPlanes;

  if (clipPlanes == NULL)
    {
    numClipPlanes = 0;
    }
  else
    {
    numClipPlanes = clipPlanes->GetNumberOfItems();
    if (numClipPlanes > 6)
      {
      vtkErrorMacro(<< "OpenGL guarantees at most 6 additional clipping planes");
      }
    }

  for (i = 0; i < numClipPlanes; i++)
    {
     glEnable((GLenum)(GL_CLIP_PLANE0+i));
    }

  if ( clipPlanes )
    {
    vtkMatrix4x4 *actorMatrix = vtkMatrix4x4::New();
    act->GetMatrix( actorMatrix );
    actorMatrix->Invert();
    
    double origin[4], normal[3], point[4];
    
    for (i = 0; i < numClipPlanes; i++)
      {    
      plane = (vtkPlane *)clipPlanes->GetItemAsObject(i);
      
      plane->GetOrigin(origin);
      plane->GetNormal(normal);
      
      point[0] = origin[0] + normal[0];
      point[1] = origin[1] + normal[1];
      point[2] = origin[2] + normal[2];
      
      origin[3] = point[3] = 1.0;
      
      actorMatrix->MultiplyPoint( origin, origin );
      actorMatrix->MultiplyPoint( point, point );
      
      if ( origin[3] != 1.0 )
        {
        origin[0] /= origin[3];
        origin[1] /= origin[3];
        origin[2] /= origin[3];
        }
      
      if ( point[3] != 1.0 )
        {
        point[0] /= point[3];
        point[1] /= point[3];
        point[2] /= point[3];
        }
      
      normal[0] = point[0] - origin[0];
      normal[1] = point[1] - origin[1];
      normal[2] = point[2] - origin[2];
      
      planeEquation[0] = normal[0];
      planeEquation[1] = normal[1];
      planeEquation[2] = normal[2];
      planeEquation[3] = -(planeEquation[0]*origin[0]+
                           planeEquation[1]*origin[1]+
                           planeEquation[2]*origin[2]);
      glClipPlane((GLenum)(GL_CLIP_PLANE0+i),planeEquation);
      }
    
    actorMatrix->Delete();  
    }

  // For vertex coloring, this sets this->Colors as side effect.
  // For texture map coloring, this sets ColorCoordinates
  // and ColorTextureMap as a side effect.
  // I moved this out of the conditional because it is fast.
  // Color arrays are cached. If nothing has changed, 
  // then the scalars do not have to be regenerted. 
  this->MapScalars(act->GetProperty()->GetOpacity());
  // If we are coloring by texture, then load the texture map.
  if (this->ColorTextureMap)
    {
    if (this->InternalColorTexture == 0)
      {
      this->InternalColorTexture = vtkOpenGLTexture::New();
      this->InternalColorTexture->RepeatOff();
      }
    this->InternalColorTexture->SetInput(this->ColorTextureMap);
    // Keep color from interacting with texture.
    float info[4];
    info[0] = info[1] = info[2] = info[3] = 1.0;
    glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, info );
    }

  //
  // if something has changed regenerate colors and display lists
  // if required
  //
  int noAbort=1;
  if ( this->GetMTime() > this->BuildTime || 
       input->GetMTime() > this->BuildTime ||
       act->GetProperty()->GetMTime() > this->BuildTime ||
       ren->GetRenderWindow() != this->LastWindow)
    {
    if (!this->ImmediateModeRendering && 
        !this->GetGlobalImmediateModeRendering())
      {
      this->ReleaseGraphicsResources(ren->GetRenderWindow());
      this->LastWindow = ren->GetRenderWindow();
      
      // If we are coloring by texture, then load the texture map.
      // Use Map as indicator, because texture hangs around.
      if (this->ColorTextureMap)
        {
        this->InternalColorTexture->Load(ren);
        }
      
      // get a unique display list id
      this->ListId = glGenLists(1);
      glNewList(this->ListId,GL_COMPILE);

      noAbort = this->Draw(ren,act);
      glEndList();

      // Time the actual drawing
      this->Timer->StartTimer();
      glCallList(this->ListId);
      this->Timer->StopTimer();      
      }
    else
      {
      this->ReleaseGraphicsResources(ren->GetRenderWindow());
      this->LastWindow = ren->GetRenderWindow();
      }
    if (noAbort)
      {
      this->BuildTime.Modified();
      }
    }
  // if nothing changed but we are using display lists, draw it
  else
    {
    if (!this->ImmediateModeRendering && 
        !this->GetGlobalImmediateModeRendering())
      {
      // If we are coloring by texture, then load the texture map.
      // Use Map as indicator, because texture hangs around.
      if (this->ColorTextureMap)
        {
        this->InternalColorTexture->Load(ren);
        }

      // Time the actual drawing
      this->Timer->StartTimer();
      glCallList(this->ListId);
      this->Timer->StopTimer();      
      }
    }
   
  // if we are in immediate mode rendering we always
  // want to draw the primitives here
  if (this->ImmediateModeRendering ||
      this->GetGlobalImmediateModeRendering())
    {
    // If we are coloring by texture, then load the texture map.
    // Use Map as indicator, because texture hangs around.
    if (this->ColorTextureMap)
      {
      this->InternalColorTexture->Load(ren);
      }
    // Time the actual drawing
    this->Timer->StartTimer();
    this->Draw(ren,act);
    this->Timer->StopTimer();      
    }

  this->TimeToDraw = (float)this->Timer->GetElapsedTime();

  // If the timer is not accurate enough, set it to a small
  // time so that it is not zero
  if ( this->TimeToDraw == 0.0 )
    {
    this->TimeToDraw = 0.0001;
    }

  for (i = 0; i < numClipPlanes; i++)
    {
    glDisable((GLenum)(GL_CLIP_PLANE0+i));
    }
}


//
// Helper routine which starts a poly, triangle or quad based upon
// the number of points in the polygon and whether triangles or quads
// were the last thing being drawn (we can get better performance if we
// can draw several triangles within a single glBegin(GL_TRIANGLES) or
// several quads within a single glBegin(GL_QUADS). 
//
static void vtkOpenGLBeginPolyTriangleOrQuad(GLenum aGlFunction,
                                             GLenum &previousGlFunction,
                                             int npts)
{
  if (aGlFunction == GL_POLYGON)
    {
    switch (npts)
      {
      case 3:  // Need to draw a triangle.
        if (previousGlFunction != GL_TRIANGLES)
          {
          // we were not already drawing triangles, were we drawing quads?
          if (previousGlFunction == GL_QUADS)
            {
            // we were previously drawing quads, close down the quads.
            glEnd();
            }
          // start drawing triangles
          previousGlFunction = GL_TRIANGLES;
          glBegin(GL_TRIANGLES);
          }
          break;
      case 4:  // Need to draw a quad
        if (previousGlFunction != GL_QUADS)
          {
          // we were not already drawing quads, were we drawing triangles?
          if (previousGlFunction == GL_TRIANGLES)
            {
            // we were previously drawing triangles, close down the triangles.
            glEnd();
            }
          // start drawing quads
          previousGlFunction = GL_QUADS;
          glBegin(GL_QUADS);
          }
        break;
      default:
        // if we were supposed to be drawing polygons but were really
        // drawing triangles or quads, then we need to close down the
        // triangles or quads and begin a polygon
        if (previousGlFunction != GL_INVALID_VALUE
            && previousGlFunction != GL_POLYGON)
          {
          glEnd();
          }
        previousGlFunction = GL_POLYGON;
        glBegin(aGlFunction);
        break;
      }
    }
  else if (aGlFunction == GL_POINTS)
    {
    // we are supposed to be drawing points
    if (previousGlFunction != GL_POINTS)
      {
      // We were not drawing points before this, switch to points.
      // We don't need to worry about switching from triangles or quads
      // since draw all points before drawing any polygons (i.e. in the polys
      // case we switch to triangles and quads as an optimization, there is
      // nothing to switch to that is below points).
      previousGlFunction = GL_POINTS;
      glBegin(GL_POINTS);
      }
    }
  else
    {
    previousGlFunction = aGlFunction;
    glBegin(aGlFunction);
    }
}


#define vtkDrawPointsMacro(ptype,ntype,glVertFuncs,glInitFuncs) \
{ \
  vtkIdType nPts; unsigned short count = 0; \
  ptype *points = (ptype *)voidPoints; \
  glInitFuncs \
  glBegin(GL_POINTS); \
  while (ptIds < endPtIds) \
    { \
    nPts = *ptIds; \
    ++ptIds; \
    while (nPts > 0) \
      { \
      glVertFuncs \
      ++ptIds; \
      --nPts; \
      } \
    if (++count == 10000) \
      { \
      cellNum += 10000; \
      count = 0; \
      this->UpdateProgress((double)cellNum/this->TotalCells); \
      if (ren->GetRenderWindow()->CheckAbortStatus()) \
        { \
        noAbort = 0; \
        break; \
        } \
      } \
    } \
  cellNum += count; \
  glEnd(); \
}

#define vtkDrawPrimsMacro(ptype,ntype,prim,glVertFuncs,glInitFuncs) \
{ \
  vtkIdType nPts; unsigned short count = 0; \
  ptype *points = (ptype *)voidPoints; \
  glInitFuncs \
  while (ptIds < endPtIds) \
    { \
    nPts = *ptIds; \
    ++ptIds; \
    glBegin(prim); \
    while (nPts > 0) \
      { \
      glVertFuncs \
      ++ptIds; \
      --nPts; \
      } \
    glEnd(); \
    if (++count == 10000) \
      { \
      cellNum += 10000; \
      count = 0; \
      this->UpdateProgress((double)cellNum/this->TotalCells); \
      if (ren->GetRenderWindow()->CheckAbortStatus()) \
        { \
        noAbort = 0; \
        break; \
        } \
      } \
    } \
  cellNum += count; \
}

#define vtkDrawPolysMacro(ptype,ntype,ttype,prim,glVertFuncs,glCellFuncs,glInitFuncs) \
{ \
  vtkIdType nPts; unsigned short count = 0; \
  ptype *points = (ptype *)voidPoints; \
  GLenum previousGlFunction=GL_INVALID_VALUE; \
  glInitFuncs \
  while (ptIds < endPtIds) \
    { \
    nPts = *ptIds; \
    ++ptIds; \
    vtkOpenGLBeginPolyTriangleOrQuad( prim, previousGlFunction, nPts ); \
    glCellFuncs \
    while (nPts > 0) \
      { \
      glVertFuncs \
      ++ptIds; \
      --nPts; \
      } \
    if (++count == 10000) \
      { \
      cellNum += 10000; \
      count = 0; \
      this->UpdateProgress((double)cellNum/this->TotalCells); \
      if (ren->GetRenderWindow()->CheckAbortStatus()) \
        { \
        noAbort = 0; \
        break; \
        } \
      } \
    if ((previousGlFunction != GL_TRIANGLES)  \
        && (previousGlFunction != GL_QUADS)   \
        && (previousGlFunction != GL_POINTS)) \
      {  \
      glEnd(); \
      } \
    } \
  cellNum += count; \
  if ((previousGlFunction == GL_TRIANGLES)  \
      || (previousGlFunction == GL_QUADS)   \
      || (previousGlFunction == GL_POINTS)) \
    { \
    glEnd(); \
    } \
}

#define vtkDrawStripLinesMacro(ptype,ntype,ttype,prim,glVertFuncs,glCellFuncs,glInitFuncs) \
{ \
  vtkIdType nPts; \
  ptype *points = (ptype *)voidPoints; \
  vtkIdType *savedPtIds = ptIds; \
  glInitFuncs \
  while (ptIds < endPtIds) \
    { \
    glBegin(prim); \
    nPts = *ptIds; \
    ++ptIds; \
    glCellFuncs \
    while (nPts > 0) \
      { \
      glVertFuncs \
      ptIds += 2; \
      nPts -= 2; \
      } \
    glEnd(); \
    ptIds += nPts; /* nPts could be 0 or -1 here */ \
    } \
  ptIds = savedPtIds; \
  while (ptIds < endPtIds) \
    { \
    glBegin(prim); \
    nPts = *ptIds; \
    ++ptIds; \
    glCellFuncs \
    ++ptIds; \
    --nPts; \
    while (nPts > 0) \
      { \
      glVertFuncs \
      ptIds += 2; \
      nPts -= 2; \
      } \
    glEnd(); \
    ptIds += nPts; /* nPts could be 0 or -1 here */ \
    } \
}

void vtkOpenGLPolyDataMapper::DrawPoints(int idx,
                                         vtkPoints *p, 
                                         vtkDataArray *n,
                                         vtkUnsignedCharArray *c,
                                         vtkDataArray *t,
                                         vtkIdType &cellNum,
                                         int &noAbort,
                                         vtkCellArray *ca,
                                         vtkRenderer *ren)
{
  void *voidPoints = p->GetVoidPointer(0);
  void *voidNormals = 0;
  unsigned char *colors = 0;
  if (ca->GetNumberOfCells() == 0)
    {
    return;
    }
  if (n)
    {
    voidNormals = n->GetVoidPointer(0);
    }
  if (c)
    {
    colors = c->GetPointer(0);
    }
  
  vtkIdType *ptIds = ca->GetPointer();
  vtkIdType *endPtIds = ptIds + ca->GetNumberOfConnectivityEntries();
    
  // draw all the elements, use fast path if available
  switch (idx)
    {
    case VTK_PDM_POINT_TYPE_FLOAT:
      vtkDrawPointsMacro(float, float, glVertex3fv(points + 3**ptIds);,;);
      break;
    case VTK_PDM_POINT_TYPE_DOUBLE:
      vtkDrawPointsMacro(double, float, glVertex3dv(points + 3**ptIds);,;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT|VTK_PDM_NORMAL_TYPE_FLOAT|VTK_PDM_NORMALS:
      vtkDrawPointsMacro(float, float, 
                         glNormal3fv(normals + 3**ptIds);
                         glVertex3fv(points + 3**ptIds);,
                         float *normals = (float *)voidNormals;);

      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_COLORS:
      vtkDrawPointsMacro(float, float, 
                         glColor4ubv(colors + 4**ptIds);
                         glVertex3fv(points + 3**ptIds);,;);
      
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS:
      vtkDrawPointsMacro(float, float, 
                         glColor3ubv(colors + 4**ptIds);
                         glVertex3fv(points + 3**ptIds);,;);      
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT |
      VTK_PDM_NORMALS | VTK_PDM_COLORS:
      vtkDrawPointsMacro(float, float, 
                         glNormal3fv(normals + 3**ptIds);
                         glColor4ubv(colors + 4**ptIds);
                         glVertex3fv(points + 3**ptIds);,
                         float *normals = (float *)voidNormals;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT |
      VTK_PDM_NORMALS | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS:
      vtkDrawPointsMacro(float, float, 
                         glNormal3fv(normals + 3**ptIds);
                         glColor3ubv(colors + 4**ptIds);
                         glVertex3fv(points + 3**ptIds);,
                         float *normals = (float *)voidNormals;);
      break;
    default:
    {
    int j;
    vtkIdType *pts = 0;
    vtkIdType npts = 0;
    unsigned short count = 0;
    glBegin(GL_POINTS);
    for (ca->InitTraversal(); noAbort && ca->GetNextCell(npts,pts); 
         count++)
      { 
      for (j = 0; j < npts; j++) 
        {
        if (c)
          {
          if (idx & 0x08)
            {
            glColor4ubv(c->GetPointer(cellNum << 2));
            }
          else
            {
            glColor4ubv(c->GetPointer(pts[j]<< 2));
            }
          }
        if (t)
          {
          if (idx & VTK_PDM_TCOORD_1D)
            {
            glTexCoord1dv(t->GetTuple(pts[j]));
            }
          else
            {
            glTexCoord2dv(t->GetTuple(pts[j]));
            }
          }
        if (n)
          {
          if (idx & 0x10)
            {
            glNormal3dv(n->GetTuple(cellNum));
            }
          else
            {
            glNormal3dv(n->GetTuple(pts[j]));
            }
          }
        glVertex3dv(p->GetPoint(pts[j]));
        }
      
      // check for abort condition
      if (count == 10000)
        {
        count = 0;
        // report progress
        this->UpdateProgress((double)cellNum/this->TotalCells);
        if (ren->GetRenderWindow()->CheckAbortStatus())
          {
          noAbort = 0;
          }
        }
      ++cellNum;
      }
    glEnd();
    }  
    }
}


void vtkOpenGLPolyDataMapper::DrawLines(int idx,
                                        vtkPoints *p, 
                                        vtkDataArray *n,
                                        vtkUnsignedCharArray *c,
                                        vtkDataArray *t,
                                        vtkIdType &cellNum,
                                        int &noAbort,
                                        vtkCellArray *ca,
                                        vtkRenderer *ren)
{
  void *voidPoints = p->GetVoidPointer(0);
  void *voidNormals = 0;
  void *voidTCoords = 0;
  unsigned char *colors = 0;
  if (ca->GetNumberOfCells() == 0)
    {
    return;
    }
  if (n)
    {
    voidNormals = n->GetVoidPointer(0);
    }
  if (t)
    {
    voidTCoords = t->GetVoidPointer(0);
    }
  if (c)
    {
    colors = c->GetPointer(0);
    }
  vtkIdType *ptIds = ca->GetPointer();
  vtkIdType *endPtIds = ptIds + ca->GetNumberOfConnectivityEntries();
  
  // draw all the elements, use fast path if available
  switch (idx)
    {
    case VTK_PDM_POINT_TYPE_FLOAT:
      vtkDrawPrimsMacro(float, float, GL_LINE_STRIP, 
                        glVertex3fv(points + 3**ptIds);,;);
      break;
    case VTK_PDM_POINT_TYPE_DOUBLE:
      vtkDrawPrimsMacro(double, float, GL_LINE_STRIP,
                        glVertex3dv(points + 3**ptIds);,;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT|VTK_PDM_NORMAL_TYPE_FLOAT|VTK_PDM_NORMALS:
      vtkDrawPrimsMacro(float, float, GL_LINE_STRIP,
                        glNormal3fv(normals + 3**ptIds);
                        glVertex3fv(points + 3**ptIds);,
                        float *normals = (float *)voidNormals;);
      
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_COLORS:
      vtkDrawPrimsMacro(float, float, GL_LINE_STRIP,
                        glColor4ubv(colors + 4**ptIds);
                        glVertex3fv(points + 3**ptIds);,;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS:
      vtkDrawPrimsMacro(float, float, GL_LINE_STRIP,
                        glColor3ubv(colors + 4**ptIds);
                        glVertex3fv(points + 3**ptIds);,;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT | 
      VTK_PDM_NORMALS | VTK_PDM_COLORS:
      vtkDrawPrimsMacro(float, float, GL_LINE_STRIP,
                        glNormal3fv(normals + 3**ptIds);
                        glColor4ubv(colors + 4**ptIds);
                        glVertex3fv(points + 3**ptIds);,
                        float *normals = (float *)voidNormals;
        );
    break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT | 
      VTK_PDM_NORMALS | VTK_PDM_COLORS  | VTK_PDM_OPAQUE_COLORS:
      vtkDrawPrimsMacro(float, float, GL_LINE_STRIP,
                        glNormal3fv(normals + 3**ptIds);
                        glColor3ubv(colors + 4**ptIds);
                        glVertex3fv(points + 3**ptIds);,
                        float *normals = (float *)voidNormals;
        );
    break;
    case VTK_PDM_POINT_TYPE_FLOAT | 
      VTK_PDM_TCOORD_TYPE_FLOAT | VTK_PDM_TCOORD_1D | VTK_PDM_TCOORDS:
      vtkDrawPrimsMacro(float, float, GL_LINE_STRIP, 
                        glTexCoord1fv(tcoords + *ptIds);
                        glVertex3fv(points + 3**ptIds);,
                        float *tcoords = (float *)voidTCoords;
        );
    break;
    case VTK_PDM_POINT_TYPE_FLOAT | 
      VTK_PDM_NORMAL_TYPE_FLOAT | VTK_PDM_NORMALS |
      VTK_PDM_TCOORD_TYPE_FLOAT | VTK_PDM_TCOORD_1D | VTK_PDM_TCOORDS:
      vtkDrawPrimsMacro(float, float, GL_LINE_STRIP, 
                        glNormal3fv(normals + 3**ptIds);
                        glTexCoord1fv(tcoords + *ptIds);
                        glVertex3fv(points + 3**ptIds);,
                        float *tcoords = (float *)voidTCoords;
                        float *normals = (float *)voidNormals;
        );
    break;
    default:
    {
    int j;
    vtkIdType *pts = 0;
    vtkIdType npts = 0;
    unsigned short count = 0;
    for (ca->InitTraversal(); noAbort && ca->GetNextCell(npts,pts); 
         count++)
      { 
      glBegin(GL_LINE_STRIP);
      for (j = 0; j < npts; j++) 
        {
        if (c)
          {
          if (idx & 0x08)
            {
            glColor4ubv(c->GetPointer(cellNum << 2));
            }
          else
            {
            glColor4ubv(c->GetPointer(pts[j] << 2));
            }
          }
        if (t)
          {
          if (idx & VTK_PDM_TCOORD_1D)
            {
            glTexCoord1dv(t->GetTuple(pts[j]));
            }
          else
            {
            glTexCoord2dv(t->GetTuple(pts[j]));
            }
          }
        if (n)
          {
          if (idx & 0x10)
            {
            glNormal3dv(n->GetTuple(cellNum));
            }
          else
            {
            glNormal3dv(n->GetTuple(pts[j]));
            }
          }
        glVertex3dv(p->GetPoint(pts[j]));
        }
      glEnd();
      
      // check for abort condition
      if (count == 10000)
        {
        count = 0;
        // report progress
        this->UpdateProgress((double)cellNum/this->TotalCells);
        if (ren->GetRenderWindow()->CheckAbortStatus())
          {
          noAbort = 0;
          }
        }
      ++cellNum;
      }
    }  
    }
}









#define PolyNormal \
{ double polyNorm[3]; vtkPolygon::ComputeNormal(p,nPts,ptIds,polyNorm); glNormal3dv(polyNorm); }

void vtkOpenGLPolyDataMapper::DrawPolygons(int idx,
                                         vtkPoints *p, 
                                         vtkDataArray *n,
                                         vtkUnsignedCharArray *c,
                                         vtkDataArray *t,
                                         vtkIdType &cellNum,
                                         int &noAbort,
                                         GLenum rep,
                                         vtkCellArray *ca,
                                         vtkRenderer *ren)
{
  void *voidPoints = p->GetVoidPointer(0);
  void *voidNormals = 0;
  void *voidTCoords = 0;
  unsigned char *colors = 0;
  if (ca->GetNumberOfCells() == 0)
    {
    return;
    }
  if (n)
    {
    voidNormals = n->GetVoidPointer(0);
    }
  if (c)
    {
    colors = c->GetPointer(0);
    // if these are cell colors then advance to the first cell
    if (idx & VTK_PDM_CELL_COLORS)
      {
      colors = colors + cellNum*4;
      }
    }
  if (t)
    {
    voidTCoords = t->GetVoidPointer(0);
    }
  vtkIdType *ptIds = ca->GetPointer();
  vtkIdType *endPtIds = ptIds + ca->GetNumberOfConnectivityEntries();

  // draw all the elements, use fast path if available
  switch (idx)
    {
    case VTK_PDM_POINT_TYPE_FLOAT:
      vtkDrawPolysMacro(float, float, float, rep, 
                        glVertex3fv(points + 3**ptIds);, 
                        PolyNormal,;);
      break;
    case VTK_PDM_POINT_TYPE_DOUBLE:
      vtkDrawPolysMacro(double, float, float, rep, 
                        glVertex3dv(points + 3**ptIds);,
                        PolyNormal,;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT|VTK_PDM_NORMAL_TYPE_FLOAT|VTK_PDM_NORMALS:
      vtkDrawPolysMacro(float, float, float, rep,
                        glNormal3fv(normals + 3**ptIds);
                        glVertex3fv(points + 3**ptIds);,;,
                        float *normals = (float *)voidNormals;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_COLORS:
      vtkDrawPolysMacro(float, float, float, rep,
                        glColor4ubv(colors + 4**ptIds);
                        glVertex3fv(points + 3**ptIds);, 
                        PolyNormal,;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_COLORS  | VTK_PDM_OPAQUE_COLORS:
      vtkDrawPolysMacro(float, float, float, rep, 
                        glColor3ubv(colors + 4**ptIds);
                        glVertex3fv(points + 3**ptIds);, 
                        PolyNormal,;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT | 
      VTK_PDM_NORMALS | VTK_PDM_COLORS:
      vtkDrawPolysMacro(float, float, float, rep, 
                        glNormal3fv(normals + 3**ptIds);
                        glColor4ubv(colors + 4**ptIds);
                        glVertex3fv(points + 3**ptIds);,;,
                        float *normals = (float *)voidNormals;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT | 
      VTK_PDM_NORMALS | VTK_PDM_COLORS  | VTK_PDM_OPAQUE_COLORS:
      vtkDrawPolysMacro(float, float, float, rep, 
                        glNormal3fv(normals + 3**ptIds); 
                        glColor3ubv(colors + 4**ptIds);
                        glVertex3fv(points + 3**ptIds);,;, 
                        float *normals = (float *)voidNormals;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT | VTK_PDM_NORMALS | 
         VTK_PDM_TCOORD_TYPE_FLOAT | VTK_PDM_TCOORD_1D | VTK_PDM_TCOORDS:
      vtkDrawPolysMacro(float, float, float, rep, 
                        glNormal3fv(normals + 3**ptIds);
                        glTexCoord1fv(tcoords + *ptIds);
                        glVertex3fv(points + 3**ptIds);,;,
                        float *normals = (float *)voidNormals;
                        float *tcoords = (float *)voidTCoords;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT | VTK_PDM_CELL_NORMALS | 
         VTK_PDM_TCOORD_TYPE_FLOAT | VTK_PDM_TCOORD_1D | VTK_PDM_TCOORDS:
      vtkDrawPolysMacro(float, float, float, rep, 
                        glTexCoord1fv(tcoords + *ptIds);
                        glVertex3fv(points + 3**ptIds);,
                        glNormal3fv(normals); normals += 3;,
                        float *tcoords = (float *)voidTCoords;
                        float *normals = (float *)voidNormals;
                        normals += cellNum*3;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | 
         VTK_PDM_TCOORD_TYPE_FLOAT | VTK_PDM_TCOORD_1D | VTK_PDM_TCOORDS:
      vtkDrawPolysMacro(float, float, float, rep, 
                        glTexCoord1fv(tcoords + *ptIds);
                        glVertex3fv(points + 3**ptIds);,
                        PolyNormal;,
                        float *tcoords = (float *)voidTCoords;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT | 
        VTK_PDM_NORMALS | VTK_PDM_TCOORD_TYPE_FLOAT | VTK_PDM_TCOORDS:
      vtkDrawPolysMacro(float, float, float, rep, 
                        glNormal3fv(normals + 3**ptIds);
                        glTexCoord2fv(tcoords + 2**ptIds);
                        glVertex3fv(points + 3**ptIds);,;,
                        float *normals = (float *)voidNormals;
                        float *tcoords = (float *)voidTCoords;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT|VTK_PDM_NORMAL_TYPE_FLOAT|
      VTK_PDM_CELL_NORMALS:
      vtkDrawPolysMacro(float, float, float, rep, 
                        glVertex3fv(points + 3**ptIds);, 
                        glNormal3fv(normals); normals += 3;,
                        float *normals = (float *)voidNormals;
                        normals += cellNum*3;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT |
      VTK_PDM_CELL_NORMALS | VTK_PDM_COLORS:
      vtkDrawPolysMacro(float, float, float, rep, 
                        glColor4ubv(colors + 4**ptIds);
                        glVertex3fv(points + 3**ptIds);,
                        glNormal3fv(normals); normals += 3;,
                        float *normals = (float *)voidNormals;
                        normals += cellNum*3;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT |
      VTK_PDM_CELL_NORMALS | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS:
      vtkDrawPolysMacro(float, float, float, rep,
                        glColor3ubv(colors + 4**ptIds);
                        glVertex3fv(points + 3**ptIds);,
                        glNormal3fv(normals); normals += 3;,
                        float *normals = (float *)voidNormals;
                        normals += cellNum*3;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT | 
      VTK_PDM_NORMALS | VTK_PDM_COLORS | VTK_PDM_CELL_COLORS:
      vtkDrawPolysMacro(float, float, float, rep, 
                        glNormal3fv(normals + 3**ptIds);
                        glVertex3fv(points + 3**ptIds);,
                        glColor4ubv(colors); colors += 4;,
                        float *normals = (float *)voidNormals;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT | 
      VTK_PDM_NORMALS | VTK_PDM_COLORS  | VTK_PDM_OPAQUE_COLORS | 
      VTK_PDM_CELL_COLORS:
      vtkDrawPolysMacro(float, float, float, rep,
                        glNormal3fv(normals + 3**ptIds);
                        glVertex3fv(points + 3**ptIds);,
                        glColor3ubv(colors); colors += 4;,
                        float *normals = (float *)voidNormals;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT | 
      VTK_PDM_CELL_NORMALS | VTK_PDM_COLORS | VTK_PDM_CELL_COLORS:
      vtkDrawPolysMacro(float, float, float, rep, 
                        glVertex3fv(points + 3**ptIds);,
                        glNormal3fv(normals); normals += 3;
                        glColor4ubv(colors); colors += 4;,
                        float *normals = (float *)voidNormals;
                        normals += cellNum*3;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT | 
      VTK_PDM_CELL_NORMALS | VTK_PDM_COLORS  | VTK_PDM_OPAQUE_COLORS | 
      VTK_PDM_CELL_COLORS:
      vtkDrawPolysMacro(float, float, float, rep,
                        glVertex3fv(points + 3**ptIds);,
                        glNormal3fv(normals); normals += 3;
                        glColor3ubv(colors); colors += 4;,
                        float *normals = (float *)voidNormals;
                        normals += cellNum*3;);
      break;
    default:
    {
    int j;
    vtkIdType *pts = 0;
    vtkIdType npts = 0;
    unsigned short count = 0;
    for (ca->InitTraversal(); noAbort && ca->GetNextCell(npts,pts); 
         count++)
      { 
      glBegin(rep);
      if (!n)
        { 
        double polyNorm[3]; 
        vtkPolygon::ComputeNormal(p,npts,pts,polyNorm); 
        glNormal3dv(polyNorm);
        }
      for (j = 0; j < npts; j++) 
        {
        if (c)
          {
          if (idx & VTK_PDM_CELL_COLORS)
            {
            glColor4ubv(c->GetPointer(cellNum << 2));
            }
          else
            {
            glColor4ubv(c->GetPointer(pts[j] << 2));
            }
          }
        if (t)
          {
          if (idx & VTK_PDM_TCOORD_1D)
            {
            glTexCoord1dv(t->GetTuple(pts[j]));
            }
          else
            {
            glTexCoord2dv(t->GetTuple(pts[j]));
            }
          }
        if (n)
          {
          if (idx & VTK_PDM_CELL_NORMALS)
            {
            glNormal3dv(n->GetTuple(cellNum));
            }
          else
            {
            glNormal3dv(n->GetTuple(pts[j]));
            }
          }
        glVertex3dv(p->GetPoint(pts[j]));
        }
      glEnd();
      
      // check for abort condition
      if (count == 10000)
        {
        count = 0;
        // report progress
        this->UpdateProgress((double)cellNum/this->TotalCells);
        if (ren->GetRenderWindow()->CheckAbortStatus())
          {
          noAbort = 0;
          }
        }
      ++cellNum;
      }
    }  
    }
}

// fix refs here
#define TStripNormal \
if ( vcount > 2) \
{ \
  if (vcount % 2) \
    { \
    normIdx[0] = ptIds[-2]; normIdx[1] = ptIds[0]; normIdx[2] = ptIds[-1]; \
    vtkTriangle::ComputeNormal(p, 3, normIdx, polyNorm); \
    } \
  else \
    { \
    normIdx[0] = ptIds[-2]; normIdx[1] = ptIds[-1]; normIdx[2] = ptIds[0]; \
    vtkTriangle::ComputeNormal(p, 3, normIdx, polyNorm); \
    } \
  glNormal3dv(polyNorm); \
} \
vcount++; 

#define TStripNormalStart \
  vtkTriangle::ComputeNormal(p, 3, ptIds, polyNorm); \
  glNormal3dv(polyNorm); int vcount = 0;

void vtkOpenGLPolyDataMapper::DrawTStrips(int idx,
                                        vtkPoints *p, 
                                        vtkDataArray *n,
                                        vtkUnsignedCharArray *c,
                                        vtkDataArray *t,
                                        vtkIdType &cellNum,
                                        int &noAbort,
                                        GLenum rep,
                                        vtkCellArray *ca,
                                        vtkRenderer *ren)
{
  void *voidPoints = p->GetVoidPointer(0);
  void *voidNormals = 0;
  void *voidTCoords = 0;
  unsigned char *colors = 0;
  double polyNorm[3];
  vtkIdType normIdx[3];
  
  if (ca->GetNumberOfCells() == 0)
    {
    return;
    }
  if (n)
    {
    voidNormals = n->GetVoidPointer(0);
    }
  if (c)
    {
    colors = c->GetPointer(0);
    }
  if (t)
    {
    voidTCoords = t->GetVoidPointer(0);
    }
  vtkIdType *ptIds = ca->GetPointer();
  vtkIdType *endPtIds = ptIds + ca->GetNumberOfConnectivityEntries();

  // draw all the elements, use fast path if available
  switch (idx)
    {
    case VTK_PDM_POINT_TYPE_FLOAT:
      vtkDrawPolysMacro(float, float, float, rep, 
                        TStripNormal glVertex3fv(points + 3**ptIds);, 
                        TStripNormalStart,;);
      break;
    case VTK_PDM_POINT_TYPE_DOUBLE:
      vtkDrawPolysMacro(double, float, float, rep, 
                        TStripNormal glVertex3dv(points + 3**ptIds);,
                        TStripNormalStart,;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT|VTK_PDM_NORMAL_TYPE_FLOAT|VTK_PDM_NORMALS:
      vtkDrawPolysMacro(float, float, float, rep,
                        glNormal3fv(normals + 3**ptIds);
                        glVertex3fv(points + 3**ptIds);,;,
                        float *normals = (float *)voidNormals;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_COLORS:
      vtkDrawPolysMacro(float, float, float, rep, 
                        TStripNormal 
                        glColor4ubv(colors + (*ptIds << 2));
                        glVertex3fv(points + 3**ptIds);,
                        TStripNormalStart,;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_COLORS  | VTK_PDM_OPAQUE_COLORS:
      vtkDrawPolysMacro(float, float, float, rep, 
                        TStripNormal 
                        glColor3ubv(colors + (*ptIds << 2));
                        glVertex3fv(points + 3**ptIds);,
                        TStripNormalStart,;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT | 
      VTK_PDM_NORMALS | VTK_PDM_COLORS:
      vtkDrawPolysMacro(float, float, float, rep, 
                        glNormal3fv(normals + 3**ptIds);
                        glColor4ubv(colors + (*ptIds << 2));
                        glVertex3fv(points + 3**ptIds);,;, 
                        float *normals = (float *)voidNormals;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT | 
      VTK_PDM_NORMALS | VTK_PDM_COLORS  | VTK_PDM_OPAQUE_COLORS:
      vtkDrawPolysMacro(float, float, float, rep, 
                        glNormal3fv(normals + 3**ptIds);
                        glColor3ubv(colors + (*ptIds << 2));
                        glVertex3fv(points + 3**ptIds);,;, 
                        float *normals = (float *)voidNormals;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT | VTK_PDM_NORMALS |
        VTK_PDM_TCOORD_1D | VTK_PDM_TCOORD_TYPE_FLOAT | VTK_PDM_TCOORDS:
      vtkDrawPolysMacro(float, float, float, rep, 
                        glNormal3fv(normals + 3**ptIds);
                        glTexCoord1fv(tcoords + *ptIds);
                        glVertex3fv(points + 3**ptIds);,;, 
                        float *normals = (float *)voidNormals;
                        float *tcoords = (float *)voidTCoords;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT | 
        VTK_PDM_NORMALS | VTK_PDM_TCOORD_TYPE_FLOAT | VTK_PDM_TCOORDS:
      vtkDrawPolysMacro(float, float, float, rep, 
                        glNormal3fv(normals + 3**ptIds);
                        glTexCoord2fv(tcoords + 2**ptIds);
                        glVertex3fv(points + 3**ptIds);,;, 
                        float *normals = (float *)voidNormals;
                        float *tcoords = (float *)voidTCoords;);
      break;
    default:
    {
    int j;
    vtkIdType nPts = 0;
    unsigned short count = 0;
    unsigned long coloroffset = cellNum;
    for (ca->InitTraversal(); noAbort && ca->GetNextCell(nPts,ptIds); 
         count++)
      { 
      glBegin(rep);
      vtkTriangle::ComputeNormal(p, 3, ptIds, polyNorm);
      glNormal3dv(polyNorm);
      for (j = 0; j < nPts; j++) 
        {
        if (c)
          {
          if ( (idx & VTK_PDM_USE_FIELD_DATA) && j>=2 )
            {
            glColor4ubv(c->GetPointer(coloroffset << 2));
            coloroffset++;
            }
          else if (idx & VTK_PDM_CELL_COLORS)
            {
            glColor4ubv(c->GetPointer(cellNum << 2));
            }
          else
            {
            glColor4ubv(c->GetPointer(ptIds[j] << 2));
            }
          }
        if (t)
          {
          if (idx & VTK_PDM_TCOORD_1D)
            {
            glTexCoord1dv(t->GetTuple(ptIds[j]));
            }
          else
            {
            glTexCoord2dv(t->GetTuple(ptIds[j]));
            }
          }
        if (n)
          {
          if (idx & VTK_PDM_CELL_NORMALS)
            {
            glNormal3dv(n->GetTuple(cellNum));
            }
          else
            {
            glNormal3dv(n->GetTuple(ptIds[j]));
            }
          }
        else
          {
          if (j >= 2) 
            { 
            if (j % 2) 
              { 
              normIdx[0] = ptIds[j-2]; normIdx[1] = ptIds[j]; 
              normIdx[2] = ptIds[j-1]; 
              vtkTriangle::ComputeNormal(p, 3, normIdx, polyNorm); 
              } 
            else 
              { 
              normIdx[0] = ptIds[j-2]; normIdx[1] = ptIds[j-1]; 
              normIdx[2] = ptIds[j]; 
              vtkTriangle::ComputeNormal(p, 3, normIdx, polyNorm); 
              } 
            } 
          glNormal3dv(polyNorm);
          }
        glVertex3dv(p->GetPoint(ptIds[j]));
        }
      glEnd();
      
      // check for abort condition
      if (count == 10000)
        {
        count = 0;
        // report progress
        this->UpdateProgress((double)cellNum/this->TotalCells);
        if (ren->GetRenderWindow()->CheckAbortStatus())
          {
          noAbort = 0;
          }
        }
      ++cellNum;
      }
    }  
    }
}

void vtkOpenGLPolyDataMapperDrawTStripLines(int idx,
                                            vtkPoints *p, 
                                            vtkDataArray *n,
                                            vtkUnsignedCharArray *c,
                                            vtkDataArray *t,
                                            vtkIdType &cellNum,
                                            int &noAbort,
                                            GLenum rep,
                                            vtkCellArray *ca,
                                            vtkRenderer *ren)
{
  void *voidPoints = p->GetVoidPointer(0);
  void *voidNormals = 0;
  void *voidTCoords = 0;
  unsigned char *colors = 0;
  double polyNorm[3];
  vtkIdType normIdx[3];
  
  if (n)
    {
    voidNormals = n->GetVoidPointer(0);
    }
  if (c)
    {
    colors = c->GetPointer(0);
    }
  if (t)
    {
    voidTCoords = t->GetVoidPointer(0);
    }
  vtkIdType *ptIds = ca->GetPointer();
  vtkIdType *endPtIds = ptIds + ca->GetNumberOfConnectivityEntries();

  // draw all the elements, use fast path if available
  switch (idx)
    {
    case VTK_PDM_POINT_TYPE_FLOAT:
      vtkDrawStripLinesMacro(float, float, float, rep, 
                             TStripNormal; glVertex3fv(points + 3**ptIds);, 
                             TStripNormalStart,;);
      break;
    case VTK_PDM_POINT_TYPE_DOUBLE:
      vtkDrawStripLinesMacro(double, float, float, rep, 
                        TStripNormal glVertex3dv(points + 3**ptIds);, 
                        TStripNormalStart,;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT|VTK_PDM_NORMAL_TYPE_FLOAT|VTK_PDM_NORMALS:
      vtkDrawStripLinesMacro(float, float, float, rep, 
                             glNormal3fv(normals + 3**ptIds);
                             glVertex3fv(points + 3**ptIds);,;,
                             float *normals = (float *)voidNormals;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_COLORS:
      vtkDrawStripLinesMacro(float, float, float, rep, 
                             TStripNormal;
                             glColor4ubv(colors + 4**ptIds);
                             glVertex3fv(points + 3**ptIds);,
                             TStripNormalStart,;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS:
      vtkDrawStripLinesMacro(float, float, float, rep, 
                             TStripNormal;
                             glColor3ubv(colors + 4**ptIds);
                             glVertex3fv(points + 3**ptIds);, 
                             TStripNormalStart,;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT | 
      VTK_PDM_NORMALS | VTK_PDM_COLORS:
      vtkDrawStripLinesMacro(float, float, float, rep, 
                             glNormal3fv(normals + 3**ptIds);
                             glColor4ubv(colors + 4**ptIds);
                             glVertex3fv(points + 3**ptIds);,;,
                             float *normals = (float *)voidNormals;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT | 
      VTK_PDM_NORMALS | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS:
      vtkDrawStripLinesMacro(float, float, float, rep, 
                             glNormal3fv(normals + 3**ptIds); 
                             glColor3ubv(colors + 4**ptIds);
                             glVertex3fv(points + 3**ptIds);,;,
                             float *normals = (float *)voidNormals;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT | VTK_PDM_NORMALS | 
      VTK_PDM_TCOORD_TYPE_FLOAT | VTK_PDM_TCOORD_1D | VTK_PDM_TCOORDS:
      vtkDrawStripLinesMacro(float, float, float, rep, 
                             glNormal3fv(normals + 3**ptIds);
                             glTexCoord1fv(tcoords + *ptIds);
                             glVertex3fv(points + 3**ptIds);,;,
                             float *normals = (float *)voidNormals;
                             float *tcoords = (float *)voidTCoords;);
      break;
    case VTK_PDM_POINT_TYPE_FLOAT | VTK_PDM_NORMAL_TYPE_FLOAT | 
        VTK_PDM_NORMALS | VTK_PDM_TCOORD_TYPE_FLOAT | VTK_PDM_TCOORDS:
      vtkDrawStripLinesMacro(float, float, float, rep, 
                             glNormal3fv(normals + 3**ptIds);
                             glTexCoord2fv(tcoords + 2**ptIds);
                             glVertex3fv(points + 3**ptIds);,;,
                             float *normals = (float *)voidNormals;
                             float *tcoords = (float *)voidTCoords;);
      break;
    default:
    {
    int j;
    vtkIdType nPts = 0;
    int count = 0;
    unsigned long coloroffset = cellNum;
    for (ca->InitTraversal(); noAbort && ca->GetNextCell(nPts,ptIds); 
         count++)
      { 
      glBegin(rep);
      for (j = 0; j < nPts; j += 2) 
        {
        if (c)
          {
          if ( (idx & VTK_PDM_USE_FIELD_DATA) && j >= 2)
            {
            glColor4ubv(c->GetPointer((coloroffset+j) << 2));
            }
          else if (idx & VTK_PDM_CELL_COLORS)
            {
            glColor4ubv(c->GetPointer(cellNum << 2));
            }
          else
            {
            glColor4ubv(c->GetPointer(ptIds[j] << 2));
            }
          }
        if (t)
          {
          if (idx & VTK_PDM_TCOORD_1D)
            {
            glTexCoord1dv(t->GetTuple(ptIds[j]));
            }
          else
            {
            glTexCoord2dv(t->GetTuple(ptIds[j]));
            }
          }
        if (n)
          {
          if (idx & VTK_PDM_CELL_NORMALS)
            {
            glNormal3dv(n->GetTuple(cellNum));
            }
          else
            {
            glNormal3dv(n->GetTuple(ptIds[j]));
            }
          }
        else
          {
          if ( j == 0 )
            {
            vtkTriangle::ComputeNormal(p, 3, ptIds, polyNorm);
            }
          else
            {
            normIdx[0] = ptIds[j-2]; normIdx[1] = ptIds[j-1]; 
            normIdx[2] = ptIds[j]; 
            vtkTriangle::ComputeNormal(p, 3, normIdx, polyNorm);
            }
          glNormal3dv(polyNorm);
          }
        glVertex3dv(p->GetPoint(ptIds[j]));
        }
      glEnd();
      
      glBegin(rep);
      for (j = 1; j < nPts; j += 2) 
        {
        if (c)
          {
          if ( (idx & VTK_PDM_USE_FIELD_DATA) && j >= 2)
            {
            glColor4ubv(c->GetPointer((coloroffset+j) << 2));
            }
          else if (idx & VTK_PDM_CELL_COLORS)
            {
            glColor4ubv(c->GetPointer(cellNum << 2));
            }
          else
            {
            glColor4ubv(c->GetPointer(ptIds[j] << 2));
            }
          }
        if (t)
          {
          if (idx & VTK_PDM_TCOORD_1D)
            {
            glTexCoord1dv(t->GetTuple(ptIds[j]));
            }
          else
            {
            glTexCoord2dv(t->GetTuple(ptIds[j]));
            }
          }
        if (n)
          {
          if (idx & VTK_PDM_CELL_NORMALS)
            {
            glNormal3dv(n->GetTuple(cellNum));
            }
          else
            {
            glNormal3dv(n->GetTuple(ptIds[j]));
            }
          }
        else
          {
          if (j == 1)
            {
            vtkTriangle::ComputeNormal(p, 3, ptIds, polyNorm);
            }
          else
            {
            normIdx[0] = ptIds[j-2]; normIdx[1] = ptIds[j]; 
            normIdx[2] = ptIds[j-1]; 
            vtkTriangle::ComputeNormal(p, 3, normIdx, polyNorm);
            }
          glNormal3dv(polyNorm);
          }
        glVertex3dv(p->GetPoint(ptIds[j]));
        }
      glEnd();

      // check for abort condition
      if (count == 100)
        {
        count = 0;
        if (ren->GetRenderWindow()->CheckAbortStatus())
          {
          noAbort = 0;
          }
        }
      ++cellNum;
      coloroffset += (nPts >= 2)? (nPts - 2) : 0;
      }
    }  
    }
}

// Draw method for OpenGL.
int vtkOpenGLPolyDataMapper::Draw(vtkRenderer *aren, vtkActor *act)
{
  vtkOpenGLRenderer *ren = (vtkOpenGLRenderer *)aren;
  int rep, interpolation;
  float tran;
  vtkProperty *prop;
  vtkPoints *p;
  vtkUnsignedCharArray *c=NULL;
  vtkDataArray *n;
  vtkDataArray *t;
  int tDim;
  int noAbort = 1;
  vtkPolyData *input = this->GetInput();
  int cellScalars = 0;
  vtkIdType cellNum = 0;
  int cellNormals;
  int resolve=0, zResolve=0;
  double zRes = 0.0;
  
  // get the property 
  prop = act->GetProperty();

  // get the transparency 
  tran = prop->GetOpacity();
  
  // if the primitives are invisable then get out of here 
  if (tran <= 0.0)
    {
    return noAbort;
    }

  // get the representation (e.g., surface / wireframe / points)
  rep = prop->GetRepresentation();

  // get the shading interpolation 
  interpolation = prop->GetInterpolation();

  // and draw the display list
  p = input->GetPoints();
  
  // are they cell or point scalars
  if ( this->Colors )
    {
    c = this->Colors;
    if ( (this->ScalarMode == VTK_SCALAR_MODE_USE_CELL_DATA ||
          this->ScalarMode == VTK_SCALAR_MODE_USE_CELL_FIELD_DATA ||
          this->ScalarMode == VTK_SCALAR_MODE_USE_FIELD_DATA ||
          !input->GetPointData()->GetScalars() )
         && this->ScalarMode != VTK_SCALAR_MODE_USE_POINT_FIELD_DATA)
      {
      cellScalars = 1;
      }
    }
    
  n = input->GetPointData()->GetNormals();
  if (interpolation == VTK_FLAT)
    {
    n = 0;
    }
  
  cellNormals = 0;
  if (n == 0 && input->GetCellData()->GetNormals())
    {
    cellNormals = 1;
    n = input->GetCellData()->GetNormals();
    }
  
  // if we are doing vertex colors then set lmcolor to adjust 
  // the current materials ambient and diffuse values using   
  // vertex color commands otherwise tell it not to.          
  glDisable( GL_COLOR_MATERIAL );
  if (c)
    {
    GLenum lmcolorMode;
    if (this->ScalarMaterialMode == VTK_MATERIALMODE_DEFAULT)
      {
      if (prop->GetAmbient() > prop->GetDiffuse())
        {
        lmcolorMode = GL_AMBIENT;
        }
      else
        {
        lmcolorMode = GL_DIFFUSE;
        }
      }
    else if (this->ScalarMaterialMode == VTK_MATERIALMODE_AMBIENT_AND_DIFFUSE)
      {
      lmcolorMode = GL_AMBIENT_AND_DIFFUSE;
      }
    else if (this->ScalarMaterialMode == VTK_MATERIALMODE_AMBIENT)
      {
      lmcolorMode = GL_AMBIENT;
      }
    else // if (this->ScalarMaterialMode == VTK_MATERIALMODE_DIFFUSE)
      {
      lmcolorMode = GL_DIFFUSE;
      } 
    glColorMaterial( GL_FRONT_AND_BACK, lmcolorMode);
    glEnable( GL_COLOR_MATERIAL );
    }
  
  unsigned long idx = 0;
  if (n && !cellNormals)
    {
    idx |= VTK_PDM_NORMALS;
    }
  if (c)
    {
    idx |= VTK_PDM_COLORS;
    if (c->GetName())
      { // In the future, I will look at the number of components.
      // All paths will have to handle 3 componet colors.
      idx |= VTK_PDM_OPAQUE_COLORS;
      }
    }
  if (cellScalars)
    {
    idx |= VTK_PDM_CELL_COLORS;
    }
  if (cellNormals)
    {
    idx |= VTK_PDM_CELL_NORMALS;
    }
  if (this->ScalarMode == VTK_SCALAR_MODE_USE_FIELD_DATA)
    {
    idx |= VTK_PDM_USE_FIELD_DATA;
    }

  // store the types in the index
  if (p->GetDataType() == VTK_FLOAT)
    {
    idx |= VTK_PDM_POINT_TYPE_FLOAT;
    }
  else if (p->GetDataType() == VTK_DOUBLE)
    {
    idx |= VTK_PDM_POINT_TYPE_DOUBLE;
    }
  if (n)
    {
    if (n->GetDataType() == VTK_FLOAT)
      {
      idx |= VTK_PDM_NORMAL_TYPE_FLOAT;
      }
    else if (n->GetDataType() == VTK_DOUBLE)
      {
      idx |= VTK_PDM_NORMAL_TYPE_DOUBLE;
      }
    }

  // Texture and color by texture
  t = input->GetPointData()->GetTCoords();
  if ( t ) 
    {
    tDim = t->GetNumberOfComponents();
    if (tDim > 2)
      {
      vtkDebugMacro(<< "Currently only 1d and 2d textures are supported.\n");
      t = NULL;
      }
    }
  // Set the texture if we are going to use texture
  // for coloring with a point attribute.
  // fixme ... make the existance of the coordinate array the signal.
  if (this->InterpolateScalarsBeforeMapping && this->ColorCoordinates &&
      ! (idx & VTK_PDM_CELL_COLORS))
    {
    t = this->ColorCoordinates;
    }
  // Set the flags
  if (t)
    {
    idx |= VTK_PDM_TCOORDS;
    if (t->GetDataType() == VTK_FLOAT)
      {
      idx |= VTK_PDM_TCOORD_TYPE_FLOAT;
      }
    else if (t->GetDataType() == VTK_DOUBLE)
      {
      idx |= VTK_PDM_TCOORD_TYPE_DOUBLE;
      }
    if (t->GetNumberOfComponents() == 1)
      {
      idx |= VTK_PDM_TCOORD_1D;
      }
    // Not 1D assumes 2D texture coordinates.
    }
    
  if ( this->GetResolveCoincidentTopology() )
    {
    resolve = 1;
    if ( this->GetResolveCoincidentTopology() == VTK_RESOLVE_SHIFT_ZBUFFER )
      {
      zResolve = 1;
      zRes = this->GetResolveCoincidentTopologyZShift();
      }
    else
      {
#ifdef GL_VERSION_1_1
      double f, u;
      glEnable(GL_POLYGON_OFFSET_FILL);
      this->GetResolveCoincidentTopologyPolygonOffsetParameters(f,u);
      glPolygonOffset(f,u);
#endif      
      }
    }

  // we need to know the total number of cells so that we can report progress
  this->TotalCells = 
    input->GetVerts()->GetNumberOfCells() + 
    input->GetLines()->GetNumberOfCells() + 
    input->GetPolys()->GetNumberOfCells() + 
    input->GetStrips()->GetNumberOfCells();
  
  // For verts or lines that have no normals, disable shading.
  // This will fall back on the color set in the glColor4fv() 
  // call in vtkOpenGLProperty::Render() - the color returned
  // by vtkProperty::GetColor() with alpha set to 1.0.
  if (!n)
    {
    glDisable( GL_LIGHTING);
    }

  this->DrawPoints(idx,p,n,c,t,cellNum,noAbort,input->GetVerts(), ren);
  
  // do lines
  if ( zResolve )
    {
    glDepthRange(zRes, 1.);
    }
  if (rep == VTK_POINTS)
    {
    this->DrawPoints(idx,p,n,c,t,cellNum, noAbort,input->GetLines(), ren);
    }
  else
    {
    this->DrawLines(idx,p,n,c,t,cellNum, noAbort, input->GetLines(), ren);
    }
  
  // reset the lighting if we turned it off
  if (!n)
    {
    glEnable( GL_LIGHTING);
    }

  // disable shading if we are rendering points, but have no normals
  if (!n && rep == VTK_POINTS)
    {
    glDisable( GL_LIGHTING);
    }
  
  // do polys
  if (rep == VTK_POINTS && !prop->GetBackfaceCulling() && !prop->GetFrontfaceCulling() )
    {
    this->DrawPoints(idx,p,n,c,t,cellNum, noAbort, input->GetPolys(), ren);
    }
  else if (rep == VTK_WIREFRAME && !prop->GetBackfaceCulling() && !prop->GetFrontfaceCulling())
    {
    this->DrawPolygons(idx,p,n,c,t,cellNum, noAbort,
                       GL_LINE_LOOP, input->GetPolys(), ren);
    }
  else
    {
    this->DrawPolygons(idx,p,n,c,t,cellNum, noAbort,
                       GL_POLYGON, input->GetPolys(), ren);
    }
  

  // do tstrips
  if ( zResolve )
    {
    glDepthRange(2*zRes, 1.);
    }
  if (rep == VTK_POINTS && !prop->GetBackfaceCulling() && !prop->GetFrontfaceCulling() )
    {
    this->DrawPoints(idx,p,n,c,t,cellNum, noAbort, input->GetStrips(), ren);
    }
  else if (rep == VTK_WIREFRAME && !prop->GetBackfaceCulling() && !prop->GetFrontfaceCulling())
    {
    vtkIdType oldCellNum = cellNum;
    this->DrawTStrips(idx,p,n,c,t,cellNum, noAbort,
                      GL_LINE_STRIP, input->GetStrips(), ren);
    vtkOpenGLPolyDataMapperDrawTStripLines(idx,p,n,c,t,oldCellNum, noAbort,
                                           GL_LINE_STRIP, input->GetStrips(), 
                                           ren);
    }
  else
    {
    this->DrawTStrips(idx,p,n,c,t,cellNum, noAbort,
                      GL_TRIANGLE_STRIP, input->GetStrips(), ren);
    }

  // enable lighting again if necessary
  if (!n && rep == VTK_POINTS)
    {
    glEnable( GL_LIGHTING);
    }

  if (resolve)
    {
    if ( zResolve )
      {
      glDepthRange(0., 1.);
      }
    else
      {
#ifdef GL_VERSION_1_1
      glDisable(GL_POLYGON_OFFSET_FILL);
#endif
      }
    }

  this->UpdateProgress(1.0); 
  return noAbort;
}

void vtkOpenGLPolyDataMapper::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}

  











