0% found this document useful (0 votes)
5 views36 pages

Chapter 3 - CG (2024)

Download as pdf or txt
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 36

Debre Markos University

Faculty of Technology
Department of Computer Science
CoSc3072 – Computer Graphics
Chapter 3 Handout – Graphics Primitives

1. Introduction

All graphics packages construct pictures from basic building blocks known as graphics
primitives.
I. Geometric Primitives: Primitives that describe the geometry, or shape, of these
building blocks are known as geometric primitives. They can be anything from 2-
D primitives such as points, lines and polygons to more complex 3-D primitives
such as spheres and polyhedra (a polyhedron is a 3-D surface made from a mesh
of 2-D polygons).
II. Fill Area Primitives: Refers to any enclosed boundary that can be filled with a
solid color or pattern.
III. Character Primitives: Used to display text characters

In the following sections we will examine some algorithms for drawing different
primitives, and where appropriate we will introduce the routines for displaying these
primitives in OpenGL.

2. OpenGL Point Drawing Primitives

The most basic type of primitive is the point. Many graphics packages, including
OpenGL, provide routines for displaying points. We have already seen the OpenGL
routines for point drawing in the simple OpenGL program introduced in Chapter 2. To
recap, we use the pair of functions glBegin … glEnd, using the symbolic constant
GL_POINTS to specify how the vertices in between should be interpreted. In addition,
the function glPointSize can be used to set the size of the points in pixels. The default
point size is 1 pixel. Points that have a size greater than one pixel are drawn as squares
with a side length equal to their size. For example, the following code draws three 2-D
points with a size of 2 pixels.

glPointSize(2.0);
glBegin(GL_POINTS);
glVertex2f(100.0, 200.0);
glVertex2f(150.0, 200.0);
glVertex2f(150.0, 250.0);
glEnd();

3. Line Drawing Algorithms

Lines are a very common primitive and will be supported by almost all graphics
packages. In addition, lines form the basis of more complex primitives such as polylines
Computer Graphics Page 1
(a connected sequence of straight-line segments) or polygons (2-D objects formed by
straight-line edges).

Lines are normally represented by the two end-points of the line, and points (x,y) along
the line must satisfy the following slope-intercept equation:

y = mx + c ..................................................................................................................(1)

where m is the slope or gradient of the line, and c is the coordinate at which the line
intercepts the y-axis. Given two end-points (x0,y0) and (xend,yend), we can calculate values
for m and c as follows:
y  y0 
m  end …………………………………………………………… (2)
xend  x0 
c  y0  mx0 …………………………………………………………………… (3)

Furthermore, for any given x-interval δx, we can calculate the corresponding y-interval
δy:
δy = m.δx ..................................................................................................................(4)
δx = (1/m).δy ............................................................................................................(5)

These equations form the basis of the two line-drawing algorithms described below: the
DDA algorithm and Bresenham’s algorithm.

3.1. DDA Line-Drawing Algorithm

The Digital Differential Analyser (DDA) algorithm operates by starting at one end-point
of the line, and then using Eqs. (4) and (5) to generate successive pixels until the second
end-point is reached. Therefore, first, we need to assign values for δx and δy.

Before we consider the actual DDA algorithm, let us consider a simple first approach to
this problem. Suppose we simply increment the value of x at each iteration (i.e. δx = 1),
and then compute the corresponding value for y using Eqs. (2) and (4). This would
compute correct line points but, as illustrated by Figure 1, it would leave gaps in the line.
The reason for this is that the value of δy is greater than one, so the gap between
subsequent points in the line is greater than 1 pixel.

Figure 1 – ‘Holes’ in a Line Drawn by Incrementing x and Computing the


Corresponding y-Coordinate

Computer Graphics Page 2


The solution to this problem is to make sure that both δx and δy have values less than or
equal to one. To ensure this, we must first check the size of the line gradient. The
conditions are:
 If |m| ≤ 1:
o δx = 1
o δy = m
 If |m| > 1:
o δx = 1/m
o δy = 1
Once we have computed values for δx and δy, the basic DDA algorithm is:
 Start with (x0,y0)
 Find successive pixel positions by adding on (δx, δy) and rounding to the nearest
integer, i.e.
o xk+1 = xk + δx
o yk+1 = yk + δy
 For each position (xk,yk) computed, plot a line point at (round(xk),round(yk)),
where the round function will round to the nearest integer.

Note that the actual pixel value used will be calculated by rounding to the nearest integer,
but we keep the real-valued location for calculating the next pixel position.

Let us consider an example of applying the DDA algorithm for drawing a straight-line
segment. Referring to see Figure 2, we first compute a value for the gradient m:

Now, because |m| ≤ 1, we compute δx and δy as follows:

δx = 1
δy = 0.6
Using these values of δx and δy we can now start to plot line points:

 Start with (x0,y0) = (10,10) – colour this pixel


 Next, (x1,y1) = (10+1,10+0.6) = (11,10.6) – so we colour pixel (11,11)
 Next, (x2,y2) = (11+1,10.6+0.6) = (12,11.2) – so we colour pixel (12,11)
 Next, (x3,y3) = (12+1,11.2+0.6) = (13,11.8) – so we colour pixel (13,12)
 Next, (x4,y4) = (13+1,11.8+0.6) = (14,12.4) – so we colour pixel (14,12)
 Next, (x5,y5) = (14+1,12.4+0.6) = (15,13) – so we colour pixel (15,13)
 We have now reached the end-point (xend,yend), so the algorithm terminates

Computer Graphics Page 3


Figure 2 - The Operation of the DDA Line-Drawing Algorithm

The DDA algorithm is simple and easy to implement, but it does involve floating point
operations to calculate each new point. Floating point operations are time-consuming
when compared to integer operations. Since line-drawing is a very common operation in
computer graphics, it would be nice if we could devise a faster algorithm which uses
integer operations only. The next section describes such an algorithm.

3.2. Bresenham’s Line-Drawing Algorithm

Bresenham’s line-drawing algorithm provides significant improvements in efficiency


over the DDA algorithm. These improvements arise from the observation that for any
given line, if we know the previous pixel location, we only have a choice of 2 locations
for the next pixel. This concept is illustrated in Figure 3: given that we know (xk,yk) is a
point on the line, we know the next line point must be either pixel A or pixel B. Therefore
we do not need to compute the actual floating-point location of the ‘true’ line point; we
need only make a decision between pixels A and B.

Figure 3 - Bresenham's Line-Drawing Algorithm


Bresenham’s algorithm works as follows. First, we denote by dupper and dlower the
distances between the centres of pixels A and B and the ‘true’ line (see Figure 3). Using
Eq. (1) the ‘true’ y-coordinate at xk+1 can be calculated as:

Computer Graphics Page 4


y  m(xk  1)  c …………………………………………………………… (6)
Therefore we compute dlower and dupper as:
dlower  y  yk  m(xk  1)  c  yk …………………………………………… (7)
dupper  ( yk  1)  y  yk  1  m(xk  1)  c …………………………………… (8)

