0% found this document useful (0 votes)
66 views39 pages

Chapter 5 Small

This document provides an overview of transformations in computer graphics. It discusses the goals of learning affine transformations including rotations, scaling, and translations. It defines fundamental transformation types such as translation, scaling, rotation, shearing, and their matrix representations. It explains how transformations map points to new locations and how they are used in computer graphics programs like OpenGL. Transformations allow composing scenes from objects and viewing scenes from different angles.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
66 views39 pages

Chapter 5 Small

This document provides an overview of transformations in computer graphics. It discusses the goals of learning affine transformations including rotations, scaling, and translations. It defines fundamental transformation types such as translation, scaling, rotation, shearing, and their matrix representations. It explains how transformations map points to new locations and how they are used in computer graphics programs like OpenGL. Transformations allow composing scenes from objects and viewing scenes from different angles.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 39

Computer Graphics CS 330

Spring 2011

Chapter 5,
Transformations of Objects
Goals of the Chapter

.To develop tools for transforming one picture into another
To introduce the fundamental concepts of affine transformations, which perform combinations of •
rotations, scaling, and translations

.To develop functions that applies affine transformations to objects in computer programs
.To develop tools for transforming coordinate frames •
.To see how to set up a camera to render a 3D scene using OpenGL •
To learn to design scenes in the Scene Design language SDL, and to write programs that read SDL •
.files and draw the scenes they describe

INTRODUCTION TO TRANSFORMATIONS

Figure 5.1 (a) shows two versions of a simple house, drawn before and after each of its points
has been transformed. In this case the house has been scaled down in size, rotated a small
amount, and then moved up and to the right.
The overall transformation is a combination of three elementary ones: scaling, rotation, and
translation. Figure 5.1(b) shows a 3D house before and after it is similarly transformed: Each
.3D point in the house is subjected to a scaling, a rotation, and a translation by the transformation

Fig 5.1, Drawings of Objects before and after they are transformed
:Transformations are very useful in a number of situations

a. We can compose a "scene" out of a number of objects, as in Figure 5.2. The scene is
fashioned by placing a number of “instances” of arch at different places and with
different sizes, using the proper transformation for each.

Fig 5.2 Composing a picture from many instances of a simple form

b. The snowflake exhibit certain symmetries. We can design a single “motif” and then
fashion the whole shape by appropriate reflections, rotations, and transformations of the
motif.
Fig 5.4 Using a “motif” to build up a figure

c. A designer may want to view an object from different vantage points and make a picture
from each one. The scene can be rotated and viewed with same camera, but it is more
natural to leave the scene alone and move the camera.

Fig 5.5 Viewing a scene from different vantage points


d. In computer animation, several objects must move relative to one another from frame o
frame. This effect can be achieved by shifting and rotating the separate local coordinate
system of each.
Using Transformations with OpenGL

A number of graphics platform, including OpenGL, provide a "graphics pipeline." or a sequence


of operations that are applied lo all points that are "sent through." A drawing is produced by
,processing each point

Figure 5,7 shows a simplified view of the OpenGL graphics pipeline. An application sends the
pipeline a sequence of points P1, P2, P3,... using commands like,

glBegin (GL_LINES);
glVertex3f (...); // send PI through the pipeline
glVertex3f (...): // send P2 through the pipeline
glVertex3f (...); // send P3 through the pipeline
glEnd ():

These points first encounter a transformation called the "current transformation" (CT), which
alters their values into a different set of points, say Q1, Q2, Q3, … Just as the original points Pi
describe some geometric object, the points Qi, describe the Transformed version of the same
object. These points are then sent through additional steps and ultimately are used lo draw the
final image on the display.
Fig 5.7 The OpenGL pipeline

5.2.1 Transforming Points and Objects


A transformation alters each point P in space (2D or 3D) into a new point Q by means of a
specific formula or algorithm.

Fig 5.8 Mapping points into new points.

As the figure illustrates, an arbitrary point P in the plane is mapped to another point Q. We say
that Q is the image of P under the mapping T. More formally, if S is a set of points, its image
T(S) is the set of all points T(P) , where P is some point in S.

We take the 2D case first, in whichever coordinate frame we are using, points P and Q have the
representations
Px Qx
P = Py and Q = Qy
1 1

respectively. This means that the point P is at location


P = Pxi + Pyj + q, and similarly for Q. Px and Py are called the "coordinates" of P.
Qx Px
Q y = T Py or Q = T(P)
1 1

Affine transformations have a simple form. The coordinates of Q are linear combinations of
those of P.
Qx m11 Px + m12Py + m13
Qy = m21 Px + m12Py + m23
1 1

The affine transformation of Equation has a useful matrix representation

Qx m11 m12 m13 Px


Qy = m21 m12 m23 Py
1 0 0 1 1

Example 5.2.1
An affine transformation is specified by the matrix
3 0 5
-2 1 2
0 0 1

Find the image Q of points P = (1, 2).


Solution
8 3 0 5 1
2= -2 1 2 2
1 0 0 1 1

Translation
To translate a picture into a different position on a graphics display
Qx 1 0 m13 Px
Qy = 0 1 m23 Py
1 0 0 1 1

or simply
Qx Px + m13
Qy = Py + m23
1 1

So, in ordinary coordinate Q = P + d, where the “offset vector” d is (m12, m23).

Example
If the offset vector is (2, 3), every point will be altered into a new point that is two units farther to
right and three units above. The point (1, -5), for instance, is transformed into (3, -2), and the
point (0, 0) is translated into (2, 3).

Scaling
Scaling changes the size of a picture and involves two scale factors, Sx, Sy, for the x- and y-
coordinates.
(Qx, Qy) = (SxPx, SyPy).
The matrix is
Sx 0 0
0 Sy 0
0 0 1

This is called scaling about the origin, because each point P is moved Sx times farther from the
origin in the x-direction and Sy times farther from the origin in the y-direction.

If a scale factor is negative, then there is also a


reflection about a coordinate axis. Fig 5.11, the
scaling (Sx, Sy) = (-1, 2) is applied to a collection of
points. Each point is both reflected about the y-axis
and scaled by 2 in the y-direction.
Fig 5.11 A scaling and a reflection

There are “pure” reflections, for which each of the scale factors is +1 or –1.
If the two factors are the same (Sx = Sy = S) , is a uniform scaling. If S is negative, there are
reflection about both axes.

Rotation
A fundamental graphics operation is the rotation of a
figure about a given point through some angle, as in Fig.

o
Fig 5.13 Rotation of points through an angle of 60

As When T() is a rotation about the origin, the offset vector d is zero and Q = T(P) the form

Qx = Px cos(q) – Pysin(q) 5.9


Qy = Px sin(q) – Pycos(q)

In terms of its matrix form, a pure rotation about the origin is given by

