Back to July Calendar Previous Entry Next Entry→

JUL 6

 

Correctomunde!  So, adding the enabling command I get the following stippling effects with glLineStipple(3, 0xcccc) preceding the strip and glLineStipple(5, 0xccbc) preceding the loop.  Here’s what Angel has to say about LineStipple(Glint factor, GLushort pattern). It “defines a 16-bit pattern for drawing lines.  If a bit in a pattern is 1, a pixel on the line is drawn.  If it is zero, the pixel is not drawn.  Succesive groups of ones and zeros in pattern are repeated factor times for values of factor between 1 and 256.  The stipple pattern is repeated as necessary to draw the line. The bits are used starting with the lowest order bits.”  Huh?  The binary form of CCCC is 1100110011001100 which alternating regularly, while ccbc is 1100110010111100.  hmmm.  Mebbe figure this out another time.

Continuing our evolution of geometric primitives from point and lines we proceed to filled primitives.  These include

  • GL_POLYGON:  pretty much like GL_LINES_LOOP; it takes sequence of glVertex*() calls nested between glBegin() and glEnd().
  • GL_TRIANGLES:  Takes successive groups of three vertices between glBegin() and glEnd() and forms (possibly disjoint) triangles with them, ignoring any extra vertices at the end.
  • GL_TRIANGLE_STRIP: After the first three vertices, which define the first triangle, each subsequent vertex is joined with the previous two to form an amalgam of triangles connected in a, well, strip.
  • GL_TRIANGLE_FAN:  After the first three vertices, which define the first triangle, each subsequent vertex is joined with the first vertex and the last vertex to form a kind of, well, fan.
  • GL_QUADS:  Succesive groups of four vertices define quadrilaterals.
  • GL_QUAD_STRIP:  Just what you would expect.

 

So consider the regular octagon inscribed in the unit circle and apply the above 6 filled types and see how it comes out.

 

I don’t quite understand the last one, but the others make sense:  The fan fills up the same space as the polygon: and colors the interior the same way.  But why does QUAD_STRIP look just like TRIANGLE_STRIP?  Not just what I would expect!  I’ll let it go for now…

Care for some stippling with your polygons?  Don’t forget to enable polygon stippling with glEnable(GL_POLYGON_STIPPLE) and then to set the pattern with glPolygonStipple() which takes an input of the form const Glubyte *mask.  Uh-oh.  

I found some information about this at http://www.quepublishing.com/articles/article.asp?p=328646&seqNum=9&rl=1 , which turns out to be excerpted from the OpenGL Superbible.  This is handy.  So I just cut and paste the code from there and add a few lines to enable and use this bitmap and yavole! Multi color fire!

Here’s the total code for that:

 

#include <GL/glut.h>   // This includes gl.h and glu.h

 

