libdcu can be found (at EVL) in ~pape/lib; the header files are in ~pape/include. DCU.tar.gz contains the source code and compiled library for downloading; it also contains a few random, undocumented demo programs. Some of the demos also require the libwave library for rendering Wavefront OBJ-format models.
Audio classes
There are two main parts to the audio classes - samples
and the dcuAudioEnv class.
The sample classes (dcuSample,
dcuLoopSample, dcuTriggerSample,
dcuWandTriggerSample,
dcuRandomSample) control individual sound samples, playing
them and updating them based on the specific class's behavior.
The dcuAudioEnv class holds a collection of samples, updates
them as a group, and can automatically build an environment from
a text description file.
The volume classes can
be used with samples to control their amplitude and when they are played.
#include "dcuSample.h"
The default settings for a newly created dcuSample are: no file or directory, length 0, maximum amplitude 1, maximum distance DCU_DEFAULT_MAX_DIST (defined in dcuSample.h), attack and decay 0, and a generic dcuVolume (which occupies infinite space - i.e., the distance to any position is 0).
The dcuSample constructor creates a vss SampleActor for the sound. Hence, samples should not be created until after BeginSoundServer() is called.
A dcuSample object can be used to simply play sound files when needed, or to control dynamic, positional sounds. The following code fragment is an example of playing a sound without any subsequent updates; the sound will be played at the specified maximum amplitude, since it uses the default dcuVolume.
BeginSoundServer(); dcuSample * sample = new dcuSample("sound.aiff",0.25); sample->setDirectory("/usr/data/sounds"); sample->play(); sleep(5); delete sample; EndSoundServer();To play a positional sound, the update() function must be called frequently, in order for the amplitude to be adjusted for the user's position. Also, a volume other than the default and a non-zero length must be set. The following fragment starts a sound which is defined to be 240 seconds long; it is assigned a dcuPointVolume (with a default position of (0,0,0)).
float userPos[3]; dcuSample * sample = new dcuSample("sound.aiff",0.25); sample->setDirectory("/usr/data/sounds"); sample->setLength(240.0); sample->setVolume(new dcuPointVolume); CAVEGetPosition(CAVE_HEAD_NAV, userPos); sample->play(userPos,CAVEGetTime()); while (1) { navigate(); CAVEGetPosition(CAVE_HEAD_NAV, userPos); sample->update(userPos,CAVEGetTime()); sginap(1); }
#include "dcuLoopSample.h"
#include "dcuRandomSample.h"
A dcuRandomSample is a sound sample which is triggered at random
intervals by update(). The maximum amplitude of the sample is also
set randomly, each time it is started by update(). update() will
not start more than one instance of the sound at a time.
#include "dcuTriggerSample.h"
A dcuTriggerSample is a sound which is automatically played whenever
the user moves near it. Whenever update() determines that the user
has entered the sample's area of effect, it is immediately played.
The sample then latches until the user moves back outside the area
of effect, so that it will only be played one time whenever the
user enters the area.
When the sample is triggered, it plays once for its entire length -
it does not stop if the user moves outside of the triggering radius.
#include "dcuWandTriggerSample.h"
#include "dcuAudioEnv.h"
The interfaces to the different classes are as follows:
#include "dcuVolume.h"
The generic dcuVolume class is primarily a parent for the other volume
classes. It represents an infinite space - any point is inside the
space, and the distance functions will always return 0.
#include "dcuPointVolume.h"
A dcuPointVolume represents a single point. The distance of any
point from the volume is the Euclidean distance from the volume's
position defined by setCenter().
#include "dcuSphereVolume.h"
A dcuSphereVolume represents an n-dimensional sphere - it contains all
points which are within radius() units of the volume's origin (getCenter()).
#include "dcuBoxVolume.h"
A dcuBoxVolume is an axis-aligned box; points which lie between the
box's minimum & maximum in each dimension are inside the box.
The dcuGrabber subclass is for grabbing
objects with the wand or other sensors; it takes care of switching between
world-space and sensor-space coordinates, so that when an object is grabbed
or released it stays in the same position and orientation.
Class interfaces:
#include "dcuTransform.h"
The following code fragment demonstrates the basic use of a dcuTransform to
animate an object:
#include "dcuGrabber.h"
The following code fragment demonstrates the basic use of a dcuGrabber:
#include "dcuImage.h"
#include "dcuTexture.h"
#include "dcuSharedImage.h"
The public interface to dcuSharedImage is identical to that of dcuImage.
However, when an image is loaded, its data (and dimensions) are placed in
shared memory, allocated by CAVEMalloc().
As long as the dcuSharedImage object itself is created before calling CAVEInit(),
the image data will be visible to all CAVE processes, even if an image
is loaded after CAVEInit().
dcuSharedImage::setImage() should only be passed pointers to image data
in shared memory; for non-shared data, use copyImage().
A dcuSharedImage can be used with a dcuTexture to create a "delayed texture",
so that a program does not have to wait for all the images to be loaded before
beginning rendering. The following code fragment demonstrates this:
#include "dcuTrigger.h"
dcuTriggerSample
Sound object triggered by user proximity.
The default trigger radius is 1.
When playing, the sample is updated by the normal dcuSample update() function.
dcuWandTriggerSample
Sound object triggered by wand proximity; subclass of dcuTriggerSample.
A dcuWandTriggerSample functions exactly like a dcuTriggerSample, except
that it is triggered by the wand position rather than the user's position.
When playing, the sample is updated by the normal dcuSample update() function.
dcuAudioEnv Class
Audio environment manager object.
A dcuAudioEnv is used to collect dcuSample objects into a group;
the dcuAudioEnv can then automatically handle the updates for all
the samples at once. It can also read in an audio environment description
file an create all the samples defined in the file.
Volume Classes
The volume classes represent simple bounding volumes; they
provide functions for computing the distance of a point to the volume
and for determining if a point is inside the volume.
Volumes can be 3, 2, 1, or 0 dimensional.
Volumes are used with the sample classes
to compute the distance from the user to the sound.
The available classes are dcuVolume,
dcuPointVolume, dcuSphereVolume,
and dcuBoxVolume.
dcuVolume
Generic volume object; parent of all other volume classes.
The default dimensions for a volume are all 3, DCU_X_DIM | DCU_Y_DIM | DCU_Z_DIM;
the default position is (0,0,0).
dcuPointVolume
Single point volume.
dcuSphereVolume
Spherical volume.
The default radius of a dcuSphereVolume is 1.
dcuBoxVolume
Axis-aligned box volume.
The default size of a box is 1 in each dimension.
Transformation Classes
The transformation classes handle GL transformations for 3D objects.
The base dcuTransform class stores its
matrix in shared memory, and so can be used to manipulate a transformation
from any process.
dcuTransform
Stores and manipulates a 4x4 transformation matrix. The standard GL-style
translate, rotate, and scale operations can be applied to the matrix.
The matrix is stored in shared memory; a CAVELOCK is used to control
access to it.
Note: The inverse matrix routines assume that the transformation
is affine. If a non-affine matrix is created (via loadMatrix(), preMultMatrix(),
or postMultMatrix()), the results are undefined.
The dcuTransform constructor loads the identity matrix by default.
Because it allocates shared memory and a lock, a dcuTransform cannot be created until
after CAVEConfigure() has been called.
dcuTransform *transform;
main(int argc,char **argv)
{
CAVEConfigure(&argc,argv,NULL);
transform = new dcuTransform;
CAVEInit();
CAVEDisplay(draw_fn,0);
while (1)
{
transform->rotate(2.0, 0.0,1.0,0.0);
sginap(10);
}
}
void draw_fn(void)
{
...
glPushMatrix();
transform->glTransform();
draw_the_object();
glPopMatrix();
...
}
dcuGrabber
Class for grabbing objects with a CAVE sensor; subclass of dcuTransform.
A dcuGrabber's grab() state flag and sensor pointer are stored in shared memory.
dcuGrabber *grabber;
main(int argc,char **argv)
{
...
grabber = new dcuGrabber;
...
while (1)
{
int cb1 = CAVEButtonChange(1);
if (cb1 == 1) /* Grab whenever button 1 is pressed */
grabber->grab();
else if (cb1 == -1) /* Release when button 1 is released */
grabber->release();
...
}
}
void draw_fn(void)
{
...
glPushMatrix();
grabber->glTransform();
draw_the_object();
glPopMatrix();
...
}
A dcuGrabber can be assigned to a dcuVolume as the volume's transform.
This code fragment shows how to use a grabber and a volume together to
grab an object only when the wand is within its bounding volume:
dcuGrabber *grabber;
main(int argc,char **argv)
{
...
grabber = new dcuGrabber;
dcuSphereVolume *volume = new dcuSphereVolume;
volume->setCenter(objectCenter); /* Define the object's bounding sphere */
volume->setRadius(objectRadius);
volume->setTransform(grabber);
...
while (1)
{
int cb1 = CAVEButtonChange(1);
if (cb1 == 1) /* Grab when button 1 is pressed */
{ /* inside the volume */
float wandPos[3];
CAVEGetPosition(CAVE_WAND_NAV,wandPos);
if (volume->contains(wandPos))
grabber->grab();
}
else if (cb1 == -1) /* Release when button 1 is released */
grabber->release();
...
}
}
void draw_fn(void)
{
...
glPushMatrix();
grabber->glTransform();
draw_the_object();
glPopMatrix();
...
}
Image & Texture classes
dcuImage
Class for loading SGI format images. Images are stored 32 bit longword
arrays.
dcuTexture
Creates an OpenGL texture map from a dcuImage.
The texture object extension (glBindTextureEXT()) will be used in defining and
binding the texture, if the graphics hardware supports it; if not, a display list
will be used.
The default minification and magnification filters are GL_NEAREST.
The default wrapping modes are GL_REPEAT.
dcuSharedImage
Loads an SGI format image, storing the data in shared memory. A subclass of dcuImage.
dcuTexture *texmap;
void defineTexture(void)
{
texmap->define();
}
void drawfn(void)
{
...
texmap->bind(); /* If the texture hasn't been defined, this will just turn off texturing */
glBegin(GL_TRIANGLE_STRIP);
glTexCoord3fv(tc[0]);
glVertex3fv(vert[0]);
glTexCoord3fv(tc[1]);
glVertex3fv(vert[1]);
glTexCoord3fv(tc[2]);
glVertex3fv(vert[2]);
glEnd();
...
}
main(int argc,char **argv)
{
dcuSharedImage *img;
CAVEConfigure(&argc,argv,NULL);
texmap = new dcuTexture; /* Create the texture, but don't wait to load the image */
img = new dcuSharedImage;
texmap->setImage(img);
CAVEInit();
CAVEDisplay(drawfn,0);
img->loadFile("texture.rgb"); /* Now load the image in parallel with the graphics */
CAVEInitApplication(defineTexture,0); /* Tell the graphics to define() the texture */
...
}
This method can also be used to change a texture map dynamically, without making
the display processes take time to read the file from disk.
Trigger Class
A dcuTrigger associates callback functions with a volume.
Whenever the position data passed to the trigger enters or leaves
the volume, the corresponding function is called.
Miscellaneous Utilities
#include "dcu.h"
struct _dcukeyword { char *str; int id; };
The last entry in table must have a str member of NULL,
to mark the end of the array.
Last modified 13 October 1997.
Dave Pape, pape@evl.uic.edu