Problem with polygon rendering

I’m trying to draw self-intersecting polygons using GLU with GLU_TESS_WINDING_ODD winding rule but sometimes I get unexpected results.

For example, using the following coordinates

  GLdouble poly[][2] = {{280.0, 290.0},  {170.0, 250.0},  {501.0, 188.0},  {140.0, 393.0},  {140.0, 61.0}};

I get this …

I’ve zipped up a very small C++ file - main.cpp (~150 lines) - which compiles in MS Visual C++ 2010 Express …
main.zip (4KB)

I’d be grateful for any help explaining why this isn’t rendering properly.

I did not open your zip, do you provide your own callback to resolve self-intersecting polygons ?
gluTessCallback (tess, GLU_TESS_COMBINE, tcbCombine);
http://glprogramming.com/red/chapter11.html
http://www.opengl.org/resources/faq/technical/glu.htm
http://www.songho.ca/opengl/gl_tessellation.html

Yes.


#include <windows.h>

#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <vector>

#define array_len(a) ( sizeof ( a ) / sizeof ( *a ) )

//------------------------------------------------------------------------------
// heap memory management for GLUtesselator ...
//------------------------------------------------------------------------------

typedef std::vector< GLdouble* > Vectors;
Vectors vectors;

GLdouble* NewVector(GLdouble x, GLdouble y)
{
  GLdouble *vert = new GLdouble[3];
  vert[0] = x;
  vert[1] = y;
  vert[2] = 0;
  vectors.push_back(vert);
  return vert;
}
//------------------------------------------------------------------------------

void ClearVectors()
{
  for (Vectors::size_type i = 0; i < vectors.size(); ++i)
    delete[] vectors[i];
  vectors.clear(); 
}

//------------------------------------------------------------------------------
// GLUtesselator callback functions ...
//------------------------------------------------------------------------------

void CALLBACK BeginCallback(GLenum type)   
{   
    glBegin(type);   
} 
//------------------------------------------------------------------------------

void CALLBACK EndCallback()   
{   
    glEnd();   
}
//------------------------------------------------------------------------------

void CALLBACK VertexCallback(GLvoid *vertex)   
{   
  glVertex3dv( (const double *)vertex );   
} 
//------------------------------------------------------------------------------

void CALLBACK CombineCallback(GLdouble coords[3], 
  GLdouble *data[4], GLfloat weight[4], GLdouble **dataOut )   
{   
  GLdouble *vert = NewVector(coords[0], coords[1]);
  *dataOut = vert;
}   
//------------------------------------------------------------------------------

void CALLBACK ErrorCallback(GLenum errorCode)   
{   
   fprintf(stderr,"Tessellation Error: %s
", gluErrorString(errorCode));
   exit(1);
}   

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------

void display()
{
  //Erase the window and the depth buffer
  glClearColor(1,1,1,1);
  glClear(GL_COLOR_BUFFER_BIT);

  GLUtesselator* tess = gluNewTess();
  gluTessCallback(tess, GLU_TESS_BEGIN, (void (CALLBACK*)())&BeginCallback);    
  gluTessCallback(tess, GLU_TESS_VERTEX, (void (CALLBACK*)())&VertexCallback);    
  gluTessCallback(tess, GLU_TESS_END, (void (CALLBACK*)())&EndCallback);   
  gluTessCallback(tess, GLU_TESS_COMBINE, (void (CALLBACK*)())&CombineCallback);   
  gluTessCallback(tess, GLU_TESS_ERROR, (void (CALLBACK*)())&ErrorCallback);
  gluTessNormal(tess, 0.0, 0.0, 1.0);

  gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); 
  gluTessProperty(tess, GLU_TESS_BOUNDARY_ONLY, GL_FALSE); //GL_FALSE
  gluTessBeginPolygon(tess, NULL); 
  gluTessBeginContour(tess);

  glColor4f(0.0f, 0.0f, 1.0f, 0.062f);
  //these coordinates don't render the polygon as expected using the GLU_TESS_WINDING_ODD winding rule ...
  GLdouble poly[][2] = {{280.0, 290.0},  {170.0, 250.0},  {501.0, 188.0},  {140.0, 393.0},  {140.0, 61.0}};
  //however, repositioning the first coordinate above just a little, it does render as expected ...
  //GLdouble poly[][2] = {{280.0, 330.0},  {170.0, 250.0},  {501.0, 188.0},  {140.0, 393.0},  {140.0, 61.0}};

  for (int i = 0; i < array_len(poly); ++i)
  {
      GLdouble *vert = NewVector(poly[i][0], poly[i][1]);
      gluTessVertex(tess, vert, vert); 
  }

  gluTessEndContour(tess); 
  gluTessEndPolygon(tess);
  ClearVectors();

  glFlush();
  glutSwapBuffers();
}
//------------------------------------------------------------------------------

void key(unsigned char ch,int x,int y)
{
   //  Exit on ESC
   if (ch == 27) exit(0);
}
//------------------------------------------------------------------------------

void reshape(int width,int height)
{

  //setup 2D projection with origin at top-left corner ...
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(0, width, height, 0, 0, 1);
  glViewport(0, 0, width, height);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}
//------------------------------------------------------------------------------

int main(int argc,char* argv[])
{

  //Initialize GLUT
  glutInit(&argc, argv);
  
  //Request double buffered, true color window with Z buffering at 600x600
  glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
  glutInitWindowSize(600,600);
  glutCreateWindow("Polygon test");
  
  //Set callbacks
  glutDisplayFunc(display);
  glutReshapeFunc(reshape);
  glutKeyboardFunc(key);

  glDisable(GL_DEPTH_TEST);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glTranslatef (0.375, 0.375, 0);

  //Pass control to GLUT so it can interact with the user
  glutMainLoop();
  return 0;
}

I’m now starting to suspect this might be a bug in the GLU library since I can duplicate the problem when I replace the polygon coordinates in the tesswind.c sample from the OpenGL Code samples with my polygon coordinates above. Also, if I change the starting coordinate to the third one, the polygon is rendered correctly.

Anyhow, could someone please verify that there is a problem either with my code or with the GLU library. If there’s a problem with the GLU library, does it affect other platforms apart from Windows?

Bump … is anyone able to spot the bug in my code or is this a bug in the GLU library?