Week4_MoreDrawingInOpenGL_1

advertisement
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.
Download