1 / 34

More on Drawing in OpenGL: Examples

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

winka
Download Presentation

More on Drawing in OpenGL: Examples

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. CSC 2141 Introduction to Computer Graphics More on Drawing in OpenGL: Examples

  2. 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

  3. 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

  4. 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

  5. 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(); }

  6. 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(); }

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

  8. 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

  9. 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

  10. 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.

  11. 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.

  12. 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(); }

  13. 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 }

  14. 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); }

  15. 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()

  16. 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)

  17. 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);

  18. 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(); }

  19. Example animation: rotating square x=cosƟ y=sinƟ The point lies on a unit circle regardless of the value of Ɵ

  20. 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 */ }

  21. 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(); }

  22. 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); }

  23. 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.

  24. Try running this with single buffering • Do you notice partial display of rotated square?

  25. 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.

  26. 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

  27. 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

  28. 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); }

  29. 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);

  30. 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…

  31. 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!)

  32. 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

  33. 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; } }

  34. 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.

More Related