void display() {

      //clear window

      glClear(GL_COLOR_BUFFER_BIT);

 

      //You've got enable this feature to use it

      glEnable(GL_POLYGON_STIPPLE);

 

      //Set point size

      glPointSize(1.0);

 

      // Bitmap of campfire from OpenGL Superbible.

      GLubyte fire[] = { 0x00, 0x00, 0x00, 0x00,

          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,

          0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x07, 0xf0,

          0x0f, 0x00, 0x1f, 0xe0, 0x1f, 0x80, 0x1f, 0xc0,

          0x0f, 0xc0, 0x3f, 0x80, 0x07, 0xe0, 0x7e, 0x00,

          0x03, 0xf0, 0xff, 0x80, 0x03, 0xf5, 0xff, 0xe0,

          0x07, 0xfd, 0xff, 0xf8, 0x1f, 0xfc, 0xff, 0xe8,

          0xff, 0xe3, 0xbf, 0x70, 0xde, 0x80, 0xb7, 0x00,

          0x71, 0x10, 0x4a, 0x80, 0x03, 0x10, 0x4e, 0x40,

          0x02, 0x88, 0x8c, 0x20, 0x05, 0x05, 0x04, 0x40,

          0x02, 0x82, 0x14, 0x40, 0x02, 0x40, 0x10, 0x80,

          0x02, 0x64, 0x1a, 0x80, 0x00, 0x92, 0x29, 0x00,

          0x00, 0xb0, 0x48, 0x00, 0x00, 0xc8, 0x90, 0x00,

          0x00, 0x85, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00,

          0x00, 0x00, 0x10, 0x00 };

 

      //Specify stipple pattern

      glPolygonStipple(fire);

      // draw polygon

      glBegin(GL_POLYGON);

        glColor3f(0.5,0.5,1.0); 

        glVertex2f(-1.0,0.0);    //left mid

        glColor3f(1.0,0.0,0.0);  //red

        glVertex2f(-0.71,0.71);  //upper left corner

        glColor3f(0.0,0.0,1.0);  //blue

        glVertex2f(0.0,1.0);

        glColor3f(0.0,1.0,0.0);  //green

        glVertex2f(0.71,0.71);

        glColor3f(0.5,0.5,0.0);

        glVertex2f(1.0,0.0);

        glColor3f(0.0,0.5,0.5);

        glVertex2f(0.71,-0.71);

        glColor3f(0.0,1.0,0.5);

        glVertex2f(0.0,-1.0);

        glColor3f(0.0,0.5,0.5);

        glVertex2f(-0.71,-0.71);

      glEnd();

 

      // draw triangles

      glBegin(GL_TRIANGLES);

        glColor3f(0.5,0.5,1.0); 

        glVertex2f(1.0,0.0);    //left mid

        glColor3f(1.0,0.0,0.0);  //red

        glVertex2f(1.29,0.71);  //upper left corner

        glColor3f(0.0,0.0,1.0);  //blue

        glVertex2f(2.0,1.0);

        glColor3f(0.0,1.0,0.0);  //green

        glVertex2f(2.71,0.71);

        glColor3f(0.5,0.5,0.0);

        glVertex2f(3.0,0.0);

        glColor3f(0.0,0.5,0.5);

        glVertex2f(2.71,-0.71);

        glColor3f(0.0,1.0,0.5);

        glVertex2f(2.0,-1.0);

        glColor3f(0.0,0.5,0.5);

        glVertex2f(1.29,-0.71);

      glEnd();

 

      // draw broken line

      glBegin(GL_TRIANGLE_STRIP);

        glColor3f(0.5,0.5,1.0); 

        glVertex2f(3.0,0.0);    //left mid

        glColor3f(1.0,0.0,0.0);  //red

        glVertex2f(3.29,0.71);  //upper left corner

        glColor3f(0.0,0.0,1.0);  //blue

        glVertex2f(4.0,1.0);

        glColor3f(0.0,1.0,0.0);  //green

        glVertex2f(4.71,0.71);

        glColor3f(0.5,0.5,0.0);

        glVertex2f(5.0,0.0);

        glColor3f(0.0,0.5,0.5);

        glVertex2f(4.71,-0.71);

        glColor3f(0.0,1.0,0.5);

        glVertex2f(4.0,-1.0);

        glColor3f(0.0,0.5,0.5);

        glVertex2f(3.29,-0.71);

      glEnd();

 

      glBegin(GL_TRIANGLE_FAN);

        glColor3f(0.5,0.5,1.0); 

        glVertex2f(-1.0,-2.0);    //left mid

        glColor3f(1.0,0.0,0.0);  //red

        glVertex2f(-0.71,-1.29);  //upper left corner

        glColor3f(0.0,0.0,1.0);  //blue

        glVertex2f(0.0,-1.0);

        glColor3f(0.0,1.0,0.0);  //green

        glVertex2f(0.71,-1.29);

        glColor3f(0.5,0.5,0.0);

        glVertex2f(1.0,-2.0);

        glColor3f(0.0,0.5,0.5);

        glVertex2f(0.71,-2.71);

        glColor3f(0.0,1.0,0.5);

        glVertex2f(0.0,-3.0);

        glColor3f(0.0,0.5,0.5);

        glVertex2f(-0.71,-2.71);

      glEnd();

 

      glBegin(GL_QUADS);

        glColor3f(0.5,0.5,1.0); 

        glVertex2f(1.0,-2.0);    //left mid

        glColor3f(1.0,0.0,0.0);  //red

        glVertex2f(1.29,-1.29);  //upper left corner

        glColor3f(0.0,0.0,1.0);  //blue

        glVertex2f(2.0,-1.0);

        glColor3f(0.0,1.0,0.0);  //green

        glVertex2f(2.71,-1.29);

        glColor3f(0.5,0.5,0.0);

        glVertex2f(3.0,-2.0);

        glColor3f(0.0,0.5,0.5);

        glVertex2f(2.71,-2.71);

        glColor3f(0.0,1.0,0.5);

        glVertex2f(2.0,-3.0);

        glColor3f(0.0,0.5,0.5);

        glVertex2f(1.29,-2.71);

      glEnd();

 

      glBegin(GL_QUAD_STRIP);

        glColor3f(0.5,0.5,1.0); 

        glVertex2f(3.0,-2.0);    //left mid

        glColor3f(1.0,0.0,0.0);  //red

        glVertex2f(3.29,-1.29);  //upper left corner

        glColor3f(0.0,0.0,1.0);  //blue

        glVertex2f(4.0,-1.0);

        glColor3f(0.0,1.0,0.0);  //green

        glVertex2f(4.71,-1.29);

        glColor3f(0.5,0.5,0.0);

        glVertex2f(5.0,-2.0);

        glColor3f(0.0,0.5,0.5);

        glVertex2f(4.71,-2.71);

        glColor3f(0.0,1.0,0.5);

        glVertex2f(4.0,-3.0);

        glColor3f(0.0,0.5,0.5);

        glVertex2f(3.29,-2.71);

      glEnd();

      //flush GL buffers

      glFlush();

}

 