Qx cos(q) -sin(q) 0 Px
Qy = sin(q) cos(q) 0 Py
1 0 0 1 1

Derivation of the Rotation Mapping


Fig 5.14 shows how to find the coordinates of a point Q that results from rotating point P about
the origin through an angle q. If P is at a distance R from the origin at some angle f, then

P = (Rcos(f), Rsin(f)).

Q must be at the same distance as P and angle (q+f). So,


Qx = R cos(q+f), Qy = R sin(q+f).
cos(q+f) = cos(q)cos(f) - sin(q)sin(f)

and
sin(q+f) = sin(q)cos(f) + cos(q)sin(f)
and use
Px = Rcos(q+f) and Py = Rsin(q+f) to obtain eq. 5.9.
Fig 5.14, Derivation of the Rotation mapping

Fig 5.15 An example of shearing


Shearing
Fig 5.15 shows shearing “in x-direction”. The y-coordinate of each point is unaffected, whereas
each x-coordinate is translated by an amount that increases linearly with y. A shear in the x-
direction is given by
Qx = Px + hPy, Q y = Py
Where h specifies what fraction of the y-coordinate of P is to be added to the x-coordinate. The
matrix form is
1 h 0
0 1 0
0 0 1

A shear “along y”, Qx = Px and Qy = gPx + Py, for value g.

1 0 0
g 1 0
0 0 1

The Inverse of an Affine Transformation

If point P is mapped into point Q according to Q = MP, we simply pre-multiply both sides by
-1
the inverse of M denoted by M , and write
m22 -m12
-1
M = 1 .
det M -m21 m11

The following matrices for elementary inverse transformations


1. Scaling
1/Sx 0 0
-1
M = 0 1/Sy 0
0 0 1

2. Rotation
cos(q) sin(q) 0
-sin(q) cos(q) 0
-1
M =
0 0 1

3. Shearing
1 -h 0
-1
M = 0 1 0
0 0 1

4. Translations
1 0 -m13
-1
M = 0 1 -m23
0 0 1
​ 5.2.5 Composing Affine Transformations
An application requires that we build a compound transformation out of several elementary ones.
For example, we may want to
• Translate by (3, -4),
• Then rotate through 30o.
• Then scale by (2, -1).
• Then translate by (0, 15).
• And, finally, rotate through –30o.

The process of applying several transformations in succession to form one overall transformation
is called composing the transformations. Fig 5.16 T1() maps P into Q, and T2() maps Q into W.
The nature of W = T2(Q)=T2(T1(P))
Suppose the two transformations are represented by the matrices M1 and M2. P is transformed to
the point M1P, which is then transformed to M2(M1P). So, the later just (M2M1)P, and we have
W = MP.
Where M = M2M1.
Notice that the matrices appear in reverse order.
Fig 5.16 The composition of two transformations.

Example 5.2.5 Rotating about an arbitrary (Pivot) point


Suppose we wish to rotate points about some other
point in the plane rather than the origin. In Fig 5.17,
the desired “pivot” point is V=(Vx, Vy), and we wish
to rotate points such as P through an angle q to
position Q.

Fig 5.17 Rotation about a point


To do this, we must relate the rotation about V to an elementary rotation about the origin. The
rotation consists of the following three elementary transformations:
1. Translate point P through vector v = (-Vx, -Vy).
2. Rotate about the origin through angle q.
3. Translate P back through v.

Creating a matrix for each elementary transformation and multiplying the matrices out produces
1 0 Vx cos(q) -sin(q) 0 1 0 -Vx cos(q) -sin(q) dx
0 1 Vy sin(q) cos(q) 0 0 1 -Vy = sin(q) cos(q) dy
0 0 1 0 0 1 0 0 1 cos(q) 0 1

where
dx = -cos(q)Vx + sin(q)Vy + Vx
dy = -sin(q)Vx - cos(q)Vy + Vy

Example 5.2.6
Scaling and shearing about arbitrary “pivot” point
We do the same “shift-transform-unshift”.

Example 5.27 Reflections about a tiled line


Consider the line through the origin that makes an angle of b with the x-axis. Point A reflects
into point B, and each house shows reflects into the other.
• A rotation through the angle b (so that the axis of reflection coincides with the x-axis).
• A reflection about the x-axis.
• A rotation back through b that
“restores” the axis of reflection.
Fig 5.18 reflecting a point about a tiled axis
​We want to develop the transformation that reflects any point P about the line, called the axis of
reflection, to produce point Q.
1. A rotation through the angle b (the axis of reflection coincides with the x-axis).
2. A reflection about the x-axis.
3. A rotation back through b that “restores” the axis of reflection.
The over all transformation is given by the product of the following three matrices:
2 2
c s 0 1 0 0 c -s 0 c -s -2sc 0
2 2
-s c 0 0 -1 0 s c 0 = -2cs s -c 0
0 0 1 0 0 1 0 0 1 0 0 1

where c stand for cos(-), and s for sin(). We can rewrite

