Week4_MoreDrawingInOpenGL_1
Download
Report
Transcript Week4_MoreDrawingInOpenGL_1
CSC 2141
Introduction to Computer Graphics
More on Drawing in OpenGL: Examples
Recall: Callbacks
Programming interface for event-driven input
Define a callback function for each type of event the
graphics system recognizes
This user-supplied function is executed when the event
occurs
GLUT example: glutMouseFunc(mymouse)
mouse callback function
void mymouse(GLint button, GLint state, GLint
x, GLint y)
GLUT Event Loop
Recall that the last line in main.c for a program using GLUT must be
glutMainLoop();
which puts the program in an infinite event loop
In each pass through the event loop, GLUT
looks at the events in the queue
for each event in the queue, GLUT executes the appropriate callback
function if one is defined
if no callback is defined for the event, the event is ignored
Using the mouse position
In the next example, we draw a small square at the
location of the mouse each time the left mouse button is
clicked
This example does not use the display callback but one is
required by GLUT; We can use the empty display callback
function
mydisplay(){}
main() function same as before
Globals and myInit()
Glsizei wh =500, ww=500; /* window dimensions */
GLfloat size = 3.0; /* one-half of side length of square */
myInit(void) {
/* set viewing conditions */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D (0.0, (GLdouble) ww,
0.0, (GLdouble) wh );
glMatrixMode(GL_MODELVIEW);
/* adjust viewport */
glViewport(0, 0, ww, wh);
glClearColor(0.0, 0.0,0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glFlush();
}
Drawing squares at cursor location
void mymouse(int btn, int state, int x, int y)
{
if(btn==GLUT_RIGHT_BUTTON && state==GLUT_DOWN)
exit(0); /*terminate the program through OpenGL */
if(btn==GLUT_LEFT_BUTTON && state==GLUT_DOWN)
drawSquare(x, y);
}
void drawSquare(int x, int y) /* (x,y) is the center */
{
y=wh-y; /* invert y position */
glColor3ub( (char) rand()%256, (char) rand ()%256,
(char) rand()%256); /* a random color */
glBegin(GL_POLYGON);
glVertex2f(x+size, y+size);
glVertex2f(x-size, y+size);
glVertex2f(x-size, y-size);
glVertex2f(x+size, y-size);
glEnd();
glFlush();
}
Positioning
• The position in the screen window returned by callback
functions is with respect to the origin at the top-left corner
(GLUT convention)
• Consequence of refresh done from top to bottom
• OpenGL uses a world coordinate system with origin at the
bottom left
• Must invert y coordinate returned by mouse callback using
the height of the window
• y = wh – y;
(0,0)
y
wh
h-y
ww
Obtaining the window size
To invert the y position we need the window height
Height can change during program execution
New height returned to reshape callback
Track with a global variable
Recall: The Reshape callback
glutReshapeFunc(myreshape)
void myreshape( int w, int h)
Returns width and height of new window (in pixels)
A redisplay is posted automatically at end of execution of the
callback
The reshape callback is good place to put viewing
functions because it is invoked when the window is first
opened
Recall: The Reshape callback
Do we redraw all the objects that were in the window
before it was resized?
We need a mechanism to store and recall them
Typically done by encapsulating all drawing in the display callback
and reposting the display redraws all.
In this example: our drawing is interactive based on
mouse input and unless we store the squares drawn, we
cannot recall them
Let’s choose to clear the window if resized.
Recall: The Reshape callback
What do we do if the aspect ratio of the new window is
different from that of the old window?
No single answer
Distortions may be okay
Or not
then set the viewport such that it has the same aspect ratio as the
drawing area.
Part of the window may not be used.
In this example, we clear the window when resized so no
distortion to old squares. New squares are drawn with the
same fixed size.
Example Reshape
This reshape preserves shapes by making the viewport and the idealized
drawing window have the same aspect ratio
void myReshape(GLsizei w, GLsizei h)
{
ww = w; /* update window dimensions */
wh = h;
/* adjust clipping box */
glMatrixMode(GL_PROJECTION); /* switch matrix mode */
glLoadIdentity();
gluOrtho2D (0.0, (GLdouble) w, 0.0, (GLdouble) h );
glMatrixMode(GL_MODELVIEW); /* return to modelview mode */
/* adjust viewport */
glViewport(0, 0, w, h);
/* clear the window each time it is resized */
glClear(GL_COLOR_BUFFER_BIT);
glFlush();
}
Using globals
The form of all GLUT callbacks is fixed
void mydisplay()
void mymouse(GLint button, GLint state, GLint
x, GLint y)
Must use globals to pass information to callbacks
float size; /*global */
void mydisplay()
{
/* draw something that depends on size
}
Recall: Using the keyboard
glutKeyboardFunc(myKeyboard)
void myKeyboard(unsigned char key,
int x, int y)
Returns ASCII code of key depressed and mouse location
void myKeyboard(unsigned char key,
int x, int y)
{
if(key == ‘Q’ || key == ‘q’)
exit(0);
}
Special and Modifier Keys
GLUT defines the special keys in glut.h
Function key 1: GLUT_KEY_F1
Up arrow key: GLUT_KEY_UP
if(key == ‘GLUT_KEY_F1’ ……
Can also check of one of the modifiers
GLUT_ACTIVE_SHIFT
GLUT_ACTIVE_CTRL
GLUT_ACTIVE_ALT
is depressed by
glutGetModifiers()
Using the motion callback
We can draw squares (or anything else) continuously as
long as a mouse button is depressed by using the motion
callback
glutMotionFunc(drawSquare)
We can draw squares without depressing a button using the
passive motion callback
glutPassiveMotionFunc(drawSquare)
Changing and disabling callback functions
We can change most callback functions during program
execution by specifying a new callback function
We can also disable a callback function by setting it to NULL
glutIdleFunc(NULL);
Using the idle callback
The idle callback is executed whenever there are no events
in the event queue
glutIdleFunc(myidle)
Useful for animations
void myidle() {
/* change something */
t += dt
glutPostRedisplay();
}
Void mydisplay() {
glClear();
/* draw something that depends on t */
glutSwapBuffers();
}
Example animation: rotating square
x=cosƟ
y=sinƟ
The point lies on a unit circle
regardless of the value of Ɵ
myDisplay()
void myDisplay() {
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_POLYGON);
thetar = theta * (2 * 3.14159) / 360.0;
/* convert degrees to radians */
glVertex2f(cos(thetar), sin(thetar));
glVertex2f(-sin(thetar), cos(thetar));
glVertex2f(-cos(thetar), -sin(thetar));
glVertex2f(sin(thetar), -cos(thetar));
glEnd();
glutSwapBuffers(); /* double buffering */
}
Change Ɵ as the program runs…
In main() function specify callback
glutIdleFunc(myIdle);
And, define callback function as
void myIdle () {
theta += 2;
if (theta >= 360.0)
theta -= 360.0;
glutPostRedisplay();
}
One further change..
Turn on and off the rotation feature by mouse input
Register mouse callback as
glutMouseFunc(myMouse);
Define mouse callback as
void myMouse(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON)&&(state == GLUT_DOWN)
glutIdleFunc(myIdle);
if (button ==GLUT_RIGHT_BUTTON)&&(state == GLUT_DOWN)
glutIdleFunc(NULL);
}
Too fast?
Use a timer callback instead
Which in turn will execute the display callback at a fixed rate
(e.g. n frames per second)
glutTimerFunc(1000/n, myTimer, 0);
But no support for cancelling a timer callback.
instead you can ignore a callback based on its value.
Try running this with single buffering
Do you notice partial display of rotated square?
Multiple Windows
GLUT supports multiple windows
id = glutCreateWindow(“Second window”);
And select this as the current window by
glutSetWindow(id);
You can make this window have different properties by
invoking glutInitDisplayMode before
glutCreateWindow
Each window can set its own callback functions
Callback registrations refer to the current window.
Menus
GLUT supports pop-up menus
A menu can have submenus
Three steps
Define entries for the menu
Define action for each menu item
Action carried out if entry selected
Attach menu to a mouse button
Defining a simple menu
In main.c
glutCreateMenu(myMenu);
glutAddMenuEntry(“clear Screen”, 1);
glutAddMenuEntry(“exit”, 2);
glutAttachMenu(GLUT_RIGHT_BUTTON);
clear screen
exit
entries that appear when
right button depressed
identifiers
Menu actions
Menu callback
void myMenu(int id)
{
if(id == 1) glClear();
if(id == 2) exit(0);
}
Note each menu has an id that is returned when it is created
Menu actions
Hierarchical menus are allowed
Add submenus by
glutAddSubMenu(char *submenu_name, int submenu_id)
int sub_menu;
sub_menu=glutCreateMenu(size_menu);
//add to the current menu
glutAddMenuEntry(“Increase square size”,2);
glutAddMenuEntry(“decrease square size”,3);
glutCreateMenu(top_menu);
glutAddMenuEntry(“Quit”, 1);
glutAddSubMenu(“Resize”, sub_menu);
glutAttachMenu(GLUT_MIDDLE_BUTTON);
Text
We often want to control size, color
and font
Two ways in OpenGL
1. Stroke Text:
constructed as other graphics primitives
Use vertices to draw line segments or
curves outlining the character
Advantage: define once and apply
transformations to generate any size
and orientation
Disadv: defining a full character set is
complex…
Text
2. Raster text
Simple and fast
Character is defined as rectangular
array of bits (0s or 1s) called bit blocks
or bitmap
A raster character can be placed in
frame buffer directly. When you overlay
a bitmap on the frame buffer, the pixels
that correspond to 1s are set to the
current color.
You can increase character size only
by replicating pixels.
Larger characters: blocky appearance
Transformations like rotation do not
make sense (can’t rotate pixel
positions!)
Raster text
glutBitmapCharacter(GLUT_BITMAP_8_BY_13, c)
GLUT_BITMAP_8_BY_13: is a set of bitmaps predefined in GLUT.
It’s a fixed width font, i.e. all characters have the same width.
c is the integer equivalent of an ASCII character
Above function places c at the “current” raster position (part
of state) and automatically advances the current position by
the character width after the character is drawn.
Position can be altered by
glRasterPos*(rx, ry);
glutBitmapWidth(GLUT_BITMAP_8_BY_13, c)
Returns the width of the character c in pixels
Typical function to display a string
void bitMapString( float x, float y, char s[])
int i = 0;
glRasterPos2f( x, y);
{
while (s[i] != '\0') {
glutBitmapCharacter( GLUT_BITMAP_8_BY_13, s[i]);
++i;
}
}
Stroke Text
glutStrokeCharacter(GLUT_STROKE_MONO_ROMAN, c)
You can use a predefined font as GLUT_STROKE_MONO_ROMAN
Or, you can define your own fonts!
Be careful: the way this function works may affect OpenGL state (the
transformation matrices, you might need to save them)
For now use raster text.