void init() {

      //set clear color to white

      glClearColor(1.0,1.0,1.0,1.0);
      //set fill color to black

      glColor3f(0.0,0.0,0.0);

      //set standard orthogonal (look straight at) clipping view

      //with cube of edge 2 centered at origin (default-could be omitted)

 

      glMatrixMode(GL_PROJECTION);

      glLoadIdentity();

      gluOrtho2D(-1.5,7.5,-3.5,1.5);

}

 

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

 

      //init mode and open window in upper-left corner

      glutInit(&argc, argv);

      glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);

      glutInitWindowSize(500,500);

      glutInitWindowPosition(0,0);

      glutCreateWindow("thimple");

      glutDisplayFunc(display);

      init();

      glutMainLoop();

}

 

I don’t quite grasp how the hex code for the campfire works, but I get the idea.  The Superbible suggests maybe waiting for the chapter on rasterization.  Ok.

 

So the problem with my QUAD_STRIP above is that it’s hard to fill a polygon whose edges cross.  OpenGL does not check to see if your polygons are simple (no crossing edges) or not. The situation is even worse for polygons in 3-dimensions, since the edges may turn out to be not coplanar. Simply imagine twisting the edges of a square, now what’s the interior?   It’s up to the programmer to deal with these problems.  OpenGL may react with surprise when asked to do the ridiculous.

 

A polygon is convex if every point in the interior can be connected with every other point in the interior by a straight line lying entirely in the interior.  Every triangle is convex.  “Darts” are quadrilaterals that aren’t convex.  Since filling is much simpler for convex polygons, they are the preferred polygon for filling in OpenGL.

 

OpenGL allows polygons to displayed as filled, just the edges, or just the vertices.  In 3D, you can also treat the front and back faces of the polygon with different colors, textures, etc. 

 

The front face has the order of vertices in counterclockwise direction/backside in clockwise order.

 

The function glPolygonMode() takes two inputs, both of type GLenum: face can be either GL_FRONT or GL_BACK or GL_FRONT_AND_BACK and  mode can be GL_POINT, GL_LINE or GL_FILL.  The default is fill faces.

 

There’s also something called glCullFace() which allows you to avoid rendering the faces at all.

 

You can reverse which is front and back by glFrontFace() which takes arguments GL_CCW or GL_CW for counterclockwise front or the reverse.

 

Suppose you want edges, vertices and fill to all be different.  This you can do by rerendering the same polygon with different attributes.

 

Tomorrow, baby. It’s a too late now.