cos(2b) sin(2b) 0
sin(2b) - cos(2b) 0 (a reflection about the axis at angle b
0 0 1

5.3 3D Affine Transformations


we use coordinate frames and suppose that we have an origin q and three mutually
perpendicular axes in the directions i, j, and k. point P in this frame is given by

P = q + Pxi + Pyj + Pzk and so has the representation.

Px
P = Py .
Pz
1

The affine transformation that transform P to Q:

Qx m11 m12 m13 m14 Px


Qy = m21 m12 m23 m24 Py
Qz m31 m32 m33 m34 Px
1 0 0 1 1 1

point Q can be found by multiplying P by M.

Qx Px
Q y = M Py
Qz Pz
1 1
5.3.1 The Elementary 3D Transformations
Translation
For pure translation, the matrix is
1 0 0 m14
0 1 0 m24
0 0 1 m34
0 0 0 1

Scaling
The matrix is
Sx 0 0 0
0 Sy 0 0
0 0 Sz 0
0 0 0 1

Shearing
The matrix for the simplest elementary shear is the identity matrix with one zero term replaced
by some value, as in
1 0 0 0
f 1 0 0
0 0 1 0
0 0 0 1

Rotations
We often want to rotate an object or a camera in order to obtain different views. We must specify
an axis about which the rotation occurs, rather than just a single point.
The simplest rotation is a rotation about one of the coordinate axes. We call a rotation about the
x-axis an "x-roll," a rotation about the y-axis a "y-roll," and a rotation about the z-axis a "z-roll."

The rotation is through an angle b, about the given axis. We define positive angles using a
"looking inward" convention:

Positive values of b cause a counterclockwise (CCW) rotation


about an axis as one looks inward from a point on the positive
axis toward the origin.
Fig 5,25 Positive rotations about the three axes.

In the particular case of a 90° rotation:


• For a z-roll, the x-axis rotates to the y-axis.
• For an x-roll, the y-axis rotates to the z-axis.
• For a y-roll, the z-axis rotates to the x-axis.
The following three matrices represent transformations that rotate points through an angle b
about a coordinate axis.
1. An x-roll
1 0 0 0
0 c -s 0
Rx(b) = 0 s c 0
0 0 0 1

2. A y-roll

c 0 s 0
0 1 0 0
Ry(b) = 0 -s c 0
0 0 0 1

3. A z-roll
c -s 0 0
s c 0 0
Rz(b) = 0 0 1 0
0 0 0 1

5.5 USING AFFINE TRANSFORMATIONS IN A PROGRAM


We want to see how to apply the theory of affine transformations in a program to carry out the
scaling, rotating, and translating of graphical objects.

Suppose you have a routine house () that draws house #1 in Fig 5.34. But you wish instead to
draw house #2, shown rotated through -30° and then translated through (32, 25). This is a
frequently encountered situation; An object is defined at a convenient size and position, but we
want to draw it (perhaps many times) at different sizes, orientations, and locations.
Fig 5.34 Drawing a rotated and translated house.
After drawing house #, how do we arrange matters so that house #2 is drawn instead? There are
tow ways:

The Hard Way


With this approach, we construct the matrix for the desired transformation, say, M, and build a
routine, say, transform 2D(), that transforms one point into another, such that
Q = transform2D (M, P);

The routine produces Q=MP, then apply the transformation to each point V [i] in house ().

The Easy Way

The window-to-viewport mapping is "quietly" applied to each vertex as part of moveTo () and
lineTo(). We can have an additional transformation, the current transformation, CT. We enhance
move-To () and linsTo () so that they first quietly apply CT to the argument vertex and then apply
.the window-to-viewport mapping
As in Fig 5.35, When glVertex2d () is called with the argument V, the vertex V is first
transformed by the CT to form point Q, which is then passed through the window-to-viewport
mapping to form point S in the screen window.
Fig
5.35
The

current transformation is applied to vertices.

How do we extend moveTo () and lineTo () so that they quietly carry out this additional
mapping?
If you are not using OpenGL, you must write code that actually performs the transformation.
If you are using OpenGL, the transformation is done automatically! OpenGL maintains a so-
called modelview matrix, and every vertex that is passed down the graphics pipeline is
multiplied by this matrix.
.We need only set up the modelview matrix to embody the desired transformation
OpenGL works entirely in 3D, so its modelview matrix produces 3D transformations.

The principal routines for altering the modelview matrix are glRotated(), glScaled (), and
glTranslated (), (d indicated to double). These do not set the CT directly; instead, each
postmultiplies the CT (the modelview matrix) by a particular matrix, say, M, and puts the result
back into the CT. That is, each of the routines creates a matrix M required for the new
transformation and performs the operation

CT = CT* M
The following are OpenGL routines for applying transformations in the 2D case;

• gl Scaled (sx, sy, 1.0);


Postmultiply CT by a matrix that performs a scaling by sx in x and by sy in y; put the result back
into CT. No scaling in z is done.

• glTranslatcd (dx, dy, 0);


Postmultiply CT by a matrix that performs a translation by dx in x and by dy in y; put the result
back into CT. No translation in z is done.

• glRotated (angle, 0, 0, 1);


Postmultiply CT by a matrix that performs a rotation through angle degrees about the z-axis
[indicated by (0,0,1)], Put the result back into CT.

Since these routines only compose a transformation with the CT, we need some way to get
started:
to initialize the CT to the identity transformation. For that purpose OpenGL provides the routine
gILoadIdentity (). And because the functions listed can be set to work on any of the matrices
that OpenGL supports, we must inform OpenGL which matrix we are altering. This is
accomplished using

gIMatrixMode (GL_MODELV1EW).

cvs . setWindow (…) ;


cvs.setViewport(…); // set the window to viewport mapping
cvs.initCT() : //get started with the identity transformation
house (); // draw the untransformed house first
cvs.translate2D (32, 25) // CT now includes translation
cvs.rotate2D (-30.0); // CT now includes translation and rotation
house (); // draw the translaformed house
//<<<<<<<<<<<< initCT >>>>>>>>>>>>>>>
void Canvas:: initCT(void) {
glMatrixMode (GL_MODELVIEW):
glLoadIdentity(); // set CT to the identity matrix
}
//<<<<<<<<<<<< sca1e2D >>>>>>>>>>>>>
void Canvas:: scale2D (double sx, double sy) {
glMaLrixMode (GL_MODELVIEW) ;
gIScaled (sx, sy, 1.0); // set CT to CT * (2D scaling)
}
//<<<<<<<<<<< LranslaLe2D >>>>>>>>>>>>>>>
void Canvas :: translate2D (donb1e dx, double dy) {
glMatrixMode (GL_MODELVIEW);
glTranslated (dx, dy 0); // set CT to CT * (2D translation)
}
//<<<<<<<<<<< rotatc2D >>>>>>>>>>>>>
void Canvas:: rotate2D (double angle) {
glMatrixMode (GL_MODELVIEW);
glRotated (angle, 0.0, 0.0, 1.0); // set CT to CT * (2D rotation)

EXAMPLE 5.5.1 Capitalizing on rotational symmetry


Figure 5.39(a) shows a star made of stripes that seem to interlock with one another. Suppose that
routine starMotif () draws a part of the star—the polygon shown in Figure 5.39(b). Then, to draw
the whole star, we just draw the motif five times, each time rotating it through an additional 72°:

Fig 5.39 Using successive rotations of the coordinate system

for (int count = 0; count < 5 ; count++5) {


starMotif() ;
cvs.rotate2D (72.0): // concatenate another rotation
}

EXAMPLE 5.5.2 Drawing snowflakes


A snowflake has six identical spokes
oriented 60° apart, and each spoke is
symmetrical about its own axis. It is
easy to produce a complex snowflake
by designing one half of a spoke and
drawing it 12 times.

Fig 5.40 Designing a snowflake


A reflection about the x-axis is achieved by the use of scale 2D (l, -l), so the motif plus its
reflection can be drawn using the following code:
flakeMotif () ; // draw the top half
cva.scals2D(1.0, -1.0) : // flip it vertically
flakeMotif (); // draw the bottom half
cvs.scalc2D(1.0, 1.0); // restore the original axis
To draw the entire snowflake just execute this code six times, with an intervening rotation of 60°:
void drawFlake () {
for (int count = 0; count < 6; count++) {
flakeMotif () ;
cvs.scale2D (l.0. -1.0) :
flakeMotif () ;
cvs.sca1e2D (l .0 , -1,0);
cvs.rotatc2D (60.0);
}
}

5.5.1 Saving the CT for Later Use


A sequences of calls to rotate2D(), scala2D () ,and translate2D () make "additional" or
"relative” changes to the CT, but sometimes we may need to "back up"' to some prior CT. To
"remember" the desired CT, we make a copy of it and store it in a convenient location. Then,
we can restore the CT. We may even want to keep a collection of prior CT's, and return to
selected ones at key moments. To do this, you can work with a stack of transformations, as
suggested by Figure 5.43.
To save this CT for later use, a copy of it is made and "pushed" onto the stack using a routine
pushCT () .This makes the top two items on the stack identical. The top item can now be altered
further with additional transformation calls. To return to the previous CT, the top item is simply
"popped" off the stack using popCT () and then discarded. That way we can return to the most
recent CT, the next most recent CT, and so forth, in a last-in, first-out order.
Fig 5.43 Manipulating a stack of CT’s

The implementation of pushCT () and popCT () is simple with OpenGL, which has routines
glPushMatrix () and glPopMatrix () to manage several different slacks of matrices as in Figure
5.44.

Fig 5.44 Routines to save and restore CT's

void Canvas:: pushCT (void) {


glMatrixMode (GL_MODELVIEW);
glPushMatrix () ; // push a copy of the top matrix
}

void Canvas:: popCT(vuid) {


glMatrixMode (GL_MODELVIEW);
glPopMatrix () : / / pop the top matrix from the stack
}

EXAMPLE 5.5.5 Tilings made easy


As in Figure 5.45, the motif is drawn centered in its own coordinate system, as shown in Part (a).
Copies of the motif are drawn L units apart in the x-direction and D units apart in the y-direction,
as shown in Part (b).
Fig 5.45 A tiling based on a Motif. (a) The motif, (b) The tiling

Cvs.pushCT () : // so we can return here


cvs. translate2D (W, H); // position for the first motif
for (row = 0; row < 3; row++) { // draw each row
cvs.pushCT ();
for (col = 0; col < 4; co1++) { // draw the next row of motifs
motif ();
cvs.translate2D (L,0); // move to the right
}
cvs.popCT(); // back to the start of this row
cvs.translate2D ( 0 . D) ; / / move up to the next row
}

cvs.popCT(); // back to where we started


Fig 5.46 Drawing a hexagonal tiling

5.5.3 A hexagonal tiling


Fig 5.49 A simple hexagonal tiling

a. The length of each edge of a hexagon with radius R is also R.


b. The centers of adjacent hexagons in a column are separated vertically by √`3*R and that
adjacent column are separated horizontally by 3R/2.
c. Using pushCT () and popCTC () and suitable Transformations to keep track of where each row
and column start.

//<<<<<<<<<<<<<<<<<<<< Scale2D >>>>>>>>>>>>>>>>>>


void Scale2D (double sx, double sy) {
glMatrixMode (GL_MODELVIEW);
glScaled (sx, sy, 1.0);
}

//<<<<<<<<<<<<<<<<<< Translate2D >>>>>>>>>>>>>>>>>>


void Translate2D (double dx, double dy) {
glMatrixMode (GL_MODELVIEW);
glTranslated (dx, dy, 0.0);
}

//<<<<<<<<<<<<<<<<<<< Rotate2D >>>>>>>>>>>>>>>>>>


void Rotate2D (double angle) {
glMatrixMode (GL_MODELVIEW);
glRotated (angle, 0.0, 0.0, 1.0);
}
//<<<<<<<<<<<<<<<<<<< T_Letter >>>>>>>>>>>>>>>>>
void T_Letter (void) {
glBegin (GL_LINE_LOOP);
for (int k = 0; k < nPoints; k++)
glVertex2d(T[k][0], T[k][1]);
glEnd(); ​
glFlush(); ​ // send all output to display
}

//<<<<<<<<<<<<<<< myDisplay >>>>>>>>>>>>>>>>>>>>>


void myDisplay (void) {
double left, right, bottom, top;
​ left = -200.0, right = 200., bottom = -200.0, top = 200.;
​ setWindow (left, right, bottom, top); // entire world window
glViewport (0, 0, 400, 400);
T_Letter ();
Scale2D (0.5, 0.5);
T_Letter ();
Scale2D (1.0, -1.0);
T_Letter ();
Translate2D (200., 100.0);
T_Letter ();
Rotate2D (-30);
T_Letter ();
}

Without using glPushMatrix () and glPopMatrix ()


//<<<<<<<<<<<<<<< myDisplay >>>>>>>>>>>>>>>>>>>>>
void myDisplay (void) {
double left, right, bottom, top;
left = -200.0, right = 200., bottom = -200.0, top = 200.;
setWindow (left, right, bottom, top); // entire world window
glPushMatrix ();
glViewport (0, 0, 400, 400);
T_Letter ();
Scale2D (0.5, 0.5);
T_Letter ();
Scale2D (1.0, -1.0);
T_Letter ();
Translate2D (200., 100.0);
T_Letter ();
glPopMatrix ();
Rotate2D (30);
T_Letter ();
}
Using glPushMatrix () and glPopMatrix ();
#include <GL/glut.h>
#include <stdlib.h>
static GLfloat spin = 0.0;
void init (void) {
glClearColor (1., 1., 1., 0.0);
glShadeModel (GL_FLAT);
}
void display (void) {
glClear (GL_COLOR_BUFFER_BIT);
glColor3f (1.0, 0.0, 0.0);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity();

// The center of the rectangle is not at the origin.


// The rotation around the origin as in Fig 1
glRotatef (-spin, 0.0, 0.0, 1.0);
glRectf (10.0, 10.0, 40.0, 40.0);

// Translate the rectangle center to the origin, rotated,


// and the translated again, as in Fig 2.
glTranslatef (25.0, 25.0, 0.0);
glRotatef (-spin, 0.0, 0.0, 1.0);
glTranslatef (-25.0, -25.0, 0.0);
glRectf (10.0, 10.0, 40.0, 40.0);
glutSwapBuffers();
}
void spinDisplay_CW (void) {
spin = spin + 1.0;
if (spin > 360.0)
spin = spin -360.0;
glutPostRedisplay ();
}
void spinDisplay_CCW (void) {
spin = spin - 1.0;
if (spin < 360.0)
spin = spin + 360.0;
glutPostRedisplay ();
}
void reshape (int w, int h) {
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (-100.0, 100.0, -100.0, 100.0, -1.0, 1.0);
glMatrixMode (GL_MODELVIEW);
}

void mouse (int button, int state, int x, int y) {


switch (button) {
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN)
glutIdleFunc (spinDisplay_CW);
break;
case GLUT_RIGHT_BUTTON:
if (state == GLUT_DOWN)
glutIdleFunc (spinDisplay_CCW);
else
glutIdleFunc (NULL);
break;
default:
break;
}
}
int main (int argc, char**argv) {
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize (600, 600);
glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);
init ();
glutDisplayFunc (display);
glutReshapeFunc (reshape);
glutMouseFunc (mouse);
glutMainLoop();

return 0;
}

Fig 1, The Rotation around the origin, the center of rectangle


Is not coincide on the origin

Fig 2, The Rotation around the center of the rectangle


​5.6 DRAWING 3D SCENES WITH OPENGL
The 2D transformations are special cases of 3D that ignore the third dimension. We have using
the camera as in Fig 5.50, the eye looks along the z-axis at the “window,” a rectangle lying in the
xy-plane. The view volume of the camera is a rectangular parallelepiped, whose four sidewalls
are determined by the border of the window and whose other two walls are determined by a near
plane and a far plane.
Fig
5.50
Simple viewing used in OpenGL for 2D drawing

Points lying inside the view volume are projected onto the window along lines parallel to the z-
axis, i.e. ignoring the z-components of those points, so 3D point (x1, y1, z1) projects to (x1, y1, 0).
Points lying outside the view volume are clipped off.

Fig 5.51 shows such a camera immersed in a scene. The scene consists of a block, part of which
lies outside the view volume.

Fig
5.51
A

camera to produce parallel views of a scene

Each vertex encounters three matrices:


• The modelview matrix
• The projection matrix
• The viewport matrix
Fig 5.52 The OpenGL Pipline

The modelview matrix provides what we have calling the CT. It combines two effects: the
sequence of modeling transformation applied to objects and the transformation that orients and
positions the camera.

Fig 5.53 effect of the modelview matrix in the graphics pipeline.

(a) before the transformations. (b) After the modeling transformation.


(c) After the modelview transformation.
Fig 5.53 suggests what the M and V matrices do.
Part (a) shows a unit cube centered at the origin.
Part (b) shows a modeling transformation based on M (scales, rotates,..) the cube into the block,
and shows the relative position of the camera’s view volume.
The V matrix used to rotate and translate the block into a new position. The specific
transformation would carry the camera from its position in the scene to its “generic” position,
with the eye at the origin and view volume aligned with z-axis, as in Part (c).
In the camera’s (eye) coordinate, the edges of the view volume are parallel to the x-,y-, and z-
axes. The volume extends from left to right in x, from bottom to top in y, and from –near to -
far in z.

The projection matrix scales and shifts each vertex in a particular way, so that all those vertices
that lie inside the view volume will lie inside a standard cube that extends from –1 to 1 in each
dimension.
Fig 5.54 Effect of the projection matrix (for parallel projections).

The viewport matrix maps the surviving portion of the block into a “3D viewport.” The matrix
maps the standard cube into a block shape whose x and y values extend across the viewport
(screen coordinate) and whose z-component extend from 0 to 1 and retains a measure of the
depth of point.

Figure 5.55 Effect of the viewport transformation

Some OpenGL Tools for Modeling and Viewing 5.6.2


The following functions are normally used to modify the modelview matrix, which is first made
:("current" by executing: gIMatrixMode (GL_MODELVIEW

glScaled (sx, sy, sz);


Postmultiply the current matrix by a matrix that performs a scaling by sx in x, by sy in y, and by
.sz in z. Put the result back into the current matrix
glTranslated (dx, dy . dz);
Postmultiply the current matrix by a matrix that performs a translation by dx in x, by dy in y, and
.by dz in z. Put the result back into the current matrix

glRotated(angle, ux , uy , uz);
Postmultiply the current matrix by a matrix that performs a rotation through angle degrees about
the axis that passes through the origin and the point (ux, uy, uz). Put the result back in the
.current matrix

Setting the Camera in OpenGL


The function glOrtho (left, right, bott, top, near, far); establishes as a view volume a
parallelipiped that extends from left to right in x, from bott to top in y, and from –near to -far
in z. The minus signs before near and far, because the default camera is located at the origin
looking down the negative z-axis, using a value of 2 for near means to place the near plane at –2,
i.e., 2 units in front of eye, 20 for far means place the far plane 20 units in front of eye.

The following code sets the projection matrix:


glMatrixMode (GL_PROJECTION); // make the projection matrix current
glLoadIdentity (); // set it to the identity matrix
glOrtho (left, right, bottom, top, near, far); // multiply it by the new matrix

Positioning and Aiming the Camera


OpenGL offers a function that creates the view matrix and postmultiplies the current matrix by it.
gluLookAt (eye.x, eye.y, eye.z, look.x, look.y, look.z, up.x, up.y, up.z);

EXAMPLE 5.6.1 Set up a typical camera


Cameras are often set to "look down " on a scene from some nearby position. Fig 5.56 shows a
camera with its eye situated at eye = (4, 4, 4), looking at the origin with look = (0, 1, 0). The
upwards direction is set to up = (0, 1, 0). Suppose we also want the view volume to have
a width of 6.4 and a height of 4.8, and suppose we wish to set near to 1 and far to 50.
The camera could be established with the following code
glMatixModR(GL_PROJECTION); // set the view volume
;() glLoadIdentity
;(gl0rtho (-3.2, 3.2, -2.4, 2.4, 1, 50
glMatrixMode (GL_MODELVTEW) : // place and aim the camera
;() glLoadIdantity
gluLookAt (4, 4, 4, 0, 1, 0, 0, 1, 0);

() FIGURE 5.56 Setting a camera with gluLookAt

5.6.3 Drawing Elementary Shapes Provided by OpenGL


The GLUT provides several ready-made 3D objects, including a sphere, a cone, a torus, the five
Platonic solids, and the teapot. Each is available as a wire-frame model and as a solid model with
faces that can be shaded.

• cube: glutWireCube (GLdouble size) ; Each side is of length size .


• sphere: glutWireSphere(GLdouble radius, GLint nSlices, GLint nStacks);
• torus: glutWireTorus (GLdouble inRad, GLdouble outRad, Glint nSlices, GLint nStacks);
• teapot: glutWircTeapot (GLdouble size)
There are also a glutSolidCube (), glutSolidSphere (), etc.,

The torus is determined by the inner radius inRad and outer radius outRad.
The sphere and torus are approximated by polygonal faces, and you can adjust the parameters
nSlices and nStacks to specify how many faces to use in the approximation. nSlices is the
number of subdivisions around the z-axis, and nStacks is the number of "bands" along the z-
axis, as if the shape were a stack of nStacks disks.

The functions used to render four of the Platonic solids are as follows:
• tetrahedron: glutWireTetrahedron();
• octahedron: glutWireOctahedron ();
• dodecahedron: glutWireDodecahedron ();
• icosahedron: glutWireIcosahedron ();

All of the preceding shapes are centered at the origin. We also have the following solids:
• cone: glutWireCone (GLdouble baseRad, GLdouble height, GLint nSlices, GLint nStacks)

glu Quadrics
• tapered cylinder: gluCylinder (GLUquadricObj * qobj, GLdouble baseRad, GLdouble topRad,
GLdouble
height, GLint nSlices, GLint nStacks)

The axes of the cone and tapered cylinder coincide with the z-axis. Their bases rest on the z = 0
plane and extend to z = height along the z-axis. The radius of the
cone and tapered cylinder at z = 0 is given by baseRad. The radius of the tapered cylinder at z =
height is topRad.

When topRad is 1, there is no taper, and we have the classic right circular cylinder. When
topRad is 0,the tapered cylinder is identical to the cone.

Note that drawing the tapered cylinder in OpenGL requires some extra work. To draw it, you
must;

1. define a new quadric object,


2. set the drawing style ( GLU_LINE for a wire frame, GL_FILL for a solid rendering), and
3. draw the object.

The following code do all of this.

GLUquadricObj * qobj = gluNewQuadric(): // make a quadric object


gluQuadricDrawStyle (qobj, GLU_LlNE); // set style to wireframe
gluCylinder (qobj , baseRad, topRad, height. nSlices. nStacks);
// draw the cylinder

Fig 5.58 Shapes available in the GLU.

EXAMPLE 5.6.2
A scene composed of wire-frame objects Figure 5.59 shows a scene with several objects
disposed at the corners of a unit cube, which itself has one corner at the origin.
The camera is given a view volume that extends from -2 to 2 in y. with an aspect ratio of
640/480. The near plane is at N = 0.1, the far plane at F = l00. This is accomplished using

g]Ortho (-2.0* aspect, 2.0* aspect, -2.0, 2.0, 0.1, 100);

The camera is positioned with eye = (2, 2, 2), lookAt = (0, 0, 0), and up = (0, 1, 0) (parallel lo the
y-axis), using
gluLookAt (2.0, 2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

glutWirecube (2.)
glutWireSphere (1.0, 8, 5);
glutWireTorus (0.5, 1., 8, 10);
glutWireCone (1.0, 2., 8, 10);
glutWireTetrahedron ();
glutWireOctahedron ();

glutWireDodecahedron (); glRotated (ang + 15, 0.5, 0.5,


0.5); glutWireTeapot (1.);
Fig
5.59 Wire-frame
drawing of
various primitive
shapes

#include
<windows.h>
//suitable when
using Windows
95/98/NT
#include
<gl/Gl.h>
#include
<gl/Glu.h>
#include
<gl/glut.h>
//<<<<<<<<<<<<<<<<<<< axis >>>>>>>>>>>>>>
void axis (double length) {
// draw a z-axis, with cone at end
glPushMatrix();
glBegin (GL_LINES);
glVertex3d (0, 0, 0);
glVertex3d (0,0,length); // along the z-axis
glEnd ();
glTranslated (0, 0,length -0.2);
glutWireCone (0.04, 0.2, 12, 9);
glPopMatrix ();
}

//<<<<<<<<<<<<<<<<<< displayWire >>>>>>>>>>>>>>>
void displayWire(void) {
glMatrixMode (GL_PROJECTION); // set the view volume shape
glLoadIdentity();
glOrtho (-2.0*64/48.0, 2.0*64/48.0, -2.0, 2.0, 0.1, 100);
glMatrixMode (GL_MODELVIEW); // position and aim the camera
glLoadIdentity();
gluLookAt (2.0, 2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

glClear (GL_COLOR_BUFFER_BIT); // clear the screen
glColor3d (0,0,0); // draw black lines
axis (0.5); // z-axis
glPushMatrix ();
glRotated (90, 0,1.0, 0);
axis (0.5); // y-axis
glRotated (-90.0, 1, 0, 0);
axis (0.5); // z-axis
glPopMatrix (); ​

glPushMatrix ();
glTranslated (0.5, 0.5, 0.5); // big cube at (0.5, 0.5, 0.5)
glutWireCube (1.0);
glPopMatrix ();

glPushMatrix (); ​

glTranslated (1.0,1.0,0); ​ // sphere at (1,1,0)


glutWireSphere (0.25, 10, 8);
glPopMatrix (); ​

glPushMatrix (); ​
glTranslated (1.0,0,1.0); ​// cone at (1,0,1)
glutWireCone (0.2, 0.5, 10, 8);
glPopMatrix ();

glPushMatrix ();
glTranslated (1,1,1);
glutWireTeapot (0.2); // teapot at (1,1,1)
glPopMatrix ();

glPushMatrix ();
glTranslated (0, 1.0 ,0); // torus at (0,1,0)
glRotated (90.0, 1,0,0);
glutWireTorus (0.1, 0.3, 10,10);
glPopMatrix ();

glPushMatrix ();
glTranslated (1.0, 0 ,0); // dodecahedron at (1,0,0)
glScaled (0.15, 0.15, 0.15);
glutWireDodecahedron ();
glPopMatrix ();

glPushMatrix ();
glTranslated (0, 1.0 ,1.0); // small cube at (0,1,1)
glutWireCube (0.25);
glPopMatrix ();

glPushMatrix ();
glTranslated (0, 0 ,1.0); // cylinder at (0,0,1)
GLUquadricObj * qobj;
qobj = gluNewQuadric ();
gluQuadricDrawStyle (qobj,GLU_LINE);
gluCylinder (qobj, 0.2, 0.2, 0.4, 8, 8);
glPopMatrix ();
glFlush ();
}

​//<<<<<<<<<<<<<<<<<< main >>>>>>>>>>>>>>>>>>>>


void main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB );
glutInitWindowSize(640,480);
glutInitWindowPosition(100, 100);
glutCreateWindow("Transformation tested - wireframes");
glutDisplayFunc(displayWire);
glClearColor(1.0f, 1.0f, 1.0f,0.0f); // background is white
glViewport(0, 0, 640, 480);
glutMainLoop();
}

The main () routine initializes a 640-by-480 pixel screen window, sets the viewport and
background color, and specifies displayWire ().
In displayWire (), the shape and position of the camera are established first. Then each object is
drawn in turn.

Before each modeling transformation is established, a glPushMatrix() is used to remember the


current transformation, and after the object has been drawn, the current transformation is restored
with a glPopMatrix().

Also shown in the figure are the x-, y-, and z-axes, drawn with conical arrow-heads. Displaying
the underlying coordinate system can help to orient the viewer. To draw the x-axis, the z-axis is
the underlying coordinate system can help to orient the viewer. To draw the x-axis, the z-axis is
o
rotated 90 about the y-axis to form a rotated system, and the x-axis is redrawn in its new
orientation. Note that this axis is drawn without immersing it in a glPushMaLrix (), glPopMatrix
() pair, so the next rotation to produce the y-axis takes place in the already rotated coordinate
system.

EXAMPLE 5.6.3 A 3D Scene Rendered with Shading


In this example, we develop a somewhat more complex scene. We also show how easy OpenGL
makes it to draw much more realistic drawings of solid objects by incorporating shading.

Fig 5.61 A simple 3D scene a) using a large view volume, b) using a small view volume

Two views of a scene are shown in Figure 5.61. Both views use a camera set by

gluLookAt (2.3, 1.3. 2. 0, 0.25, 0, 0.0,1 . 0 , 0 . 0).

Part (a) uses a large view volume that encompasses the whole scene;
Part (b) uses a small view volume that encompasses only a small portion of the scene, thereby
providing a close-up view.

The scene contains three objects resting on a table in the corner of a "room." Each of the three
walls is made by flattening a cube into a thin sheet.

The jack is composed of three stretched spheres oriented at right angles to each other, plus six
small spheres at their ends.
The table consists of a tabletop and four legs. Each of the table's five pieces is a cube that has
been scaled to the desired size and shape. The layout for the table is shown in Figure 5.62 and is
based on Four parameters that characterize the size of its parts: topWidth, topThick, 1egLen, and
legThick. A routine tableLeg () draws each leg and is called four times within the routine table ().
Always, a glPushMatrix (), glPopMatrix () pair surrounds the modeling functions to isolate their
effect.
.Fig 5.62 Designing the table
The complete code for this program is shown in Fig 5.63. The code shows the various things that
must be done to create shaded images. The position and properties of a light source must be
specified, along with certain properties of the objects' surfaces, in order to describe how they
reflect light.

<include <windows.h#
#include <gl/Gl.h>
#include <gl/Glu.h>
#include <gl/glut.h>
// <<<<<<<<<< wall >>>>>>>>>>>
void wall (double thickness ) {
// draw thin wall with top = xz-plane, corner at origin
glPushMatrix () ;
glTranslated (0.5, 0.5 * thickness, 0.5);
glScaled (1.0, thickness, 1.0);
glutSolidCube (1.0);
glPopMatrix ();
}
// <<<<<<<<<< tablfeLeg >>>>>>>>>>
void tableLeg (double thick, double len) {
glPushMatrix () ;
glTranslated (0, len/2, 0);
glScaled (thick, len, thick);
glutSolidCube (1.0) ;
glPopMatrix ();
}
//<<<<<<<<<< jack part >>>>>>>>>>>>
void jackPart () {
// draw one axis of the unit jack - a stretched sphere
glPushMatrix ();
glScaled (0.2,0.2, 1.0);
glutSolidSphere (1, 15, 15);
glPopMatrix () ;
glPushMatrix () ;
glTranslated (0, 0.1, 2) ; // ball on one end
glutSolidSphere (0.2, 15, 15) ;
glTranslated (0, 0, -2.4);
glutSolidSphere (0.2, 15, 15); // ball on the other end
glPopMatrix ();
}
//<<<<<<<<<<<<< jack >>>>>>>>>>>
void jack() {
// draw a unit jack out of spheroids
glPushMatrix () ;
jackPart ();
glRotated (90.0, 0, 1, 0);
jackPart ();
glRotated (90.0, 1, 0, 0);
jackPart () ;
glPopMatrix () ;
}

//<<<<<<<<<<<< table >>>>>>>>>>>


void table (double topWid, double topThick, double legThick,
double legLen) {
// draw tha tabi e - a top and four lags
glPushMatrix (); // draw the table top
glTranslated (0, legLen, 0);
glScaled (topWid , topThick, topWid) ;
glutSolidCube (1.0);
glPopMatrix ();
double dist =0.95 * topWid/2.0 - legThick / 2.0;
glPushMatrix ();
glTranslated (dist, 0, dist);
tableLeg (legThick, legLen);
glTranslated (0, 0, -2*dist);
tableLeg (legThick, legLen);
glTranslated(-2*dist, 0, 2*dist);
tableLeg (legThick, legLen);
glTranslated (0, 0, -2*dist);
tableLeg (legThick, legLen);
glPopMatrix();
}
//<<<<<<<<<<<, displaySolid >>>>>>>>>
void displaySolid (void) {
//set properties of the surface material
GLfloat mat_ambient () = { 0.7f, 0.7f, 0.7f, 1.0f}; // gray
GLfloat mat_diffuse () = { 0.6f, 0.6f, 0.6f, 1.0f};
GLfloat mat_specular () = {1.0f, 1.0f, 1.0f, 1.0f};
GLfloat mat_shininess [] = { 50.0f};
glMaterialfv (GL_FRONT, GL_AMBIENT, mat_ambient) ;
glMaterialfv (GL_FRONT, GL_DIFFUSE, mat_diffuse) ;
glMaterialfv (GL_FRONT, GL_SPECULAR, mat_specular) ;
glMaterialfv (GL_FRONT, GL_SHININESS, mat_shininess);
// set the light source properties
GLfloat lightIntensity () = {0.7f, 0.7f, 0.7f, 1.0f} ;
GLfloat light_position () = {2.0f, 6.0f, 3.0f, 0.0f} ;
glLightfv (GL_LIGHT0, GL_POSITION, light_position);
glLightfv( GL_LIGHT0, GL_DIFFUSE, lightIntensity) ;
// set the camera
glMatrixMode (GL_PROJECTION);
glLoadIdentity () ;
double winHt = 1.0; // half-height of the window
glOrtho (-winHt* 64/48.0, winHt *64/48.0, -winHt, winHt, 0.1, 100.0) ;
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
gluLookAt(2.3, 1.3, 2, 0, 0.25, 0, 0.0, 1.0, 0.0);
// start drawing
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ; // clear
glPushMatrix ();
glTranslated (0.4, 0.4, 0.6);
glRotated (45, 0, 0, 1);
glScaled (0.08, 0.08, 0.08);
jack() ; // draw the jack
glPopMatrix ();
glPushMatrix ();
glTranslated (0.6, 0.38, 0.5);
glRotated (30,0, 1,0) ;
glutSolidTeapot (0.08) ; // draw the teapot
glPopMatrix () ;
glPushMatrix ();
glTranslated (0.25 ,0.42, 0.35);// draw the. sphere
glutSolidSphere (0.1, 15, 15) ;
glPopMatrix () ;
glPushMatrix ();
glTranslated (0.4, 0, 0.4) ;
table (0.6, 0.02, 0.02, 0.3); // draw the table
glPopMatrix () ;
wall (0.02); // wall #1 in xz-plane
glPushMatrix () ;
glRotated (90.0, 0.0, 0.0, 1.0);
wall (0.02); // wall #2 in yz-plane
glPopMatrix () ;
glPushMatrix () ;
glRotated (-90.0, 1.0, 0.0, 0.0) ;
wall ( 0.02) ; // wall #3: in xy-plane
glPopMatrix ();
glFlush () ;
}
//<<<<<<<<<<<< main >>>>>>>>>>
void main (int argc, char **argv) {
glutInit (&argc , argv) ;
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize (640, 480) ;
glutInitWindowPosition (100, 100) ;
glutCreateWindow ("shaded example - 3D scene") ;
glutDisplayFunc (displaySolid) ;
glEnable (GL_LIGHTING) ; // enable the light source
glEnable (GL_LIGHT0) ;
glShadeModel (GL_SMOOTH) ;
glEnable (GL_DEPTH_TEST) ; // for removal of hidden surfaces
glEnable (GL_NORMALIZE); // normalize vecLors for proper shading
glClearColor (0.1f, 0.1f, 0.1f, 0.0f); // background is light gray
glViewport (0, 0, 640, 480);
glutMainLoop () ;
}

light_position () = {2.0f, 6.0f, 3.0f, 0.0f} ; light_position() = {5.0f, 0.0f,


; {0.0f, 0.0f
light_position () = {0.0f, 5.0f, 0.0f, 0.0f} ; light_position () = {0.0f, 0.0f,
-5.0f, 0.0f} ;

gluLookAt(2.3, 1.3, 2, 0, 0.25, 0, 1.0, 0.0, 0.0);


gluLookAt(2.3, 1.3, 2, 0, 0.25, 0, 0.0, 0.0,1.0);

5.6.3 Adjusting the Scene

What changes should be made in Figure 5.63 to place the jack on the floor and the sphere
perched on top of the teapot?

​Menus
The windowing systems support a set of widgets, which are special types of windows with which
the user can interact. Widgets sets include menus, buttons, slides bars, and dialog boxes. GLUT
provides limited capabilities, such as menu.

Defining a menu requires:


• We must decide what entries are in the menu, i.e., what string will be displayed in each
row of a menu.
• We must tie specific actions to the rows.
• We must tie each menu to a mouse button.
Menus are usually created either in main() or in an initialization function called from main().

int glutCreateMenu (void (*f)(int value))


Create a top-level menu that uses the callback f(), which is pressed an integer value for the menu
entry. A unique identifier is returned for the menu created.
The menu created becomes the current menu. The current menu can be changed by
glutSetMenu().

void glutSetMenu (int id)


Set the current menu to the menu with identifier id. Entries are added into the current menu by
glutAddMenuEntry(). Each entry consists of two parts:
1. A string displayed for the entry.
2. A value returned when that entry is selected.
void glutAddMenuEntry (char *name, int value)
Adds an entry with name displayed to the current menu; value is returned to the menu callback.

Attached the menu to a mouse button by


void glutAttachMenu (int button)
Attaches the current menu to the specified mouse button (GLUT_RIGHT_BUTTON,
GLUT_MIDDLE_BUTTON, or GLUT_LEFT_BUTTON).

Suppose that we want to use the right mouse button to pop up a menu that will have two entries:
• Clear the screen.
• End the program.
glutCreateMenu (mymenu);
glutAddMenuEntry (“Clear Screen”, 1);
glutAddMenuEntry (“Exit”, 2);
glutAttachMenuEntry (GLUT_RIGHT_BUTTON);

void myMenu (int value) {


if (value == 1) glClear();
if (value == 2) exit(0);
}

We can add submenus to a menu.

void glutAddSubMenu (char *name, int menu)


Add a submenu entry name as the next entry in the current menu. The value of menu is the ID of
the submenu returned when the submenu was created.

The NULL Callback


Callback functions can be redefined during execution by simply naming a new callback function
in the appropriate function. At times, we want to simply eliminate a callback.
glutIdelFunc (NULL);

Subwindows and Multiple Windows


Some times we want to use multiple windows.

int glutCreateWindow (char *name)


Creates a top-level window name

void glutdestroyWindow (int id)


Destroy the top-level window id.

When a window is created, it becomes the current window, the primitive are rendered to the
current window. We can change this window by:

int glutSetWindow (int id)


Sets the current window to the window with identifier id

We can also create sub-windows of any window. Each sub-window is defined to be a sub-
rectangle of its parent using:

int glutCreateSubWindow (int parant, int x, int y, int width, int height ) ;
Creates a sub-window of parent and returns its ID. The sub-window has its origin at (x, y) and
has size width by height in pixels. The sub-window becomes the current window.

​Some Functions:
void glutIdleFunc (void (*f) (void)) ;
The function f() is executed whenever no other events are to be handled. When we want to
eliminate a callback, we call glutIdelFunction ().

void glutPostRedisplay ();


Requests that display callback be executed.
void glutSwapBuffers ();
Swaps the front and back buffers.

// Menu Program
#include <GL/glut.h>
#include <stdlib.h>
GLsizei ww = 500, wh = 500;
int fill, r=1.0, g=1.0, b=1.0;
void fill_menu (int );
void color_menu (int );
void right_menu (int );
void display (void) {
glClearColor (0.0, 0.0, 0.0, 0.0);
glClear (GL_COLOR_BUFFER_BIT);
glColor3f(r, g, b);
if (fill == 1)
glBegin (GL_POLYGON);
else
glBegin (GL_LINE_LOOP);
glVertex3f (100.0, 200.0, 0.0);
glVertex3f (200.0, 200.0, 0.0);
glVertex3f (200.0, 300.0, 0.0);
glVertex3f (100.0, 300.0, 0.0);
glEnd();
glFlush ();
}
void init (void) {
glClearColor (0.3, 0.5, 0.3, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
}
void fill_menu (int id) {
if (id == 1)
fill = 1;
else
fill = 0;
glutPostRedisplay();
}

void color_menu (int id) {


if (id == 1) { r=1.0; g=0.0; b=0.0;}
if (id == 2) { r=0.0; g=1.0; b=0.0;}
if (id == 3) { r=0.0; g=0.0, b=1.0;}
glutPostRedisplay();
}

void right_menu (int id) {

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


int c_menu, f_menu;
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize (300, 300);
glutInitWindowPosition (50, 100);
glutCreateWindow ("hello");
glutDisplayFunc (display);

c_menu = glutCreateMenu(color_menu);
glutAddMenuEntry ("Red", 1);
glutAddMenuEntry ("Green", 2);
glutAddMenuEntry ("Blue", 3);

f_menu = glutCreateMenu (fill_menu);


glutAddMenuEntry ("fill on", 1);
glutAddMenuEntry ("fill off", 2);

glutCreateMenu (right_menu);
glutAddSubMenu("Colors", c_menu);
glutAddSubMenu("Fill", f_menu);
glutAttachMenu (GLUT_RIGHT_BUTTON);
init ();
glutMainLoop();
return 0;
}
Dr
Taleb
Obaid

5 / 42

You might also like