Now, we can decide which of pixels A and B to choose based on comparing the values of
dupper and dlower:
 If dlower > dupper, choose pixel A
 Otherwise choose pixel B
We make this decision by first subtracting dupper from dlower:
dlower dupper  2mxk  1 2 yk  2c 1 .....................................................................(9)

If the value of this expression is positive we choose pixel A; otherwise we choose pixel
B. The question now is how we can compute this value efficiently. To do this, we define
a decision variable pk for the kth step in the algorithm and try to formulate pk so that it can
be computed using only integer operations. To achieve this, we substitute m  y / x
(where Δx and Δy are the horizontal and vertical separations of the two line end-points)
and define pk as:
pk  x(dlower dupper )  2yxk  2xyk  d …………………………… (10)

where d is a constant that has the value 2y  2cx  x . Note that the sign of pk will be
the same as the sign of (dlower – dupper), so if pk is positive we choose pixel A and if it is
negative we choose pixel B. In addition, pk can be computed using only integer
calculations, making the algorithm very fast compared to the DDA algorithm.

An efficient incremental calculation makes Bresenham’s algorithm even faster. (An


incremental calculation means we calculate the next value of pk from the last one.) Given
that we know a value for pk, we can calculate pk+1 from Eq. (10) by observing that:
 Always xk+1 = xk+1
 If pk < 0, then yk+1 = yk, otherwise yk+1 = yk+1

Therefore we can define the incremental calculation as:

pk 1  pk  2y , if pk < 0..........................................................................................(11)


pk 1  pk  2y  2x , if pk ≥ 0 ................................................................................(12)

The initial value for the decision variable, p0, is calculated by substituting xk = x0 and yk
= y0 into Eq. (10), which gives the following simple expression:

p0  2y  x …………………………………………………………… (13)

So we can see that we never need to compute the value of the constant d in Eq. (10).

Computer Graphics Page 5


Summary

To summarise, we can express Bresenham’s algorithm as follows:


 Plot the start-point of the line (x0,y0)
 Compute the first decision variable:
o p0  2y  x
 For each k, starting with k=0:
o If pk < 0:
 Plot (xk+1,yk)
 pk 1  pk  2y
o Otherwise:
 Plot (xk+1,yk+1)
 pk 1  pk  2y  2x

The steps given above will work for lines with positive |m| < 1. For |m| > 1 we simply
swap the roles of x and y. For negative slopes one coordinate decreases at each iteration
while the other increases.

Exercise

Consider the example of plotting the line shown in Figure 2 using Bresenham’s
algorithm:
 First, compute the following values:
o Δx = 5
o Δy = 3
o 2Δy = 6
o 2Δy - 2Δx = -4
o p0  2y  x  2  3  5  1
 Plot (x0,y0) = (10,10)
 Iteration 0:
o p0 ≥ 0, so
 Plot (x1,y1) = (x0+1,y0+1) = (11,11)
  p1  p0  2y  2x  1  4  3
 Iteration 1:
o p1 < 0, so
 Plot (x2,y2) = (x1+1,y1) = (12,11)
  p2  p1  2y  3  6  3
 Iteration 2:
o p2 ≥ 0, so
 Plot (x3,y3) = (x2+1,y2+1) = (13,12)
  p3  p2  2y  2x  3  4  1
 Iteration 3:
o p3 < 0, so
 Plot (x4,y4) = (x3+1,y3) = (14,12)

Computer Graphics Page 6


  p4  p3  2y  1  6  5
 Iteration 4:
o p4 ≥ 0, so
 Plot (x5,y5) = (x4+1,y4+1) = (15,13)
 We have reached the end-point, so the algorithm terminates

We can see that the algorithm plots exactly the same points as the DDA algorithm but it
computes them using only integer operations. For this reason, Bresenham’s algorithm is
the most popular choice for line-drawing in computer graphics.

3.3. OpenGL Line Functions

We can draw straight-lines in OpenGL using the same glBegin … glEnd functions that
we saw for point-drawing. This time we specify that vertices should be interpreted as line
end-points by using the symbolic constant GL_LINES. For example, the following code

glLineWidth(3.0);
glBegin(GL_LINES);
glVertex2f(100.0, 200.0);
glVertex2f(150.0, 200.0);
glVertex2f(150.0, 250.0);
glVertex2f(200.0, 250.0);
glEnd()

will draw two separate line segments: one from (100,200) to (150,200) and one from
(150,250) to (200,250). The line will be drawn in the current drawing colour and with a
width defined by the argument of the function glLineWidth.

Two other symbolic constants allow us to draw slightly different types of straight-line
primitive: GL_LINE_STRIP and GL_LINE_LOOP. The following example illustrates the
difference between the three types of line primitive. First we define 5 points as arrays of
2 Glint values. Next, we define exactly the same vertices for each of the three types of
line primitive. The images to the right show how the vertices will be interpreted by each
primitive.

Glint p1[] = {200,100}; Glint p2[] = {50,0}


Glint p3[] = {100,200}; Glint p4[] = {150,0};
Glint p5[] = {0,100};

glBegin(GL_LINES);
glVertex2iv(p1);
glVertex2iv(p2);
glVertex2iv(p3);
glVertex2iv(p4);
glVertex2iv(p5);
glEnd();

Computer Graphics Page 7


glBegin(GL_LINE_STRIP);
glVertex2iv(p1);
glVertex2iv(p2);
glVertex2iv(p3);
glVertex2iv(p4);
glVertex2iv(p5);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex2iv(p1);
glVertex2iv(p2);
glVertex2iv(p3);
glVertex2iv(p4);
glVertex2iv(p5);
glEnd();
We can see that GL_LINES treats the vertices as pairs of end-points. Lines are drawn
separately and any extra vertices (i.e. a start-point with no end-point) are ignored.
GL_LINE_STRIP will create a connected polyline, in which each vertex is joined to the
one before it and after it. The first and last vertices are only joined to one other vertex.
Finally, GL_LINE_LOOP is the same as GL_LINE_STRIP except that the last point is
joined to the first one to create a loop.

4. Circle-Drawing Algorithms

Some graphics packages allow us to draw circle primitives. Before we examine


algorithms for circle-drawing we will consider the mathematical equations of a circle. In
Cartesian2 coordinates we can write:
(x  x )  ( y  y )2  r2 …………………………………………………… (14)
c c

Where (xc,yc) is the centre of the circle. Alternatively, in polar coordinates we can write:

x  xc  r cos …………………………………………………………… (15)


y  yc  r sin  …………………………………………………………… (16)

In the following sections we will examine a number of approaches to plotting points on a


circle, culminating in the most efficient algorithm: the midpoint algorithm.

4.1. Plotting Points Using Cartesian Coordinates

As a first attempt at a circle-drawing algorithm we can use the Cartesian coordinate


representation. Suppose we successively increment the x-coordinate and calculate the
corresponding y-coordinate using Eq. (14):

y  yc  r 2  xc  x
2
…………………………………………………… (17)

Computer Graphics Page 8


