Lecture 6 - Handling Input Events
Lecture 6 - Handling Input Events
Handling input
events
glColor3f(0.0, 0.0, 0.0);
draw_object(A);
draw_object(B);
glColor3f(1.0, 0.0, 0.0);
draw_object(C);
• Allow you to link a keyboard key or a mouse button with a routine that's invoked when the key or
mouse button is pressed or released.
glutIdleFunc(void (*func)(void))
• You can specify a function that's to be executed if no other events are pending - for example,
when the event loop would otherwise be idle .
• This routine takes a pointer to the function as its only argument.
• Pass in NULL (zero) to disable the execution of the function.
• Registering callbacks…
User-defined
// Register call backs. functions
glutDisplayFunc(display);
glutReshapeFunc(reshapeMainWindow);
glutKeyboardFunc(graphicKeys);
glutSpecialFunc(functionKeys);
glutMotionFunc(mouseMovement);
glutIdleFunc(idle);
What to do when there’s nothing to do…
Catching a mouse …
How to react on special keys (F1..F12, etc)
How to react on “ordinary” keys…
How to resize on resize event…
Knowing how to display the model
5
Program
#include <GL/glut.h>
MainLoop() Mouse
Window
Event Queue
Events in OpenGL
Event Example OpenGL Callback
Function
Keypress KeyDown glutKeyboardFunc
KeyUp
Mouse leftButtonDown glutMouseFunc
leftButtonUp
Motion With mouse press glutMotionFunc
Without glutPassiveMotionFunc
Callbacks: reshapeMainWindow()
// Respond to window resizing, preserving proportions.
// Parameters give new window size in pixels.
}
glViewport Function
• glViewport: This function defines the current viewport
transform.
• It defines as a region of the window, specified by the
bottom-left position and a width/height.
e.g:
void reshape (int w, int h)
{
if(w < h)
glViewport(0, 0, (GLsizei) w, (GLsizei) w);
else
glViewport(0, 0, (GLsizei) h, (GLsizei) h);
}
Example
#include <GL/glut.h> void reshape(int w, int h)
#include <stdlib.h> {
glViewport (0, 0, (GLsizei) w, int main(int argc, char** argv)
static GLfloat spin = 0.0; (GLsizei) h); {
void init(void) glMatrixMode(GL_PROJECTION); glutInit(&argc, argv);
{ glLoadIdentity(); glutInitDisplayMode
glClearColor (0.0, 0.0, 0.0, 0.0); glOrtho(-50.0, 50.0, -50.0, 50.0, -1.0, (GLUT_DOUBLE | GLUT_RGB);
1.0); glutInitWindowSize (250, 250);
glShadeModel (GL_FLAT);
glMatrixMode(GL_MODELVIEW); glutInitWindowPosition (100, 100);
}
glLoadIdentity(); glutCreateWindow (argv[0]);
void display(void)
} init ();
{
void mouse(int button, int state, int glutDisplayFunc(display);
glClear(GL_COLOR_BUFFER_
x,
BIT); glutReshapeFunc(reshape);
int y)
glPushMatrix(); glutMouseFunc(mouse);
{
glRotatef(spin, 0.0, 0.0, 1.0); glutMainLoop();
switch (button) {
glColor3f(1.0, 1.0, 1.0); return 0;
case GLUT_LEFT_BUTTON:
glRectf(-25.0, -25.0, 25.0, 25.0); }
if (state == GLUT_DOWN)
glPopMatrix();
glutIdleFunc(spinDisplay);
glutSwapBuffers();
break;
}
case GLUT_MIDDLE_BUTTON:
if (state == GLUT_DOWN)
{
glutIdleFunc(NULL);
spin = spin + 2.0;
break;
if (spin > 360.0)
default:
spin = spin - 360.0;
break;
glutPostRedisplay();
}
}
}
b) Window Initialization in init()
•To maximize efficiency, operations that need only be called
once (s.a setting the background color and coordinate
system) are in a procedure called init().
•Operations to render (and possibly re-render) the scene are
in the display() procedure, which is the registered GLUT
display callback.
void init()
{
glClearColor (0.0, 0.0, 0.0, 1.0); black clear color
glColor3f(1.0, 1.0, 1.0);
opaque window
glMatrixMode (GL_PROJECTION);
glLoadIdentity (); fill/draw with white
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); viewing
}
volume
c) glutIdleFunc( idle )
Idle Callback
d)
glutKeyboardFunc
( my_key_events )
void glutKeyboardFunc(void (*func)(unsigned char
key, int x, int y));
• glutMouseFunc( my_mouse );
Example {
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-50.0, 50.0, -50.0, 50.0, -1.0, 1.0);
#include <GL/glut.h>
glMatrixMode(GL_MODELVIEW);
#include <stdlib.h> glLoadIdentity();
static GLfloat spin = 0.0; }
void init(void) void mouse(int button, int state, int x, int y)
{ {
switch (button) {
glClearColor (0.0, 0.0, 0.0, 0.0);
case GLUT_LEFT_BUTTON:
glShadeModel (GL_FLAT); if (state == GLUT_DOWN)
} glutIdleFunc(spinDisplay);
void display(void) break;
{ case GLUT_MIDDLE_BUTTON:
if (state == GLUT_DOWN)
glClear(GL_COLOR_BUFFER_BIT);
glutIdleFunc(NULL);
glPushMatrix(); break;
glRotatef(spin, 0.0, 0.0, 1.0); default:
glColor3f(1.0, 1.0, 1.0); break;
glRectf(-25.0, -25.0, 25.0, 25.0); }}
glPopMatrix();
int main(int argc, char** argv)
glutSwapBuffers(); {glutInit(&argc, argv);
} glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize (250, 250);
{ glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);
spin = spin + 2.0;
init ();
if (spin > 360.0) glutDisplayFunc(display);
spin = spin - 360.0; glutReshapeFunc(reshape);
glutPostRedisplay(); glutMouseFunc(mouse);
} glutMainLoop();
return 0;
}
g) glutMainLoop()
• In event-driven programming, like you have in interactive OpenGL
applications, the main application loop generally does three things:
1. Check the current event queues, and process any events (e.g., mouse
movement, key presses, etc.) that have occurred since the last check
2. Update the application state - things like player and object positions,
game physics, etc. - in preparation of the next rendering frame
• void idle(void) {
time += 0.05;
glutSetWindow(window);
glutPostRedisplay();
}
Double Buffering
• GLUT has support for double buffering through GLUT_DOUBLE.
• Combined with swapping out glFlush() for glutSwapBuffers(), we get a nice constant image on the
screen. Double buffering gives OpenGL a ‘hidden’ render which it can write to while the previous
render is being shown on the screen.
• Think of it this way, you are drawing an animation using two blackboards in front of a crowd of people,
but they only see one blackboard at a time. You draw frame number 1 on blackboard number one and
when it’s complete, you swap blackboard number 1 and blackboard number 2. You then erase
anything on blackboard number 2 and draw the next frame, once it’s complete you once again swap
blackboard number 1 and blackboard number 2.
#include <GL/glut.h>
i) glPopMatrix()
#include <stdlib.h>
void reshape(int w, int h)
static GLfloat spin = 0.0; int main(int argc, char** argv)
{
void init(void) {
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
{ glutInit(&argc, argv);
glMatrixMode(GL_PROJECTION);
glClearColor (0.0, 0.0, 0.0, 0.0); glutInitDisplayMode (GLUT_DOUBLE |
glLoadIdentity();
glShadeModel (GL_FLAT); GLUT_RGB);
glOrtho(-50.0, 50.0, -50.0, 50.0, -1.0, 1.0);
} glutInitWindowSize (250, 250);
glMatrixMode(GL_MODELVIEW);
void display(void) glutInitWindowPosition (100, 100);
glLoadIdentity();
{ glutCreateWindow (argv[0]);
}
glClear(GL_COLOR_BUFFER_BIT); init ();
void mouse(int button, int state, int x,
glPushMatrix(); glutDisplayFunc(display);
int y)
glRotatef(spin, 0.0, 0.0, 1.0); glutReshapeFunc(reshape);
{
glColor3f(1.0, 1.0, 1.0); glutMouseFunc(mouse);
switch (button) {
glRectf(-25.0, -25.0, 25.0, 25.0); glutMainLoop();
case GLUT_LEFT_BUTTON:
glPopMatrix(); return 0;
if (state == GLUT_DOWN)
glutSwapBuffers(); }
glutIdleFunc(spinDisplay);
}
break;
case GLUT_MIDDLE_BUTTON:
{
if (state == GLUT_DOWN)
spin = spin + 2.0;
glutIdleFunc(NULL);
if (spin > 360.0)
break;
spin = spin - 360.0;
default:
glutPostRedisplay();
break;
}
}
}
The Matrix Stack
• You may notice that when you assign a colour
to an object, that colour will also attach itself to
every object you draw after the colour
statement.
• Or the same for rotations and translations. This
is because OpenGL is based on a state
machine.
• Every time you perform an action such as glTranslate or glRotate, then you
are modifying the transformation matrix, and once something has been
done, it cannot be easily undone, so OpenGL makes use of states.
• State means that once an operation has been performed, it will affect
everything to come, but it means we can go back to a previous state and
forget about our current one.
• To do this, we only need to make use of two commands.
They are:
glPushMatrix(); //set where to start the current object transformations
and:
• glPopMatrix(); //end the current object transformations
• The first call, glPushMatrix(), tells OpenGL to
store the current state that we are in.
This then allows us to perform a bunch of
different effects.
• Then when we want to go back to our previous
state, we call glPopMatrix().
• This works fine for rotations and translations, but
OpenGL allows for many other commands, so it
gives us the ability to store attributes with
glPushAttrib() and glPopAttrib().
• Some of the attributes that we can store include,
GL_LIGHT and GL_COLOUR, but there are
many more.
Manipulating the matrix stack
void glPushMatrix(void);
• Pushes all matrices in the current stack down one level. The
current stack is determined by glMatrixMode().
• The topmost matrix is copied, so its contents are duplicated in
both the top and second-from-the-top matrix.
• If too many matrices are pushed, an error is generated.
void glPopMatrix(void);
• Pops the top matrix off the stack, destroying the contents of
the popped matrix.
• What was the second-from-the-top matrix becomes the top
matrix.
• The current stack is determined by glMatrixMode().
• If the stack contains a single matrix, calling glPopMatrix()
generates an error.
Example: Draws an automobile, assuming the existence of routines that draw the car body, a wheel, and a bolt by Pushing
and Popping the Matrix
draw_wheel_and_bolts()
{
long i;
draw_wheel();
for(i=0;i<5;i++){
glPushMatrix();
glRotatef(72.0*i,0.0,0.0,1.0);
glTranslatef(3.0,0.0,0.0);
draw_bolt();
glPopMatrix();
}
}
draw_body_and_wheel_and_bolts()
{
draw_car_body();
glPushMatrix();
glTranslatef(40,0,30); /*move to first wheel position*/
draw_wheel_and_bolts();
glPopMatrix();
glPushMatrix();
glTranslatef(40,0,-30); /*move to 2nd wheel position*/
draw_wheel_and_bolts();
glPopMatrix();
... /*draw last two wheels similarly*/
}
The Modelview Matrix Stack
• The modelview matrix contains the cumulative product of
multiplying, viewing and modeling transformation matrices.
• Each viewing or modeling transformation creates a new matrix
that multiplies the current modelview matrix; the result, which
becomes the new current matrix, represents the composite
transformation.
• The modelview matrix stack contains at least thirty-two 4 × 4
matrices; initially, the topmost matrix is the identity matrix.
Some implementations of OpenGL may support more than
thirty-two matrices on the stack.
The Projection Matrix Stack