Drawing Primitives and Modifying Colors
(updated in 17/05/2001)

Previous | Index | Next

To draw some HOpenGL primitives, such as lines, points and triangles, you'll need to use the function `beginEnd`. It is defined in module GL_BeginEnd, which is automatically imported if your program already imports module GL.

The following example draws a blue triangle whose vertices, using the (x,y,z) axis notation, are (0.20,0.20,0.0), (0.50,0.20,0.0) and (0.35,0.40,0.0):

```	blueTriangle :: IO ()
blueTriangle = do
color (Color3 0.0 0.0 1.0 :: Color3 GLfloat)
beginEnd Triangles \$ mapM_ vertex [
Vertex3 0.20 0.20 0.0,
Vertex3 0.50 0.20 0.0,
Vertex3 0.35 0.40 (0.0 :: GLfloat)]
```
Notes:
• If you wish to work with 2D rather than 3D, it is possible to use `Vertex2` instead of `Vertex3`, to make things simpler.
• The cast to `GLfloat` is necessary. Although it must be applied only to the last element of the last `Vertex`, all elements of all `Vertex` will be "casted to" `GLfloat`.
• The `color` function is very simple and is used to modify the current color. The values of the parameters (just after `Color3`) follows the RGB notation. In the example above, we have: RED = 0%, GREEN = 0% and BLUE = 100%.
• The type of the function `beginEnd` is `VertexMode -> IO a -> IO a`.

Now we are going to show all possible values for `VertexMode`, and a brief explanation of what each one draws (obs.: let n be the number of vertices (`Vertex3` or `Vertex2`) received by `beginEnd`):

• `Points` - Draws a group of n points.

• `Lines` - Draws (n/2) lines. Given 2 vertices, one line is drawn; given 4 vertices, two lines are drawn: the first line with the first two vertices and the second line with the two last vertices. And so on...

• `LineStrip` - Draws a line strip: the first two vertices are used to draw the first line, the next vertex v[n] draws a new line whose extremities are the vertices (v[n],v[n-1]).

• `LineLoop` - It behaves the same way as as `LineStrip`, but this time the first and the last vertices are connected together, in order to draw one more line.

• `Polygon` - Draws a (filled) polygon with n vertices (n >= 3), with the last vertex connected to the first one. Concavous polygons need special attention (the result obtained may not be the one you would like to have).

• `Triangles` - Draws (n/3) triangles: given 3 vertices, one triangle is drawn; given 6 vertices, two triangles are drawn: one with the first three vertices and the other one with the three last last vertices. And so on...

• `TriangleStrip` - Draws a triangle strip (n >= 3): the first three vertices are used to draw the first triangle, the next vertex v[n] draws a new triangle whose vertices are (v[n],v[n-1],v[n-2]).

• `TriangleFan` - Draws a fan made of several triangles (n >= 3): the first three vertices are used to draw the first triangle, the next vertex v[n] draws a new triangle whose vertices are (v[n],v[n-1],v[1]).

• `Quads` - Draws (n/4) quadrilaterals: given 4 vertices, one quadrilateral is drawn; given 8 vertices, two quadrilaterals are drawn: one with the first four vertices and the other one with the four last last vertices. And so on...

• `QuadStrip` - Draws a quadrilateral strip (n>=4): the first four vertices are used to draw the first quadrilateral; the next two vertices v[n] and v[n+1] draw a new quadrilateral whose vertices are (v[n+1],v[n],v[n-1],v[n-2]).

Check out the following picture to understand how the primitives are drawn:

Let the bottom left corner and the top right corner of the window be the coordinates (0.0,0.0,0.0) and (1.0,1.0,1.0) respectively. Now observe some examples

• Example 1 - two red points are drawn, one in the middle of the window and other next to its top left corner:
```	ex1 :: IO ()
ex1 = do
color (Color3 1.0 0.0 0.0 :: Color3 GLfloat)
beginEnd Points \$ mapM_ vertex [
Vertex3 0.50 0.50 0.0,
Vertex3 0.10 0.90 (0.0 :: GLfloat)]
```

• Example 2 - draws a non-filled green star:
```	ex2 :: IO ()
ex2 = do
color (Color3 0.0 1.0 0.0 :: Color3 GLfloat)
beginEnd LineLoop \$ mapM_ vertex [
Vertex3 0.20 0.10 0.0,
Vertex3 0.50 0.90 0.0,
Vertex3 0.80 0.10 0.0,
Vertex3 0.10 0.60 0.0,
Vertex3 0.90 0.60 (0.0 :: GLfloat)]
```

• Exemplo 3 - draws a yellow square and a red triangle inside it:
```	ex3 :: IO ()
ex3 = do
color (Color3 1.0 1.0 0.0 :: Color3 GLfloat)
beginEnd Quads \$ mapM_ vertex [
Vertex3 0.20 0.20 0.0,
Vertex3 0.80 0.20 0.0,
Vertex3 0.80 0.80 0.0,
Vertex3 0.20 0.80 (0.0 :: GLfloat)]

color (Color3 1.0 0.0 0.0 :: Color3 GLfloat)
beginEnd Triangles \$ mapM_ vertex [
Vertex3 0.30 0.30 0.0,
Vertex3 0.70 0.30 0.0,
Vertex3 0.50 0.70 (0.0 :: GLfloat)]
```

Notice that, in this last example, the order in which the primitives are drawn is important. The triangle won't appear if you draw the square before it.

In the `display` function introduced to you in our "first (and simple) program" (previous module), try to make a call to one of these examples (`ex1`, `ex2` or `ex3`). Obviously, do not forget to include their respesctive code. Compile again and watch the results by yourself.

Hints and Tips:
• Use `Strips` as often as you can. They are a great way to boost your program performance (a less number of vertices are needed in order to draw them).
• If you wish to draw non-filled polygons, use `LineLoop` to trace their contour.
• You can create a `Vertex3` (or `Vertex2`) list and call the function `beginEnd` using this list. This may be helpful to create animations, in which the values of the vertices are updated in the list and a new call to `beginEnd` will draw the primitive with new coordinates.
• Pay attention to problems related to bad identation: the declaration of the vertices and the declaration of `BeginEnd` must not be done in the same column. For example, the following code will have problems during compilation:
```		beginEnd Points \$ mapM_ vertex [
Vertex3 0.50 0.50 0.0,
Vertex3 0.10 0.90 (0.0 :: GLfloat)]
```