This would correctly generate points on the boundary of a circle. However, like the first
attempt at a line-drawing algorithm we saw in Section 3.1 (see Figure 1) we would end
up with ‘holes’ in the line – see Figure 4. We would have the same problem if we
incremented the y-coordinate and plotted a calculated x-coordinate. As with the DDA
line-drawing algorithm we can overcome this problem by calculating and checking the
gradient: if |m| ≤ 1 then increment x and calculate y, and if |m| > 1 then increment y and
calculate x. However, with the DDA algorithm we only needed to compute and check the
gradient once for the entire line, but for circles the gradient changes with each point
plotted, so we would need to compute and check the gradient at each iteration of the
algorithm. This fact, in addition to the square root calculation in Eq. (17), would make
the algorithm quite inefficient.

Figure 4 - Circle-Drawing by Plotting Cartesian Coordinates

4.2. Plotting Points Using Polar Coordinates

An alternative technique is to use the polar coordinate equations. Recall that in polar
coordinates we express a position in the coordinate system as an angle θ and a distance r.
For a circle, the radius r will be constant, but we can increment θ and compute the
corresponding x and y values according to Eqs. (15) and (16).

For example, suppose we want to draw a circle with (xc,yc) = (5,5) and r = 10. We start
with θ = 0o and compute x and y as:
 x = 5 + 10 cos 0o = 15
 y = 5 + 10 sin 0o = 5
 Therefore we plot (15,5)
Next, we increase θ to 5o:
 x = 5 + 10 cos 5o = 14.96
 y = 5 + 10 sin 5o = 5.87
 Therefore we plot (15,6)
This process would continue until we had plotted the entire circle (i.e. θ = 360o). Using
this polar coordinate technique, we can avoid holes in the boundary if we make small
enough increases in the value of θ. In fact, if we use θ = 1/r (where r is measured in
pixels, and θ in radians) we will get points exactly 1 pixel apart and so there is guaranteed
to be no holes.

This algorithm is more efficient than the Cartesian plotting algorithm described in
Section 4.1. It can be made even more efficient, at a slight cost in quality; by increasing

Computer Graphics Page 9


the size of the steps in the value of θ and then joining the computed points by straight-
line segments (see Figure 5).

Figure 5 - Circle-Drawing by Plotting Polar Coordinates

4.3. Taking Advantage of the Symmetry of Circles in Plotting

We can improve the efficiency of any circle-drawing algorithm by taking advantage of


the symmetry of circles. As illustrated in Figure 6, when we compute the Cartesian
coordinates x and y of points on a circle boundary we have 4 axes of symmetry (shown in
blue): we can generate a point reflected in the y-axis by negating the x-coordinate; we can
generate a point reflected in the x-axis by negating the y-coordinate, and so on. In total,
for each point computed, we can generate seven more through symmetry. Computing
these extra points just by switching or negating the coordinates of a single point is much
more efficient than computing each boundary point separately. This means that we only
need to compute boundary points for one octant (i.e. one eighth) of the circle boundary –
shown in red in Figure 6

In addition to generating extra points, the 4-way symmetry of circles has another
advantage if combined with the Cartesian plotting algorithm described in Section 4.1.
Recall that this algorithm resulted in holes in some parts of the circle boundary (see
Figure 4), which meant that a time-consuming gradient computation had to be performed
for each point. In fact, the problem of holes in the boundary only occurs when the
gradient is greater than 1 for computing x-coordinates, or when the gradient is less than or
equal to 1 for computing y-coordinates. Now that we know we only need to compute
points for one octant of the circle we do not need to perform this check. For example, in
the red octant in Figure 6, we know that the gradient will never become greater than one,
so we can just increment the y-coordinate and compute the corresponding x-coordinates

Figure 6 - Four-Way Symmetry of Circles


However, even with these efficiency improvements due to symmetry, we still need to
perform a square root calculation (for Cartesian plotting) or a trigonometric calculation
(for polar plotting). It would be nice if there were an algorithm for circle-drawing that

Computer Graphics Page 10


used integer operations only, in the same way that Bresenham’s algorithm does for line-
drawing.

4.4. Midpoint Circle-Drawing Algorithm

The midpoint algorithm takes advantage of the symmetry property of circles to produce a
more efficient algorithm for drawing circles. The algorithm works in a similar way to
Bresenham’s line-drawing algorithm, in that it formulates a decision variable that can be
computed using integer operations only.

The midpoint algorithm is illustrated in Figure 7. Recall that we only need to draw one
octant of the circle, as the other seven octants can be generated by symmetry. In Figure 7
we are drawing the right-hand upper octant – the one with coordinate (y,x) in Figure 6,
but the midpoint algorithm would work with slight modifications whichever octant we
chose. Notice that in this octant, when we move from one pixel to try to draw the next
pixel there is only a choice of two pixels: A and B, or (xk+1,yk) and (xk+1,yk-1). Therefore
we don’t need to calculate a real-valued coordinate and then round to the nearest pixel,
we just need to make a decision as to which of the two pixels to choose.

Figure 7 - The Midpoint Circle-Drawing Algorithm

We start by defining a function fcirc as follows:


f circ (x, y)  x2  y2  r2 ………………………………………………….. (18)

This term can be derived directly from Eq. (14). Based on the result of this function, we
can determine the position of any point relative to the circle boundary:
 For points on circle, fcirc= 0
 For points inside circle, fcirc< 0
 For points outside circle, fcirc> 0

Now referring again to Figure 7, we note that the position of the midpoint of the two
pixels A and B can be written as:

midk = (xk+1,yk-0.5) ...................................................................................................(19)


Now we can see from Figure 7 that if the midpoint lies inside the circle boundary the next
pixel to be plotted should be pixel A. Otherwise it should be pixel B. Therefore we can
use the value of fcirc(midk) to make the decision between the two candidate pixels:

 If fcirc(midk) < 0, choose A

Computer Graphics Page 11


 Otherwise choose B

In order to make this decision quickly and efficiently, we define a decision variable pk,
by combining Eqs. (18) and (19):

pk  fcirc xk 1, yk  0.5  xk 1  y  0.5  r2
2 2
………………….. (20)

An incremental calculation for pk+1 can be derived by subtracting pk from pk+1 and
simplifying – the result is:

pk 1  pk  2xk 1  1, if pk < 0 ...................................................................................(21)


pk 1  pk  2xk 1  1  2 yk 1 , if pk ≥ 0 ........................................................................(22)
The initial value of the decision variable, p0, is calculated by evaluating it at the starting
point (0,r):
5
p0  fcirc 1, r  0.5  1  r  0.5  r   r..........................................................(23)
2 2

4
If r is an integer, then all increments are integers and we can round Eq. (23) to the nearest
integer:

p0 = 1 – r ....................................................................................................................(24)

Summary

To summarise, we can express the midpoint circle-drawing algorithm for a circle centred
at the origin as follows:
 Plot the start-point of the circle (x0,y0) = (0,r)
 Compute the first decision variable:
o p0  1  r
 For each k, starting with k=0:
o If pk < 0:
 Plot (xk+1,yk)
 pk 1  pk  2xk 1  1
