More on Drawing in OpenGL: Examples CSC 2141 Introduction to Computer Graphics.
-
Upload
mariah-haynes -
Category
Documents
-
view
221 -
download
1
Transcript of More on Drawing in OpenGL: Examples CSC 2141 Introduction to Computer Graphics.
More on Drawing in OpenGL: Examples
CSC 2141Introduction to Computer Graphics
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)
void mymouse(GLint button, GLint state, GLint x, GLint y)
mouse callback function
GLUT Event Loop
Recall that the last line in main.c for a program using GLUT must beglutMainLoop();
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 functionmydisplay(){}
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 locationvoid 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) wh
ww
y
h-y
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_ALTis depressed byglutGetModifiers()
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 += dtglutPostRedisplay();
}
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 callbackglutIdleFunc(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 asvoid 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);
entries that appear whenright button depressed
identifiers
clear screen
exit
Menu actions
Menu callback
Note each menu has an id that is returned when it is created
void myMenu(int id){
if(id == 1) glClear();if(id == 2) exit(0);
}
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 menuglutAddMenuEntry(“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.