Hierarchical transformations can be thought of as transformations that are "attached to" other transformations.
They are used to transform objects relative to other objects.
A common use is in articulated bodies.
We can draw this "car" by transforming the two wheels relative to the body of the car.
We'd like each wheel to be affected by the car body's transformation, but not by any other wheel's transformation.
The basic tool needed is commands to save & restore transformation state.
apply body transformation draw body save state apply front wheel transformation draw wheel restore saved state apply rear wheel transformation draw wheel
A transformation is represented mathematically as a matrix.
OpenGL maintains a stack of saved transformation matrices.
glPushMatrix() & glPopMatrix() save and restore transformation state.
Make sure you always have the same number of pushes & pops.
The number of transformations you can save is finite; it is at least 32.
Hierarchical transformations are often represented as a tree of transformations.
This is the basis of scene graph systems.
glutKeyboardFunc(func) | Called when a 'character' key is hit |
glutSpecialFunc(func) | Called when a 'special' key is hit |
glutKeyboardUpFunc(func) | Called when a 'character' key is released |
glutSpecialUpFunc(func) | Called when a 'special' key is released |
glutGetModifiers() | Returns state of shift, control, alt keys when event happened |
glutIgnoreKeyRepeat(val) | Tells GLUT whether to ignore automatic keyboard repeat |
All keyboard callback functions take the form:
def func(key, x, y): ...
key is the key pressed or released - either a single-character string (e.g. 'a'), or a special-key constant (e.g. GLUT_KEY_UP)
x, y is the mouse pointer location when the key event occurred
Note: in Python, the same function can be used for both normal & special keys
glutGetModifiers() returns a bit-mask value
i.e. a combination of flags
Possible flags are GLUT_ACTIVE_SHIFT, GLUT_ACTIVE_CTRL, and GLUT_ACTIVE_ALT
Test a flag with the & operator. e.g.:
if glutGetModifiers() & GLUT_ACTIVE_CTRL: doSomethingForCtrlKey()
glutMouseFunc(func) | Called when a mouse button is pressed |
glutMotionFunc(func) | Called when mouse moves, while button pressed |
glutPassiveMotionFunc(func) | Called when mouse moves, with no button pressed |
glutGetModifiers() | Returns state of shift, control, alt keys when event happened |
Mouse-button callback functions take the form:
def func(button, state, x, y): ...
button is the button pressed or released - one of GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, or GLUT_RIGHT_BUTTON
state is GLUT_DOWN if the button was pressed, or GLUT_UP if it was released
x, y is the mouse pointer location when the button was pressed or released
Mouse-motion callback functions take the form:
def func(x, y): ...
x, y is the new mouse pointer location
GLUT provides simple pop-up menus
A menu is attached to a mouse button, and appears whenever that button is pressed
If a menu entry is selected, a callback is called with a value associated with that entry
Menus can include sub-menus
id = glutCreateMenu(func) | Starts defining a new menu (or submenu) |
glutAddMenuEntry(label, value) | Adds a selectable entry to the current menu |
glutAddSubMenu(label, id) | Adds a submenu to the current menu |
glutAttachMenu(button) | Defines mouse button to pop-up the current menu |
Examples:
menu0.py
menu1.py
menu2.py
Each menu has a unique ID - a number
ID primarily needed when creating submenus
Value associated with a menu entry must be a single integer
Menus can be changed dynamically
(See glutSetMenu, glutRemoveMenuItem, glutChangeToMenuEntry, glutChangeToSubMenu)
Menus can also be attached & detached from buttons dynamically (See glutDetachMenu)