o Otherwise:
 Plot (xk+1,yk-1)
 pk 1  pk  2xk 1  1  2 yk 1
Example

For example, given a circle of radius r=10, centred at the origin, the steps are:
 First, compute the initial decision variable:
o p0  1  r  9
 Plot (x0,y0) = (0,r) = (0,10)
 Iteration 0:
o p0 < 0, so
 Plot (x1,y1) = (x0+1,y0) = (1,10)

Computer Graphics Page 12


  p1  p0  2x1  1  9  3  6
 Iteration 1:
o p1 < 0, so
 Plot (x2,y2) = (x1+1,y1) = (2,10)
  p2  p1  2x2 1  6  5  1
 Iteration 2:
o p2 < 0, so
 Plot (x3,y3) = (x2+1,y2) = (3,10)
  p3  p2  2x3  1  1  7  6
 Iteration 3:
o p3 ≥ 0, so
 Plot (x4,y4) = (x3+1,y3-1) = (4,9)
  p4  p3  2x4  1  2 y4  6  9  3
 Iteration 4:
o p4 < 0, so
 Plot (x5,y5) = (x4+1,y4) = (5,9)
  p5  p4  2x5  1  3  11  8
 Iteration 5:
o p5 ≥ 0, so
 Plot (x6,y6) = (x5+1,y5-1) = (6,8)
 p6  p5  2x6  1  2 y6  8  3  5
 Etc.

5. Fill-Area Primitives

The most common type of primitive in 3-D computer graphics is the fill-area primitive.
The term fill-area primitive refers to any enclosed boundary that can be filled with a solid
color or pattern. However, fill-area primitives are normally polygons, as they can be filled
more efficiently by graphics packages. Polygons are 2-D shapes whose boundary is
formed by any number of connected straight-line segments. They can be defined by three
or more coplanar vertices (coplanar points are positioned on the same plane). Each pair
of adjacent vertices is connected in sequence by edges. Normally polygons should have
no edge crossings: in this case they are known as simple polygons or standard polygons
(see Figure 8).

Figure 8 - A Polygon with an Edge Crossing

Polygons are the most common form of graphics primitive because they form the basis of
polygonal meshes, which is the most common representation for 3-D graphics objects.

Computer Graphics Page 13


Polygonal meshes approximate curved surfaces by forming a mesh of simple polygons.
Some examples of polygonal meshes are shown in Figure 9.

Figure 9 - Examples of Polygonal Mesh Surfaces

5.1. Convex and Concave Polygons

We can differentiate between convex and concave polygons:


 Convex polygons have all interior angles ≤ 180o
 Concave polygons have at least one interior angle > 180o
The difference between convex and concave polygons is shown in Figure 10. Many
graphics packages (including OpenGL) require all fill-area polygons to be convex
polygons. The reason for this, as we will see in Chapter 3, is that it is much more efficient
to fill a polygon if we know it is convex. Some packages even require that all fill-area
primitives are triangles, as this makes filling even more straightforward.

(a) (b)
Figure 10 – Types of Polygon: (a) Convex; (b) Concave

5.2. Polygon Inside-Outside Tests

In order to fill polygons we need some way of telling if a given point is inside or outside
the polygon boundary: we call this an inside-outside test.

We will examine two different inside-outside tests: the odd-even rule and the nonzero
winding number rule. Both techniques give good results, and in fact usually their results
are the same, apart from for some more complex polygons.

5.2.1. Odd-Even Rule

The odd-even rule is illustrated in Figure 11(a). Using this technique, we determine if a
point P is inside or outside the polygon boundary by the following steps:

Computer Graphics Page 14


 Draw a line from P to some distant point (that is known to be outside the polygon
boundary).
 Count the number of crossings of this line with the polygon boundary:
o If the number of crossings is odd, then P is inside the polygon boundary.
o If the number of crossings is even, then P is outside the polygon boundary.
We can see from Figure 11(a) that the two white regions are considered to be outside the
polygon since they have two line crossings to any distant points.

5.2.2. Nonzero Winding Number Rule

The nonzero winding number rule is similar to the odd-even rule, and is illustrated in
Figure 11(b). This time we consider each edge of the polygon to be a vector, i.e. they
have a direction as well as a position. These vectors are directed in a particular order
around the boundary of the polygon (the programmer defines which direction the vectors
go). Now we decide if a point P is inside or outside the boundary as follows:
 Draw a line from P to some distant point (that is known to be outside the polygon
boundary).
 At each edge crossing, add 1 to the winding number if the edge goes from right to
left, and subtract 1 if it goes from left to right.
o If the total winding number is nonzero, P is inside the polygon boundary.
o If the total winding number is zero, P is outside the polygon boundary.
We can see from Figure 11(b) that the nonzero winding number rule gives a slightly
different result from the odd-even rule for the example polygon given. In fact, for most
polygons (including all convex polygons) the two algorithms give the same result. But for
more complex polygons such as that shown in Figure 11 the nonzero winding number
rule allows the programmer a bit more flexibility, since they can control the order of the
edge vectors to get the results they want.

(a) (b)
Figure 11 - Inside-Outside Tests for Polygons

5.3. Representing Polygons

Polygons, and in particular convex polygons, are the most common type of primitive in
3-D graphics because they are used to represent polygonal meshes such as those shown in

Computer Graphics Page 15


Figure 9. But how can polygonal meshes be represented? A common technique is to use
tables of data. These tables can be of two different types:
 Geometric tables: These store information about the geometry of the polygonal
mesh, i.e. what are the shapes/positions of the polygons?
 Attribute tables: These store information about the appearance of the polygonal
mesh, i.e. what colour is it, is it opaque or transparent, etc. This information can
be specified for each polygon individually or for the mesh as a whole.

Error! Reference source not found. shows a simple example of a geometric table. We
can see that there are three tables: a vertex table, an edge table and a surface-facet table.
The edge table has pointers into the vertex table to indicate which vertices comprise the
edge. Similarly the surface-facet table has pointers into the edge table. This is a compact
representation for a polygonal mesh, because each vertex’s coordinates are only stored
once, in the vertex table, and also information about each edge is only stored once.

5.4. OpenGL Fill-Area Routines

OpenGL provides a variety of routines to draw fill-area polygons. In all cases these
polygons must be convex. In most cases the vertices should be specified in an anti-
clockwise direction when viewing the polygon from outside the object, i.e. if you want
the front-face to point towards you. The default fill-style is solid, in a color determined by
the current color settings.

In all, there are seven different ways to draw polygons in OpenGL:


 glRect*
 Six different symbolic constants for use with glBegin … glEnd
We will now consider each of these techniques in turn.

glRect*

Two-dimensional rectangles can also be drawn using some of the other techniques
described below, but because drawing rectangles in 2-D is a common task OpenGL
provides the glRect* routine especially for this purpose (glRect* is more efficient for 2-D
graphics than the other alternatives). The basic format of the routine is:

glRect* (x1, y1, x2, y2)

Computer Graphics Page 16


