Last modified: 11/22/98. Current gleem version: 1.0
gleem is a small, self-contained C++ library of 3D widgets that support direct user interaction with a 3D scene. The user interfaces are roughly based on the manipulators in Silicon Graphics' Open Inventor; the names are borrowed from Inventor.
The currently implemented manipulators are:
The most recent version of gleem is available from http://www.media.mit.edu/~kbrussel/gleem/.
gleem uses GLUT and OpenGL for acquiring mouse events and performing rendering. However, all of the data structures for storing shapes and computing mouse pointer-object intersections are done within the library, not using the OpenGL pick mechanism. Therefore it should be fairly simple to port gleem to other graphics libraries such as Java3D.
gleem currently does not implement Inventor-style fields, field-to-field connections, reference counting, run-time type checking, instantiation by type ID, or any other of the basic mechanisms which made Inventor possible. It is implemented entirely using virtual functions; there is no casting down the hierarchy based on run-time type checks.
The most fundamental limitation of gleem is that, in the interest of portability, it has no notion of a scene graph. It defines what little such support it needs internally. All manipulators live conceptually in world coordinates. If you want to attach a manipulator to the end of a kinematic chain, for example, you will need to manually keep the manipulator in place as your application moves the links.
gleem was developed under SGI's Irix 6.5. The Makefile is currently set up for SGI's CC and include directories. Type "make" in the gleem subdirectory to build the library and tests. A precompiled version (built on a 6.5 Indy) is in lib/iris. You will need to set your LD_LIBRARY_PATH to, for example, /users/yourname/gleem-1.0/lib/iris before running any of the tests.
The sources should be quite portable and compilable with any recent C++ compiler. STL support is required and SGI's version of the STL is included in the distribution. By default gleem puts all of its datatypes into the namespace "gleem", but if your compiler doesn't support namespaces all of the macros gleem uses to this end are in Namespace.h. If you port gleem to another platform, please consider making a cross-platform Makefile for gmake and submitting your work; see the suggested projects. The "machtype" script in the top-level directory may be useful for this purpose.
To use gleem's manipulators, you need to add the following to your OpenGL/GLUT application:
ManipManager::init()
in main()
.
There must be an open window at this point if you want the ManipManager to
install its callbacks. (To disable callback installation, call
ManipManager::init(false)
.)
ManipManager::updateCameraParameters()
with parameters of your viewing frustum (forward and up vectors, vertical
FOV, image plane aspect ratio, horizontal and vertical size of
window). gleem currently only handles frusta corresponding to symmetric
truncated pyramids.
ManipManager::render()
in your display
callback.
You can then call methods such as getTranslation()
and
getRotation()
on the above manipulator classes in, for
example, its GLUT render callback, and feed those values elsewhere. You can
also register a motion callback via Manip::addMotionCallback()
which will be called each time the manipulator is moved.
See the sources Translate1Test.cpp, Translate2Test.cpp, and TestHandleBox.cpp for specific, small examples of instantiating manipulators.
The ExaminerViewer class implements trackball-style rotation, translation, and dollying of the scene. To use it in conjunction with the ManipManager, you need to do the following:
ExaminerViewer viewer =
new ExaminerViewer();
). This creates a new window internally and
overrides mouse and motion callbacks.
ManipManager::init(false);
. It isn't possible to
re-install the ExaminerViewer's callbacks if they're overridden, so it's
important not to let the ManipManager do so.
viewer->setMouseDelegate(ManipManager::mouseFunc); viewer->setMotionDelegate(ManipManager::motionFunc);
viewer->makeCurrent(); glutPassiveMotionFunc(ManipManager::passiveMotionFunc);
viewer->update();
before you begin drawing
your geometry. This recomputes the ModelView and Projection matrices for
the current rendering context. You should then be able to push matrices on
top of the one loaded by the ExaminerViewer to effect a camera moving about
the scene.
gleem supports rendering manipulators in multiple windows. See
ManipManager::windowCreated()
,
ManipManager::windowDestroyed()
,
ManipManager::addManipToWindow()
, and
ManipManager::removeManipFromWindow
. By default, manipulators
are rendered in the window which was current at the time of their
instantiation (determined via glutGetWindow()
.) See
TestMultiWin.cpp
for an example of rendering the same
manipulator into two windows.
gleem is not thread-safe. You should not attempt to instantiate or use gleem objects in more than one thread.
The Translate1Manip and Translate2Manip are self-explanatory. Click and drag to cause motion along a line or in a plane.
The HandleBoxManipulator contains a box with six faces. Clicking and dragging on any of these six faces causes translational motion in the plane parallel to the face.
This manipulator also contains six handles, each of which can be used to rotate the manipulator about two possible axes. The one chosen at the start of a drag motion is the one most parallel to the viewing direction. If you visualize the two perpendicular planes which go through the handle and three others, the one which is rotated about is the one which is facing the camera the most at the current time.
Scaling of the HandleBoxManip still needs to be implemented.
The ExaminerViewer behaves similarly to Inventor's Examiner Viewer. It grabs all drag motions when the Alt key is depressed. The ExaminerViewer has a conceptual "focal point" which is always defined as being the focal distance directly in front of the viewer.
Drag motions with Alt key depressed:
Calling the viewAll() method re-positions (but does not re-orient) the ExaminerViewer so the bounding sphere given by the BSphereProvider is contained entirely within the viewing frustum. The focal distance is reset to be the distance between the camera and the center of the bounding sphere.
gleem partitions its API into two sections, separate from the C++ access rules. Classes and access qualifiers prefaced with GLEEM_INTERNAL are not intended to be used by outside users, and have even fewer guarantees about interface stability than the public interfaces (which have none).
"Public" classes are in bold.
Manipulator-related classes
Application-level classes
Manipulator parts (visible and/or intersectable geometry)
Linear algebra classes
Other math-related classes
gleem contains a fair amount of documentation in the form of javadoc-style comments. I was not able to find a free document generator for C++ which could turn these into html; please let me know if you know of one. In the meantime, the headers contain all of the class-specific documentation.
Manipulators contain Manipulator Parts. The ManipPart hierarchy is divided into two sections, one containing triangle-based pieces of manipulators and one which contains grouping nodes (analogues to Group and Transform nodes). This is gleem's scene graph mechanism. A warning: shared instancing of "nodes" (ManipParts) in this scene graph is not allowed (since reference counting is not implemented). The ManipManager keeps track of all instantiated manipulators and handles the picking mechanism as well as rendering.
The Manip base class only implements a minimal interface; it is intended that you refer to manipulators through a pointer to the concrete type rather than the abstract Manip type. The simple manipulators (Translate1Manip, Translate2Manip) contain replaceGeometry() methods so you can customize the draggers with whatever geometry you like. It is not so simple to customize a more complex manipulator like the HandleBoxManip, so it contains no such method.
Each manipulator understands its constraints and implements its drag() method from scratch. Clearly there is some commonality between the Translate2Dragger and the translation functionality of the HandleBoxManip. However, this commonality has not been abstracted into a set of classes like Inventor's projectors. Instead there are a few geometrical classes (Line, Plane, PlaneUV) which encapsulate such functionality as ray casting and point projection, and the manipulators determine how to use this information based on what manipulator part was selected and the current configuration of the manipulator.
The linear algebra gleem uses is quite simple and should be accessible to anyone with anyone who has taken an undergraduate linear algebra course. I encourage you to experiment with more sophisticated algorithms for the drag mechanisms.
Recommended texts:
The one thing I strongly recommend against is attempting to turn gleem's internal scene graph (the ManipPart hierarchy) into a full scene graph library. The run-time support is not there, and the structure would need to be fully redesigned for this purpose. On the other hand, I think a free, portable, and high-performance scene graph library is a great idea.
Suggested projects:
Code contributions will be gladly accepted and incorporated into the "official" distribution. Or you can redistribute your modifications yourself; see below.
gleem is distributed under the GNU Library General Public License, version 2.0, or any later version. If you want to incorporate gleem into a commercial product, please contact me so we can discuss exceptions to the license's requirement that you distribute object files as well as gleem's (potentially modified) source code.
gleem includes a copy of SGI's STL implementation. Here is the copyright notice from this library:
/* * * Copyright (c) 1994 * Hewlett-Packard Company * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Hewlett-Packard Company makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * * * Copyright (c) 1996 * Silicon Graphics Computer Systems, Inc. * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Silicon Graphics makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. */
Q: Why don't the manipulators show up in the right place in my application? (Or, why can't I drag them?)
A: gleem expects the following from the rendering state at the time you call ManipManager::render():
TestExaminerViewer.cpp
for an example
of how an application using gleem might be structured.