Acknowledgements To: RD TH
Acknowledgements To: RD TH
5.1.1 INTERACTION
In the field of computer graphics, interaction refers to the manner in
which the application program communicates with input and output
devices of the system.
For e.g. Image varying in response to the input from the user.
OpenGL doesn’t directly support interaction in order to maintain
portability. However, OpenGL provides the GLUT library. This library
supports interaction with the keyboard, mouse etc and hence enables
interaction. The GLUT library is compatible with many operating systems
such as X windows, Current Windows, Mac OS etc and hence indirectly
ensures the portability of OpenGL.
Input devices are the devices which provide input to the computer
graphics application program. Input devices can be categorized in two
ways:
The major disadvantage is that it has the difficulty in obtaining a position that
corresponds to a dark area of the screen
Stick doesn’t move rather pressure sensors in the ball measure the
forces applied by the user. The space ball can measure not only three direct
forces (up-down, front-back, left-right) but also three independent twists. So
totally device measures six independent values and thus has six degree of
freedom.
API defines six classes of logical input devices which are given below:
The application program can obtain the measure and trigger in three distinct
modes:
1. REQUEST MODE: In this mode, measure of the device is not returned
to the program until the device is triggered.
For example, consider a typical C program which reads a character input
using scanf(). When the program needs the input, it halts when it
encounters the scanf() statement and waits while user type characters at
the terminal. The data is placed in a keyboard buffer (measure) whose
contents are returned to the program only after enter key (trigger) is
pressed.
Another example, consider a logical device such as locator, we can move
out pointing device to the desired location and then trigger the device
with its button, the trigger will cause the location to be returned to the
application program.
2. SAMPLE MODE: In this mode, input is immediate. As soon as the
function call in the user program is executed, the measure is returned. Hence
no trigger is needed.
Both request and sample modes are useful for the situation if and only if there
is a single input device from which the input is to be taken. However, in case of
flight simulators or computer games variety of input devices are used and these
mode cannot be used. Thus, event mode is used.
Most popular examples of servers are print servers – which allow using
high speed printer devices among multiple users. File servers – allow
users to share files and programs.
Users or clients will make use of these services with the help of user
programs or client programs. The OpenGL application programs are the client
programs that use the services provided by the graphics server.
Even if we have single user isolated system, the interaction would be
configured as client-server model.
5.1.4 DISPLAY LISTS
The original architecture of a graphical system was based on a general-purpose
computer connected to a display. The architecture is shown in the next page.
At that time, the disadvantage is that system was slow and expensive.
Therefore, a special purpose computer is build which is known as “display
processor”.
The user program is processed by the host computer which results a compiled
list of instruction that was then sent to the display processor, where the
instruction are stored in a display memory called as “display file” or
“display list”. Display processor executes its display list contents repeatedly
at a sufficient high rate to produce flicker-free image.
There are two modes in which objects can be drawn on the screen:
1. IMMEDIATE MODE: This mode sends the complete description of the
object which needs to be drawn to the graphics server and no data can be
retained. i.e., to redisplay the same object, the program must re-send the
information. The information includes vertices, attributes, primitive types,
viewing details.
2. RETAINED MODE: This mode is offered by the display lists. The object
is defined once and its description is stored in a display list which is at the server
side and redisplay of the object can be done by a simple function call issued by
the client to the server.
NOTE: The main disadvantage of using display list is it requires memory at the
server architecture and server efficiency decreases if the data is changing
regularly.
The flag GL_COMPILE indicates the system to send the list to the server
but not to display its contents. If we want an immediate display of the
contents while the list is being constructed then
GL_COMPILE_AND_EXECUTE flag is set.
Each time if the client wishes to redraw the box on the display, it need
not resend the entire description. Rather, it can call the following
function:
glCallList(Box)
We can retrieve these values by popping them from the stack, usually the
below function calls are placed at the end of the display list,
glPopAttrib();
glPopMatrix();
We can create multiple lists with consecutive identifiers more easily
using:
glGenLists (number)
We can display multiple display lists by using single funciton call:
glCallLists()
TEXT AND DISPLAY LISTS
There are two types of text i.e., raster text and stroke text which can be
generated.
For example, let us consider a raster text character is to be drawn of size
8x13 pattern of bits. It takes 13 bytes to store each character.
If we define a stroke font using only line segments, each character
requires a different number of lines.
From the above figure we can observe to draw letter ‘I’ is fairly simple,
whereas drawing ‘O’ requires many line segments to get sufficiently
smooth.
So, on the average we need more than 13 bytes per character to
represent stroke font. The performance of the graphics system will be
degraded for the applications that require large quantity of text.
A more efficient strategy is to define the font once, using a display list for
each char and then store in the server. We define a function OurFont()
which will draw any ASCII character stored in variable ‘c’.
The function may have the form
For the character ‘O’ the code sequence is of the form as shown below:
The above code approximates the circle with 12 quadrilaterals.
When we want to generate a 256-character set, the required code using
OurFont() is as follows
base = glGenLists(256);
for(i=0;i<256;i++) {
glNewList(base+i, GL_COMPILE);
OurFont(i);
glEndList();
}
To display char from the list, offset is set by using glListBase(base)
function. The drawing of a string is accomplished in the server by the
following function, char *text_string;
glCallLists((GLint) strlen (text_string), GL_BYTE, text_string);
FONTS IN GLUT
GLUT provides raster and stroke fonts; they do not make use of display
lists.
glutStrokeCharacter(GLUT_STROKE_MONO_ROMAN, int character);
provides proportionally space characters. Position of a character is done
by using a translation before the character function is called.
glutBitmapCharacter(GLUT_BITMAP_8_BY_13, int character);
produces the bitmap characters of size 8x13.
Each face has two identical eyes, two identical ears, one nose, one mouth
& an outline. We can specify these parts through display lists which is
given below:
5.1.6 PROGRAMMING EVENT DRIVEN INPUT
The various events can be recognized by the window system and call
back function can be called for each of these events.
#include<stdio.h>
#include<stdlib.h>
#include<GL/glut.h>
int wh=500, ww=500;
float siz=3;
void myinit()
{
glClearColor(1.0,1.0,1.0,1.0);
glViewPort(0,0,w,h)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,(GLdouble) ww, 0, (GLdouble) wh);
glMatrixMode(GL_MODELVIEW);
glColor3f(1,0,0);
}
The above code ensures when ‘Q’ or ‘q’ key is pressed, the execution of the
program gets terminated.
WINDOW MANAGEMENT
GLUT also supports multiple windows of a given window. We can create a
second top-level window as follows:
id = glutCreateWindow(“second window”);
The returned integer value allows us to select this window as the current
window.
i.e., glutSetWindow(id);
NOTE: The second window can have different properties from other window by
invoking the glutInitDisplayMode before glutCreateWindow.
5.1.7 MENUS
Menus are an important feature of any application program. OpenGL
provides a feature called “Pop-up-menus” using which sophisticated
interactive applications can be created.
Menu creation involves the following steps:
1. Define the actions corresponding to each entry in the menu.
2. Link the menu to a corresponding mouse button.
3. Register a callback function for each entry in the menu.
The glutCreateMenu() registers the callback function demo_menu. The
function glutAddMenuEntry() adds the entry in the menu whose name is
pased in first argument and the second argument is the identifier passed
to the callback when the entry is selected.
5.1.8 PICKING
Picking is the logical input operation that allows the user to identify an
object on the display.
The action of picking uses pointing device but the information returned
to the application program is the identifier of an object not a position.
It is difficult to implement picking in modern system because of graphics
pipeline architecture. Therefore, converting from location on the display
to the corresponding primitive is not direct calculation.
There are at least three ways to deal with this difficulty:
O Selection:
It involves adjusting the clipping region and viewport such
that we can keep track of which primitives lies in a small
clipping region and are rendered into region near the cursor.
These primitives are sent into a hit list that can be
examined later by the user program.
O Bounding boxes or extents:
Picking can be performed in four steps that are initiated by user defined
pick function in the application:
O We draw the objects into back buffer with the pick colors.
O We get the position of the mouse using the mouse callback.
O Use glReadPixels() to find the color at the position in the frame
buffer corresponding to the mouse position.
O We search table of colors to find the object corresponds to the color
read.
#include<glut.h>
void myReshape()
{
glViewPort(0,0,w,h)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,(GLdouble) w, 0, (GLdouble) h);
glMatrixMode(GL_MODELVIEW);
}
The above idle callback function must be registered in the main function:
glutIdleFunc(idle);
Suppose that we want to turn off and turn on the rotation feature then
we can write a mouse callback function as shown below:
The above mouse callback function starts the rotation of the cube when
the left mouse button and when the middle button is pressed it will halt
the rotation.
The above mouse callback function must be registered in the main
function as follow:
glutMouseFunc(mouse);
DOUBLE BUFFERING:
Double buffering is a must in such animations where the primitives,
attributes and viewing conditions are changing continuously.
Double buffer consists of two buffers: front buffers and back buffers.
Double buffering mode can be initialized:
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
Execution of this function starts timer in the event loop that delays for
delay milliseconds. When timer has counted down, timer_func is
executed the value parameter allow user to pass variable into the timer
call back.
Again mouse is used to get second point and draw a line segment in XOR
mode.
Here in the above code, copy mode is used to switch back in order to
draw other objects in normal mode.
If we enter another point with mouse, we first draw line in XOR mode
from 1st point to 2nd point and draw second line using 1st point to
current point is as follows:
In this example, we draw rectangle using same concept and the code for
callback function are given below:
For the first time, we draw a single rectangle in XOR mode.
After that each time that we get vertex, we first erase the existing
rectangle by redrawing new rectangle using new vertex.
Finally, when mouse button is released the mouse callback is executed
again which performs final erase and draw and go to replacement mode.
Therefore, typical color buffer may have 8 bits for each Red, green and blue and
one red, one green and one blue overlay plane. i.e., each color will be having its
own overlay plane then those values will be updated to color buffer.
Module 5 ***SAI Curve
RAM*** s
5.2 Curves:
Curved surfaces
Quadric surfaces
OpenGL quadric surfaces and cubic surface functions
Bezier spline curves
Bezier surfaces
Opengl curve functions
Corresponding opengl functions
1. Sphere
A spherical surface with radius r centered on the coordinate origin is defined as the set of
points (x, y, z) that satisfy the equation
x2 + y2 + z2 = r 2
We can also describe the spherical surface in parametric form, using latitude and
longitude angles as shown in figure
x = r cos φ cos θ, − π/2 ≤ φ ≤ π/2
y = r cos φ sin θ, − π ≤ θ ≤ π
z = r sin φ
2. Ellipsoid
An ellipsoidal surface can be described as an extension of a spherical surface where the
radii in three mutually perpendicular directions can have different values
The Cartesian representation for points over the surface of an ellipsoid centered on the
origin is
And a parametric representation for the ellipsoid in terms of the latitude angle φ and the
longitude angle θ
x = rx cos φ cos θ, − π/2 ≤ φ ≤ π/2
y = ry cos φ sin θ, − π ≤ θ ≤ π
z = rz sin φ
3. Torus
A torus is a doughnut-shaped object, as shown in fig. below.
The corresponding parametric equations for the torus with a circular cross-section are
x = (raxial + r cos φ) cos θ, − π ≤ φ ≤
π y = (raxial + r cos φ) sin θ, − π ≤ θ ≤
π z = r sin φ
We could also generate a torus by rotating an ellipse, instead of a circle, about the z axis.
we can write the ellipse equation as
where raxial is the distance along the y axis from the rotation z axis to the ellipse
center. This generates a torus that can be described with the Cartesian equation
The corresponding parametric representation for the torus with an elliptical crosssection
is
x = (raxial + ry cos φ) cos θ, − π ≤ φ ≤
π y = (raxial + ry cos φ) sin θ, − π ≤ θ ≤
π z = rz sin φ
Sphere
Function:
glutWireSphere (r, nLongitudes, nLatitudes);
or
glutSolidSphere (r, nLongitudes, nLatitudes);
where,
r is sphere radius which is double precision point.
nLongitudes and nLatitudes is number of longitude and latitude lines used to
approximate the sphere.
Cone
Function:
glutWireCone (rBase, height, nLongitudes, nLatitudes);
or
glutSolidCone (rBase, height, nLongitudes, nLatitudes);
where,
rBase is the radius of cone base which is double precision point.
height is the height of cone which is double precision point.
nLongitudes and nLatitudes are assigned integer values that specify the number of
orthogonal surface lines for the quadrilateral mesh approximation.
Torus
Function:
glutWireTorus (rCrossSection, rAxial, nConcentrics, nRadialSlices);
or
glutSolidTorus (rCrossSection, rAxial, nConcentrics, nRadialSlices);
where,
rCrossSection radius about the coplanar z axis
rAxial is the distance of the circle center from the z axis
nConcentrics specifies the number of concentric circles (with center on the z axis) to be
used on the torus surface,
nRadialSlices specifies the number of radial slices through the torus surface
where,
sphere1 is the name of the object
the quadric renderer is activated with the gluNewQuadric function, and then the display
mode GLU_LINE is selected for sphere1 with the gluQuadricDrawStyle command
Parameter r is assigned a double-precision value for the sphere radius
nLongitudes and nLatitudes. number of longitude lines and latitude lines
Three other display modes are available for GLU quadric surfaces
GLU_POINT: quadric surface is displayed as point plot
GLU_SILHOUETTE: quadric surface displayed will not contain shared edges between two
coplanar polygon facets
GLU_FILL: quadric surface is displayed as patches of filled area.
A flat, circular ring or solid disk is displayed in the xy plane (z=0) and centered on the
world-coordinate origin with
gluDisk (ringName, rInner, rOuter, nRadii, nRings);
We set double-precision values for an inner radius and an outer radius with
parameters rInner and rOuter. If rInner = 0, the disk is solid.
Otherwise, it is displayed with a concentric hole in the center of the disk.
The disk surface is divided into a set of facets with integer parameters nRadii and
nRings
We can specify a section of a circular ring with the following GLU function:
gluPartialDisk (ringName, rInner, rOuter, nRadii, nRings, startAngle,
sweepAngle);
startAngle designates an angular position in degrees in the xy plane measured
clockwise from the positive y axis.
parameter sweepAngle denotes an angular distance in degrees from the
startAngle position.
A section of a flat, circular disk is displayed from angular position startAngle to
startAngle + sweepAngle
For example, if startAngle = 0.0 and sweepAngle = 90.0, then the section of the
disk lying in the first quadrant of the xy plane is displayed.
Allocated memory for any GLU quadric surface can be reclaimed and the surface
eliminated with
gluDeleteQuadric (quadricName);
Also, we can define the front and back directions for any quadric surface with the
following orientation function:
gluQuadricOrientation (quadricName, normalVectorDirection);
Where,
Parameter normalVectorDirection is assigned either GLU_OUTSIDE or
GLU_ INSIDE
A set of three parametric equations for the individual curve coordinates can be
represented as
Below Figure demonstrates the appearance of some Bézier curves for various selections
of control points in the xy plane (z = 0).
for n ≥ k. Also, the Bézier blending functions satisfy the recursive relationship
BEZk,n(u) = (1 − u)BEZk,n−1(u) + u BEZk−1,n−1(u), n > k ≥ 1 (27)
with BEZk,k = uk and BEZ0,k = (1 − u)k .
Program
#include <GL/glut.h>
#include <stdlib.h>
#include <math.h>
/* Set initial size of the display window. */
GLsizei winWidth = 600, winHeight = 600;
/* Set size of world-coordinate clipping window. */
GLfloat xwcMin = -50.0, xwcMax = 50.0;
GLfloat ywcMin = -50.0, ywcMax = 50.0;
class wcPt3D {
public:
GLfloat x, y, z;
};
void init (void)
{
/* Set color of display window to white. */
glClearColor (1.0, 1.0, 1.0, 0.0);
}
void plotPoint (wcPt3D bezCurvePt)
{
glBegin (GL_POINTS);
glVertex2f (bezCurvePt.x, bezCurvePt.y);
glEnd ( );
}
/* Compute binomial coefficients C for given value of n. */
void binomialCoeffs (GLint n, GLint * C)
{
GLint k, j;
for (k = 0; k <= n; k++) {
/* Compute n!/(k!(n - k)!). */
C [k] = 1;
for (j = n; j >= k + 1; j--)
C [k] *= j;
for (j = n - k; j >= 2; j--)
C [k] /= j;
}
}
void computeBezPt (GLfloat u, wcPt3D * bezPt, GLint nCtrlPts, wcPt3D * ctrlPts, GLint * C)
{
GLint k, n = nCtrlPts - 1;
GLfloat bezBlendFcn;
bezPt->x = bezPt->y = bezPt->z = 0.0;
/* Compute blending functions and blend control points. */
for (k = 0; k < nCtrlPts; k++) {
bezBlendFcn = C [k] * pow (u, k) * pow (1 - u, n - k);
bezPt->x += ctrlPts [k].x * bezBlendFcn;
bezPt->y += ctrlPts [k].y *
bezBlendFcn; bezPt->z += ctrlPts [k].z *
bezBlendFcn;
}
}
void bezier (wcPt3D * ctrlPts, GLint nCtrlPts, GLint nBezCurvePts)
{
wcPt3D bezCurvePt;
GLfloat u;
GLint *C, k;
/* Allocate space for binomial coefficients */
C = new GLint [nCtrlPts];
binomialCoeffs (nCtrlPts - 1, C);
for (k = 0; k <= nBezCurvePts; k++) {
u = GLfloat (k) / GLfloat (nBezCurvePts);
computeBezPt (u, &bezCurvePt, nCtrlPts, ctrlPts, C);
plotPoint (bezCurvePt);
}
delete [ ] C;
}
void displayFcn (void)
{
/* Set example number of control points and number of
* curve positions to be plotted along the Bezier curve. */
GLint nCtrlPts = 4, nBezCurvePts = 1000;
wcPt3D ctrlPts [4] = { {-40.0, -40.0, 0.0}, {-10.0, 200.0, 0.0},
{10.0, -200.0, 0.0}, {40.0, 40.0, 0.0} };
glClear (GL_COLOR_BUFFER_BIT); // Clear display window.
glPointSize (4);
glColor3f (1.0, 0.0, 0.0); // Set point color to red.
bezier (ctrlPts, nCtrlPts, nBezCurvePts);
glFlush ( );
}
void winReshapeFcn (GLint newWidth, GLint newHeight)
{
/* Maintain an aspect ratio of 1.0. */
glViewport (0, 0, newHeight, newHeight);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ( );
gluOrtho2D (xwcMin, xwcMax, ywcMin, ywcMax);
glClear (GL_COLOR_BUFFER_BIT);
}
void main (int argc, char** argv)
{
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition (50, 50);
glutInitWindowSize (winWidth, winHeight);
glutCreateWindow ("Bezier Curve");
init ( );
glutDisplayFunc (displayFcn);
glutReshapeFunc (winReshapeFcn);
glutMainLoop ( );
}
The parametric second derivatives of a Bézier curve at the endpoints are calculated as
Property 2:
Another important property of any Bézier curve is that it lies within the convex hull
(convex polygon boundary) of the control points.
This follows from the fact that the Bézier blending functions are all positive and their
sum is always 1:
Other Properties:
The basic functions are real.
The degree of the polynomial defining the curve segment is one less than the number of
defining points.
The curve generally follows the shape of the defining polygon,
The tangent vectors at the ends of the curve have the same direction as the first and last
polygon spans respectively.
Design Techniques Using Bézier Curves
A closed Bézier curve is generated when we set the last control-point position to the
coordinate position of the first control point.
Specifying multiple control points at a single coordinate position gives more weight to
that position a single coordinate position is input as two control points, and the resulting
curve is pulled nearer to this position.
When complicated curves are to be generated, they can be formed by piecing together
several Bézier sections of lower degree.
Generating smaller Bézier-curve sections also gives us better local control over the shape
of the curve.
Because Bézier curves connect the first and last control points, it is easy to match curve
sections.
Also,Bézier curves have the important property that the tangent to the curve at an
endpoint is along the line joining that endpoint to the adjacent control point to obtain
first-order continuity between curve sections, we can pick control points p0’ and p1’for
the next curve section to be along the same straight line as control points pn−1 and pn of
the preceding section
If the first curve section has n control points and the next curve section has n’ control
points, then we match curve tangents by placing control point p1’ at the position
Cubic Bézier Curves
Cubic Bézier curves are generated with four control points. The four blending functions
for cubic Bézier curves, obtained by substituting n = 3 in the equations below, they are
Plots of the four cubic Bézier blending functions are given in Figure
At the end positions of the cubic Bézier curve, the parametric first derivatives (slopes) are
A matrix formulation for the cubic-Bézier curve function is obtained by expanding the
polynomial expressions for the blending functions and restructuring the equations as
where the Bézier matrix is
Bézier surfaces have the same properties as Bézier curves, and they provide a convenient
method for interactive design applications.
To specify the threedimensional coordinate positions for the control points, we could first
construct a rectangular grid in the xy “ground” plane.
We then choose elevations above the ground plane at the grid intersections as the z-
coordinate values for the control points.
Figure above illustrates various polyline displays that could be used for a circle segment.
A third alternative is to write our own curve-generation functions based on the algorithms
with respect to line drawing and circle drawing.
5.2.7 OpenGL Approximation-Spline Functions
OpenGL Bézier-Spline Curve Functions
We specify parameters and activate the routines for Bézier-curve display with the
OpenGL functions
glMap1* (GL_MAP1_VERTEX_3, uMin, uMax, stride, nPts, *ctrlPts);
glEnable (GL_MAP1_VERTEX_3);
We deactivate the routines with
glDisable (GL_MAP1_VERTEX_3);
where,
A suffix code of f or d is used with glMap1 to indicate either floating-point or double
precision for the data values. M
inimum and maximum values for the curve parameter u are specified in uMin and uMax,
although these values for a Bézier curve are typically set to 0 and 1.0, respectively.
Bézier control points are listed in array ctrlPts number of elements in this array is given
as a positive integer using parameter nPts.
stride is assigned an integer offset that indicates the number of data values between the
beginning of one coordinate position in array ctrlPts and the beginning of the next
coordinate position
which maps each of uValue and vValue to the interval from 0 to 1.0
To determine the current value of a B-spline property, we use the following query
function:
gluGetNurbsProperty (splineName, property, value);
When the property GLU_AUTO_LOAD_MATRIX is set to the value GL_FALSE, we
invoke
gluLoadSamplingMatrices (splineName, modelviewMat, projMat, viewport);
Animation
Raster methods of computer animation
Design of animation sequences
Traditional animation techniques
General computer animation function
OpenGL animation procedures
Introduction:
To 'animate' is literally 'to give life to'.
'Animating' is moving something which can't move itself.
Animation adds to graphics the dimension of time which vastly increases the amount of
information which can be transmitted.
Computer animation generally refers to any time sequence of visual changes in a
picture.
In addition to changing object positions using translations or rotations, a computer-
generated animation could display time variations in object size, color, transparency, or
surface texture.
Two basic methods for constructing a motion sequence are
1. real-time animation and
In a real-time computer-animation, each stage of the sequence is viewed as it
is created.
Thus the animation must be generated at a rate that is compatible with the
constraints of the refresh rate.
2. frame-by-frame animation
For a frame-by-frame animation, each frame of the motion is separately
generated and stored.
Later, the frames can be recorded on film, or they can be displayed
consecutively on a video monitor in “real-time playback” mode.
Double Buffering
One method for producing a real-time animation with a raster system is to employ two
refresh buffers.
We create a frame for the animation in one of the buffers.
Then, while the screen is being refreshed from that buffer, we construct the next frame in
the other buffer.
When that frame is complete, we switch the roles of the two buffers so that the refresh
routines use the second buffer during the process of creating the next frame in the first
buffer.
When a call is made to switch two refresh buffers, the interchange could be performed at
various times.
The most straight forward implementation is to switch the two buffers at the end of the
current refresh cycle, during the vertical retrace of the electron beam.
If a program can complete the construction of a frame within the time of a refresh cycle,
say 1/60 of a second, each motion sequence is displayed in synchronization with the
screen refresh rate.
If the time to construct a frame is longer than the refresh time, the current frame is
displayed for two or more refresh cycles while the next animation frame is being
generated.
Similarly, if the frame construction time is 1/25 of a second, the animation frame rate is
reduced to 20 frames per second because each frame is displayed three times.
Irregular animation frame rates can occur with double buffering when the frame
construction time is very nearly equal to an integer multiple of the screen refresh time the
animation frame rate can change abruptly and erratically.
One way to compensate for this effect is to add a small time delay to the program.
Another possibility is to alter the motion or scene description to shorten the frame
construction time.
Object movements can also be emphasized by creating preliminary actions that indicate
an anticipation of a coming motion
class scrPt {
public:
GLint x, y;
};
static void init (void)
{
scrPt hexVertex;
GLdouble hexTheta;
GLint k;
glClearColor (1.0, 1.0, 1.0, 0.0);
/* Set up a display list for a red regular hexagon.
* Vertices for the hexagon are six equally spaced
* points around the circumference of a circle.
*/
regHex = glGenLists (1);
glNewList (regHex, GL_COMPILE);
glColor3f (1.0, 0.0, 0.0);
glBegin (GL_POLYGON);
for (k = 0; k < 6; k++) {
hexTheta = TWO_PI * k / 6;
hexVertex.x = 150 + 100 * cos (hexTheta);
hexVertex.y = 150 + 100 * sin (hexTheta);
glVertex2i (hexVertex.x, hexVertex.y);
}
glEnd ( );
glEndList ( );
}
void displayHex (void)
{
glClear (GL_COLOR_BUFFER_BIT);
glPushMatrix ( );
glRotatef (rotTheta, 0.0, 0.0, 1.0);
glCallList (regHex);
glPopMatrix ( );
glutSwapBuffers ( );
glFlush ( );
}
void rotateHex (void)
{
rotTheta += 3.0;
if (rotTheta > 360.0)
rotTheta -= 360.0;
glutPostRedisplay ( );
}
void winReshapeFcn (GLint newWidth, GLint newHeight)
{
glViewport (0, 0, (GLsizei) newWidth, (GLsizei) newHeight);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ( );
gluOrtho2D (-320.0, 320.0, -320.0, 320.0);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ( );
glClear (GL_COLOR_BUFFER_BIT);
}
void mouseFcn (GLint button, GLint action, GLint x, GLint y)
{
switch (button) {
case GLUT_MIDDLE_BUTTON: // Start the rotation.
if (action == GLUT_DOWN)
glutIdleFunc (rotateHex);
break;
case GLUT_RIGHT_BUTTON: // Stop the rotation.
if (action == GLUT_DOWN)
glutIdleFunc (NULL);
break;
default:
break;
}
}
void main(int argc, char ** argv)
{
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition (150, 150);
glutInitWindowSize (winWidth, winHeight);
glutCreateWindow ("Animation Example");
init ( );
glutDisplayFunc (displayHex);
glutReshapeFunc (winReshapeFcn);
glutMouseFunc (mouseFcn);
glutMainLoop ( );
}