where (x1,y1) and (x2,y2) define opposite corners of the rectangle. Actually when we call
the glRect* routine, OpenGL will construct a polygon with vertices defined in the
following order:

(x1,y1), (x2,y1), (x2,y2), (x1,y2)

For example, Figure 12 shows an example of executing the following call to glRecti:

glRecti(200,100,50,250);

(The black crosses are only shown for the purpose of illustrating where the opposing
corners of the rectangle are.)

In 2-D graphics we don’t need to worry about front and back faces – both faces will be
displayed. But if we use glRect* in 3-D graphics we must be careful. For example, in the
above example we actually specified the vertices in a clockwise order. This would mean
that the back-face would be facing toward the camera. To get an anti-clockwise order
(and the front-face pointing towards the camera), we must specify the bottom-left and
top-right corners in the call to glRect*.

Figure 12 - Drawing a 2-D Rectangle with the OpenGL routine glRect*

GL_POLYGON

The GL_POLYGON symbolic constant defines a single convex polygon. Like all of the
following techniques for drawing fill-area primitives it should be used as the argument to
the glBegin routine. For example, the code shown below will draw the shape shown in
Figure 13. Notice that the vertices of the
polygon are specified in anti-clockwise order.

glBegin(GL_POLYGON);

Computer Graphics Page 17


glVertex2iv(p1);
glVertex2iv(p2);
glVertex2iv(p3);
glVertex2iv(p4);
glVertex2iv(p5);
glVertex2iv(p6);
glEnd();

Figure 13 - A Polygon Drawn Using the


GL_POLYGON OpenGL Primitive
GL_TRIANGLES

The GL_TRIANGLES symbolic constant causes the glBegin … glEnd pair to treat the
vertex list as groups of three 3 vertices, each of which defines a triangle. The vertices of
each triangle must be specified in anti-clockwise order. Figure 14 illustrates the use of the
GL_TRIANGLES primitive.
glBegin(GL_TRIANGLES);
glVertex2iv(p1);
glVertex2iv(p2);
glVertex2iv(p6);
glVertex2iv(p3);
glVertex2iv(p4);
glVertex2iv(p5);
glEnd();

Figure 14 - Triangles Drawn Using the


GL_TRIANGLES OpenGL Primitive
GL_TRIANGLE_STRIP

To form polygonal meshes it is often convenient to define a number of triangles using a


single glBegin … glEnd pair. The GL_TRIANGLE_STRIP primitive enables us to define a
strip of connected triangles. The vertices of the first triangle only must be specified in
anti-clockwise order. Figure 15 illustrates the use
of GL_TRIANGLE_STRIP.
glBegin(GL_TRIANGLE_STRIP);
glVertex2iv(p1);
glVertex2iv(p2);
glVertex2iv(p6);
glVertex2iv(p3);
glVertex2iv(p5);
glVertex2iv(p4);
glEnd();

Figure 15 - Triangles Drawn Using the


GL_TRIANGLE_STRIP OpenGL
Primitive

Computer Graphics Page 18


GL_TRIANGLE_FAN

GL_TRIANGLE_FAN is similar to GL_TRIANGLE_STRIP, in that it allows us to define a


number of triangles using a single glBegin … glEnd command. In this case, we can define
a ‘fan’ of triangles emanating from a single point. The first point of the first triangle is the
source of the fan, and the vertices of this triangle must be specified in an anti-clockwise
direction. In addition, the fan of triangles must also be defined in an anti-clockwise
direction. See Figure 16 for an example of the use of GL_TRIANGLE_FAN.

glBegin(GL_TRIANGLE_FAN);
glVertex2iv(p1);
glVertex2iv(p2);
glVertex2iv(p3);
glVertex2iv(p4);
glVertex2iv(p5);
glVertex2iv(p6);
glEnd();
GL_QUADS

Using the GL_QUADS primitive, the vertex Figure 16 - Triangles Drawn Using the
list is treated as groups of four vertices, each GL_TRIANGLE_FAN OpenGL
of which forms a quadrilateral. If the number Primitive
of vertices specified is not a multiple of four, then the extra vertices are ignored. The
vertices for each quadrilateral must be defined in an anti-clockwise direction. See Figure
17 for an example of GL_QUADS.
glBegin(GL_QUADS);
glVertex2iv(p1);
glVertex2iv(p2);
glVertex2iv(p3);
glVertex2iv(p4);
glVertex2iv(p5);
glVertex2iv(p6);
glVertex2iv(p7);
glVertex2iv(p8);
glEnd(); Figure 17 - Quadrilaterals Drawn Using the
GL_QUADS OpenGL Primitive
GL_QUAD_STRIP

In the same way that GL_TRIANGLE_STRIP allowed us to define a strip of connected


triangles, GL_QUAD_STRIP allows us to define a strip of quadrilaterals. The first four
vertices form the first quadrilateral, and each subsequent pair of vertices is combined
with the two before them to form another quadrilateral. The vertices of the first
quadrilateral must be specified in an anti-clockwise direction. Figure 18 illustrates the use
of GL_QUAD_STRIP.

Computer Graphics Page 19


glBegin(GL_QUAD_STRIP);
glVertex2iv(p1);
glVertex2iv(p2);
glVertex2iv(p3);
glVertex2iv(p4);
glVertex2iv(p5);
glVertex2iv(p6);
glVertex2iv(p7);
glVertex2iv(p8);
glEnd(); Figure 18 - Quadrilaterals Drawn Using the
GL_QUAD_STRIP OpenGL Primitive
6. Character Primitives

The final type of graphics primitive we will consider is the character primitive. Character
primitives can be used to display text characters. Before we examine how to display
characters in OpenGL, let us consider some basic concepts about text characters.

We can identify two different types of representation for characters: bitmap and stroke
(or outline) representations. Using a bitmap representation (or font), characters are stored
as a grid of pixel values (see Figure 19(a)). This is a simple representation that allows fast
rendering of the character. However, such representations are not easily scalable: if we
want to draw a larger version of a character defined using a bitmap we will get an
aliasing effect (the edges of the characters will appear jagged due to the low resolution).
Similarly, we cannot easily generate bold or italic versions of the character. For this
reason, when using bitmap fonts we normally need to store multiple fonts to represent the
characters in different sizes/styles etc.

An alternative representation to bitmaps is the stroke, or outline, representation (see


Figure 19(b)). Using stroke representations characters are stored using line or curve
primitives. To draw the character we must convert these primitives into pixel values on
the display. As such, they are much more easily scalable: to generate a larger version of
the character we just multiply the coordinates of the line/curve primitives by some
scaling factor. Bold and italic characters can be generated using a similar approach. The
disadvantage of stroke fonts is that they take longer to draw than bitmap fonts.

Arial is a sans-serif font


Verdana is a sans-serif font
Times Roman is a serif font
Garamond is a serif font

Finally, we can categorise fonts as either monospace or proportional fonts. Characters


drawn using a monospace font will always take up the same width on the display,
regardless of which character is being drawn. With proportional fonts, the width used on
the display will be proportional to the actual width of the character, e.g. the letter ‘i’ will

Computer Graphics Page 20


