CSC 333 Exercise 1

Sept 6, 2005

Write a program that allows the user to draw free-hand shapes with the mouse: whenever the left mouse button is down, mouse motions leave a colored track. When the left mouse button is up, mouse motions have no effect. Use the example code in Section 3.5 of the textbook to get you started.

Enhancements

(try as many of these as you wish; I recommend, but don't insist, that you do them in this order).
  1. The sample code in the textbook uses the width and height of the window (in pixels) as both window coordinates and model coordinates (the only difference is that window coordinates have y=0 at the top, and model coordinates have y=0 at the bottom, hence the mysterious line of code y = wh - y;). Modify your program so that the model coordinates are floating-point numbers in the range 0-1, while the window coordinates remain integers in the range 0-500 (or whatever the current window size is). This will help you keep model coordinates and window coordinates distinct in your mind.

  2. Add a window-reshape callback function, like that in the textbook, but bearing in mind the distinction between model and window coordinates. There are several ways you can do this:

    The difference among these choices will be perceptible mainly to the programmer, not the user, unless you implement some form of ...

  3. object permanence.
    If you draw directly into the graphics frame buffer, then every time the window is resized, or covered by another window and uncovered, or minimized and restored, etc. you'll lose whatever you had drawn before. The usual way to solve this problem is called "damage and redraw": maintain a modifiable internal model, make all modifications to it rather than to the frame buffer, and have a display callback simply draw the current state of the internal model. Note that whenever you change the internal model, you have to tell OpenGL that the model has changed (e.g. by calling glutPostRedisplay()), or your change won't be visible on the screen until the next time the window is resized, covered and uncovered, etc. Likewise, if the user gives a command to change the scaling factor, you need to call glutPostRedisplay() to cause the window to be redrawn with the new scaling factor.

    One approach to implementing the internal model is described in section 3.9, which also allows the user to delete individual parts of the model (s)he has previously created. This approach works best with simple geometric shapes, but you can define a type of object to represent a freehand-drawn curve (presumably stored as a list of vertices).

  4. Add a keyboard callback function, e.g. to quit the program when the user types the letter 'q'. You could also use the '+' and '-' keys to change the scale factor. Again, the effect won't be visible unless you've implemented object permanence.

  5. Add the ability for the user to create circles, rectangles, squares, line segments, etc. of fixed size and shape. The sample program in section 3.8 (and appendix A.6) does this with a tool palette, so that a mouse-click in any of the boxes of the palette allows the user to select what shape to create next; one or more subsequent mouse-clicks in the main portion of the screen create the shape. Obviously, you won't learn much from simply copying paint.c from the Appendix; I'd like you to try to write as much as possible of this from scratch, turning to the Appendix code only for help with specific problems.

  6. Add the ability for the user to specify the size and shape of new geometric objects by rubber-banding. For example, one might create a circle by clicking on the center, then holding the mouse button down while dragging to some distance away, which will become the radius; while the mouse is being dragged, the display updates continuously to show what the circle would look like if the mouse button were released right now. One might create a rectangle by clicking on one corner and dragging to the opposite corner; again, the display is continuously updated to show what the rectangle would look like if the mouse button were released now.

  7. Add the ability for the user to select an existing shape and delete it (e.g. by pressing the DEL key on the keyboard). In the damage-and-redraw approach, this simply requires deleting the shape from the internal model and telling OpenGL to redraw everything.

  8. Use display lists to "pre-compute" some of the work: every time you create a complex object, assign it a unique identifying number and compile a display list for it. The display callback function will then simply invoke glCallList() for the identifying numbers of each of the objects that still exist in the model (i.e. haven't been deleted); if these numbers are stored in an array, it can be done very easily using glCallLists().

    Note that this enhancement probably won't make a visible difference unless you're running the program in a client-server context, especially over a slow connection. If you are, you may save considerable bandwidth by sending only the identifying numbers of objects, rather than all the primitives that make them up.

  9. Add the ability for the user to select an existing shape and make it start or stop rotating (as described in section 3.10.1).

  10. Add double-buffering (section 3.10.2), so the animation looks smooth, even if you have a lot of objects rotating at the same time.

  11. Add a timer callback (section 3.10.3), so you can control how fast things rotate.


You are visitor number to this and related pages since Sept 30, 2005.
Last modified:
Stephen Bloch / sbloch@adelphi.edu