take up less width than the letter ‘w’. As shown below, Courier is an example of a
monospace font whereas Times-Roman and Arial are examples of proportional fonts:

Courier is a monospace font


Times-Roman is a proportional font
Arial is a proportional font

(a) (b)

Figure 19 - Bitmap and Stroke Character Primitives

7. OpenGL Character Primitive Routines

OpenGL on its own does not contain any routines dedicated to drawing text characters.
However, the glut library does contain two different routines for drawing individual
characters (not strings). Before drawing any character, we must first set the raster
position, i.e. where will the character be drawn. We need to do this only once for each
sequence of characters. After each character is drawn the raster position will be
automatically updated ready for drawing the next character. To set the raster position we
use the glRasterPos2i routine. For example,

glRasterPos2i(x, y)

positions the raster at coordinate location (x,y).

Next, we can display our characters. The routine we use to do this will depend on
whether we want to draw a bitmap or stroke character. For bitmap characters we can
write, for example,

glutBitmapCharacter(GLUT_BITMAP_9_BY_15, ‘a’);

This will draw the character ‘a’ in a monospace bitmap font with width 9 and height 15
pixels. There are a number of alternative symbolic constants that we can use in place of
GLUT_BITMAP_9_BY_15 to specify different types of bitmap font. For example,
 GLUT_BITMAP_8_BY_13
 GLUT_BITMAP_9_BY_15

Computer Graphics Page 21


We can specify proportional bitmap fonts using the following symbolic constants:
 GLUT_BITMAP_TIMES_ROMAN_10
 GLUT_BITMAP_HELVETICA_10
Here, the number represents the height of the font.

Alternatively, we can use stroke fonts using the glutStrokeCharacter routine. For
example,

glutStrokeCharacter(GLUT_STROKE_ROMAN, ‘a’);

This will draw the letter ‘a’ using the Roman stroke font, which is a proportional font.
We can specify a monospace stroke font using the following symbolic constant:
 GLUT_STROKE_MONO_ROMAN

Summary

The following points summarise the key concepts of this chapter:


 Graphics primitives are the basic building blocks of images.
 Geometric primitives describe the geometry, or shape, of these building blocks.
 The GL_POINTS primitive can be used to draw points in OpenGL.
 The DDA (Digital Differential Analyser) line-drawing algorithm computes
successive points by iteratively adding the x and y offsets δx and δy onto the
previously computed location.
 Bresenham’s line-drawing algorithm is the most efficient line-drawing algorithm,
and determines computes successive points by computing a decision function,
which can be calculated using integer calculations only.
 The GL_LINES primitive can be used to draw separate line segments in OpenGL.
 The GL_LINE_STRIP and GL_LINE_LOOP primitives can be used to draw
polylines (connected line segments) in OpenGL.
 Circles can be drawn by plotting Cartesian or polar coordinates.
 The efficiency of any circle-drawing algorithm can be improved by taking
advantage of the four-way symmetry of circles: for each point we compute, we
can generate seven more through symmetry.
 The midpoint algorithm is the most efficient circle-drawing algorithm, and works
in a similar way to Bresenham’s line-drawing algorithm: successive points are
determined by computing a decision function, which can be calculated using
integer calculations only.
 The midpoint algorithm can also be adapted to work with ellipses, but ellipses
have only two-way symmetry, so drawing them is less efficient than drawing
circles.
 A fill-area primitive is any boundary that can be filled. Most fill-area primitives
are polygons.
 Polygon primitives are typically used to construct 3-D objects in the form of a
polygonal mesh.

Computer Graphics Page 22


 Polygonal meshes are normally represented using a geometric table, which
consists of a vertex table, an edge table and a surface-facet table.
 A simple polygon, or standard polygon, is one with no edge crossings.
 A convex polygon is one in which all interior angles are less or equal to 180o. If a
polygon has at least one interior angle greater than 180o it is a concave polygon.
 An inside-outside test determines if a given point is inside or outside a polygon
boundary.
 Common inside-outside tests are the odd-even rule and the nonzero winding
number rule.
 The front-face of a polygon is normally the face that is pointing out from the
surface of the polygonal mesh.
 The back-face of a polygon points in to the interior of the object.
 The front-face of a polygon is normally identified by a surface normal vector.
 Surface normal vectors can be computed by taking the cross-product of any two
adjacent edge vectors.
 OpenGL requires that all polygons are convex polygons.
 The glRect* routine can be used to draw 2-D rectangles in OpenGL.
 The GL_POLYGON, GL_TRIANGLES and GL_QUADS and primitives can be
used to draw fill-area polygons in OpenGL
 The GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN and GL_QUAD_STRIP
primitives can be used to draw connected sets of fill-area polygons in OpenGL.
 Character primitives can be drawn using either bitmap or stroke fonts:
o Bitmap fonts represent characters using a grid of pixel values. They are
efficient to draw but not easily scalable.
o Stroke (or outline) fonts represent characters using line or curve
primitives. They are less efficient to draw but are easily scalable.
 Fonts can be either serif or sans-serif: serif fonts feature accents at the ends of the
lines whereas sans-serif fonts do not.
 Fonts can be either monospace or proportional: monospace fonts use the same
width for each character whereas proportional fonts use a width proportional to
the width of the character.
 The glutBitmapCharacter routine can be used to draw a bitmap character
primitive in OpenGL.
 The glutStrokeCharacter routine can be used to draw a stroke character primitive
in OpenGL.

Computer Graphics Page 23


Exercises

1) The figure below shows the start and end points of a straight line.

a. Show how the DDA algorithm would draw the line between the two points.

b. Show how Bresenham’s algorithm would draw the line between the two points.

2) Show how the following circle-drawing algorithms would draw a circle of radius 5
centred on the origin. You need only consider the upper-right octant of the circle,
i.e. the arc shown in red in the figure below.

a. Plotting points using Cartesian coordinates.

b. Plotting points using polar coordinates.

c. The midpoint algorithm.

3) Show which parts of the fill-area primitive shown below would be classified as
inside or outside using the following inside-outside tests:

a. Odd-even rule.

b. Nonzero winding number rule.

Computer Graphics Page 24


4) Write a C++/OpenGL program to read in a string and a sequence of points from a
file, and display the string as a title and the points as triangles using the
GL_TRIANGLES primitive. For example, the file listed below would lead to the
following image being displayed.

Triangle_Demo
150 100
150 150
100 100
200 100
300 100
260 200
150 300
200 400
100 300

Computer Graphics Page 25


Exercise Solutions

1) The final line would be as shown below:

a. First we calculate the gradient:


y  y0   (2  0)  2  0.67
m  end
xend  x0  (3  0) 3
Now, because |m| ≤ 1, we compute δx and δy as follows:
δx = 1
δy = 0.67

Using these values of δx and δy we can now start to plot line points:
o Start with (x0,y0) = (0,0) – colour this pixel
o Next, (x1,y1) = (0+1,0+0.67) = (1,0.67) – so we colour pixel (1,1)
o Next, (x2,y2) = (1+1,1 +0.67) = (2,1.33) – so we colour pixel (2,1)
o Next, (x3,y3) = (2+1,1 +0.67) = (3,2) – so we colour pixel (3,2)
o We have now reached the end-point (xend,yend), so the algorithm terminates

b. First, compute the following values:


o Δx = 3
o Δy = 2
o 2Δy = 4
o 2Δy - 2Δx = -2
o p0  2y  x  2  2  3  1
Plot (x0,y0) = (0,0)
Iteration 0:
o p0 ≥ 0, so
 Plot (x1,y1) = (x0+1,y0+1) = (1,1)
  p1  p0  2y  2x  1  2  1
Iteration 1:
o p1 < 0, so
 Plot (x2,y2) = (x1+1,y1) = (2,1)
  p2  p1  2y  1 4  3
Iteration 2:
o p2 ≥ 0, so
 Plot (x3,y3) = (x2+1,y2+1) = (3,2)
 p3  p2  2y  2x  3  2  1

Computer Graphics Page 26


2) The answers are:

a. We start from x = 0, and then successively increment xand calculate the


corresponding y using Eq. (17): y  yc  r 2  xc  x . We can tell that we
2

have left the first octant when x > y.


o x = 0, y  0  52  0  02  5 , so we plot (0,5).
o x = 1, y  0  52  0 12  4.9 , so we plot (4.9,1) = (1,5).
o x = 2, y  0  52  0  22  4.58 , so we plot (4.58,2) = (2,5).
o x = 3, y  0  52  0  32  4 , so we plot (3,4).
o x = 4, y  0  52  0  42  3 , so x > y and we stop.
The figure below shows the first quadrant of the circle, with the plotted points
shown in blue, and points generated by symmetry in grey.

b. First we calculate the angular increment using θ = 1/r radians. This is equal to
(1/5)*(180/π) = 11.46o. Then we start with θ = 90o, and compute x and y
according to Eqs. (15) and (16) for successive value of θ, subtracting 11.46o at
each iteration. We stop when θ becomes less than 45o.
o θ = 90o, x  0  5cos90o  0 , y  0  5sin 90 o  5 , so we plot (0,5)
o θ = 78.54o, x  0  5cos78.54  0.99 , y  0  5sin 78.54 o  4.9 , so we
o

plot (1,5)
o θ = 67.08o, x  0  5cos67.08  1.95, y  0  5sin 67.08 o  4.6 , so we
o

plot (2,5)
o θ = 55.62o, x  0  5cos55.62o  2.82 , y  0  5sin 55.62 o  4.13 , so we
plot (3,4)
o θ = 44.16o, which is less than 45o, so we stop.
The points plotted are the same as for the Cartesian plotting algorithm.

Computer Graphics Page 27


c. The steps of the algorithm are:
o Plot the first circle point (0,r) = (0,5)
o Compute the first value of the decision variable p0 = 1 – r = -4
o Iteration 0:
 p0 < 0, so we plot (x0+1,y0) = (1,5)
 p1  p0  2x1  1  4  2 1  1  1
o Iteration 1:
 p1 < 0, so we plot (x1+1,y1) = (2,5)
 p2  p1  2x1 1  1 2  2 1  4
o Iteration 2:
 p2 ≥ 0, so we plot (x2+1,y2-1) = (3,4)
 p3  p2  2x3  1  2 y3  4  2  3  1  2  4  3
o Iteration 3:
 p3 ≥ 0, so we plot (x3+1,y3-1) = (4,3)
 At this point, x > y so we have left the octant and the algorithm
stops.

3) The figure below shows the classifications for each of the algorithms: the grey
shaded areas are classified as inside, and the white areas as outside. In this case the
two algorithms produce different results. The odd-even rule classifies the inner
polygon as outside because points inside it have two (an even number) line
crossings to reach any distant point. For the nonzero winding number rule, both of
the line crossings go from right to left, so the winding number is incremented in
both cases. Therefore the total winding number for points inside the inner polygon
is 2, which in nonzero and so the points are classified as inside. By reversing the
direction of the edge vectors of the inner (or outer) polygon we could get the same
result as the odd-even rule.

4) See the code listing included in the zip file for this handout for the solution to this
question.

Source: Computer Graphics with OpenGL, Donald Hearn and M.


Pauline Baker, Prentice-Hall, 2004 (Third Edition)

Computer Graphics Page 28


Programs Using OPENGL using DEVC++

// 1. PROGRAM FOR DDA LINE DRAWING ALGORITHM


#include<GL/glut.h>
#include<stdlib.h>
float xstart=10,ystart=10,xend=400,yend=480,step,xinc,yinc,x,y;
void drawline()
{
float ydiff = yend-ystart;
float xdiff = xend-xstart;
if (abs(xdiff) > abs(ydiff))
step = abs(xdiff);
else
step = abs(ydiff);
xinc = xdiff/step;
yinc = ydiff/step;
x = xstart;
y = ystart;
glColor3f(1,0,0);
glPointSize(3);
while ((x != xend)&(y != yend))
{
glBegin(GL_POINTS);
glVertex2f(x,y);
x = x+xinc;
y = y+yinc;
}
glEnd();
}
void display(void){
glClear(GL_COLOR_BUFFER_BIT);
drawline();
glFlush();
}
void MyInit(){
glClearColor(1, 1, 1, 0.0); // white background
glColor3i(1,0,0); // black foreground
glPointSize(2.0); // size of points to be drawn (in pixels)
gluOrtho2D(0.0, 640.0, 0.0, 480.0);
}
int main(int argc,char* argv[]){
glutInit(&argc,argv);
glutInitWindowSize(640,480);
glutInitWindowPosition(100,100);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutCreateWindow("DDA Line Drawing");

Computer Graphics Page 29


glutDisplayFunc(display);
MyInit();
glutMainLoop();
return 0;
}
//2. Program for Bresenhams Line Drawing Algorithm
#include<GL/glut.h>
#include<stdlib.h>
#include<math.h>
float xstart=10,ystart=10,xend=400,yend=400,p,x,y;
void drawline()
{ float ydiff = yend-ystart;
float xdiff = xend-xstart;
p= 2*ydiff - xdiff;
x = xstart;
y = ystart;
glColor3f(0,1,0); //drawing color
glPointSize(3); //size in pixel
while (x < xend)
{ glBegin(GL_POINTS);
glVertex2f(x,y);
if (p<0)
{ x=x+1;
y=y;
p = p + 2*ydiff;
}
else
{ x=x+1;
y=y+1;
p= p+2*ydiff-2*xdiff; }}
glEnd();
}
void display(void){
//glClear(GL_COLOR_BUFFER_BIT);
drawline();
glFlush();
}
void MyInit(void)
{ glClearColor(1, 0, 0, 0); // white background
//glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0,0,0); // black foreground
glPointSize(1.0); // size of points to be drawn (in pixels)
gluOrtho2D(0.0, 640.0, 0.0, 480.0);// ortho graphics projection
}
int main(int argc,char* argv[]){
glutInit(&argc,argv);

Computer Graphics Page 30


glutInitWindowSize(640,480);
glutInitWindowPosition(10,10);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutCreateWindow("Bresenhams Line Drawing");
glutDisplayFunc(display);
MyInit();
glutMainLoop();
return 0;
}
//3.Program for Midpoint Circle Drawing Algorithm
#include<GL/glut.h>
void circleMidPoint()
{
int xCenter = 300 ;
int yCenter = 200;
int radius = 100;
int x = 0;
int y = radius;
int p = 1 - radius;//5/4 is rounded to 1 for integer radius
while(x<y) {// iterates to draw the first sector
x++;
if(p < 0)// the mid point is inside the circle
p += 2*x + 1;
else {// the mid point is outside or at the circle
y--;
p += 2 * (x - y) + 1;
}
glBegin(GL_POINTS);
glVertex2i(xCenter + x, yCenter + y);
glVertex2i(xCenter - x, yCenter + y);
glVertex2i(xCenter + x, yCenter - y);
glVertex2i(xCenter - x, yCenter - y);
glVertex2i(xCenter + y, yCenter + x);
glVertex2i(xCenter - y, yCenter + x);
glVertex2i(xCenter + y, yCenter - x);
glVertex2i(xCenter - y, yCenter - x);
glEnd();
}
// OPTIONAL:-> center of the circle
glBegin(GL_POINTS);
glVertex2i(xCenter,yCenter);
glEnd(); }
void display()
{ glClearColor(1.0,1.0,1.0,0.0); // white background
glClear(GL_COLOR_BUFFER_BIT); // clear the screen
glColor3f(1.0,0.0,0.0); // red foreground

Computer Graphics Page 31


glPointSize(5.0); // size of points to be drawin (in pixel)
gluOrtho2D(0.0, 640.0, 0.0, 480.0);
circleMidPoint();
glFlush(); // send all output to the display
}
int main()
{ glutInitWindowSize(640,480); // set the size of the window
glutInitWindowPosition(10,10); // the position of the top-left of window
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutCreateWindow("Midpoint Circle Drawing Algorithm");
glutDisplayFunc(display); // set the GLUT display callback function
glutMainLoop(); // enter the GL event loop
return 0;
}
//4.Program using OpenGL to display line primitives
#include<GL/glut.h>
#include<stdlib.h>
int z;
void myInit(void){;
glClearColor(1.0,1.0,1.0,0.0); // white background
glColor3f(1.0,0.0,0.0); // red foreground
glPointSize(8.0); // size of points to be drawin (in pixel)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 640.0, 0.0, 480.0);
}
void Line()
{
glBegin(GL_LINES);
glVertex2i(50,100);
glVertex2i(300,400);
glEnd();
}
void Linestrip()
{
glBegin(GL_LINE_STRIP);
glVertex2i(200,100);
glVertex2i(50,0);
glVertex2i(100,200);
glVertex2i(150,0);
glVertex2i(0,100);
glEnd();
}
void Lineloop()
{
glBegin(GL_LINE_LOOP);

Computer Graphics Page 32


glVertex2i(350,250);
glVertex2i(200,150);
glVertex2i(250,350);
glVertex2i(300,150);
glVertex2i(150,250);
glEnd();
}
void display(void){
glClear(GL_COLOR_BUFFER_BIT); // clear the screen
switch(z)
{
case 1:
Line();
break;
case 2:
Linestrip();
break;
case 3:
Lineloop();
break;
}
glFlush(); // send all output to the display
}
void keyboard(unsigned char key, int , int )
{
switch(key)
{
case 'L':
case 'l':
z=1;
break;
case 'S':
case 's':
z=2;
break;
case 'C':
case 'c':
z=3;
break;
case 'Q':
case 'q':
exit(1);
break;
}
glutPostRedisplay();
}

Computer Graphics Page 33


int main(int argc, char *argv[])
{
glutInit(&argc, argv); // initialise the glut library
glutInitWindowSize(640,480); // set the size of the window
glutInitWindowPosition(10,10); // the position of the top-left of window
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutCreateWindow("Output Primitives");
glutDisplayFunc(display); // set the GLUT display callback function
glutKeyboardFunc(keyboard);//keyboard event handler
myInit(); // perform other initialisation of OpenGL settings
glutMainLoop(); // enter the GL event loop
return 0;
}

//5.Program for OpenGL Fill area Primitives


#include<GL/glut.h>
#include<stdlib.h>
int z;
void myInit(void){;
glClearColor(1.0,1.0,1.0,0.0); // white background
glColor3f(1.0,0.0,0.0); // red foreground
glPointSize(8.0); // size of points to be drawin (in pixel)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 640.0, 0.0, 480.0);
}
void rec()
{
glRecti(200,100,50,250);
}
void tri()
{
glBegin(GL_TRIANGLES);
glVertex2f(100.0, 400.0);
glVertex2f(150.0, 420.0);
glVertex2f(180.0, 390.0);
glVertex2f(90.0, 350.0);
glVertex2f(100.0, 390.0);
glVertex2f(130.0, 380.0);
glVertex2f(130.0, 350.0);
glVertex2f(180.0, 350.0);
glVertex2f(150.0, 320.0);
glEnd();
}
void poly()
{

Computer Graphics Page 34


glBegin(GL_POLYGON);
glVertex2i(350,250);
glVertex2i(400,300);
glVertex2i(400,350);
glVertex2i(350,400);
glVertex2i(300,400);
glVertex2i(250,350);
glVertex2i(250,300);
glVertex2i(300,250);
glVertex2i(350,250);
glEnd();
}
void quad()
{
glBegin(GL_QUADS);
glVertex2f(500.0, 400.0);
glVertex2f(530.0, 410.0);
glVertex2f(525.0, 365.0);
glVertex2f(490.0, 350.0);
glVertex2f(500.0, 350.0);
glVertex2f(550.0, 350.0);
glVertex2f(550.0, 300.0);
glVertex2f(500.0, 300.0);
glEnd();
}
void display(void){
glClear(GL_COLOR_BUFFER_BIT); // clear the screen
switch(z)
{
case 1:
rec();
break;
case 2:
tri();
break;
case 3:
poly();
break;
case 4:
quad();
break;
}
glFlush(); // send all output to the display
}
void keyboard(unsigned char key, int , int )
{

Computer Graphics Page 35


switch(key)
{
case 'R':
case 'r':
z=1;
break;
case 'T':
case 't':
z=2;
break;
case 'P':
case 'p':
z=3;
break;
case 'Q':
case 'q':
z=4;
break;
case 'E':
case 'e' :
exit(1);
break;
}
glutPostRedisplay();
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv); // initialise the glut library
glutInitWindowSize(640,480); // set the size of the window
glutInitWindowPosition(10,10); // the position of the top-left of window
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutCreateWindow("Fill Area Primitives");
glutDisplayFunc(display); // set the GLUT display callback function
glutKeyboardFunc(keyboard);//keyboard event handler
myInit(); // perform other initialisation of OpenGL settings
glutMainLoop(); // enter the GL event loop
return 0;
}

Computer Graphics Page 36

You might also like