/* Author : Josh Grant
Date : October 20th, 2000
Description: This program uses the classes SoUnitCube and
SoBouncingSpheres to illustrate any number of spheres
bouncing around within a cube created by SoUnitCube. The
attributes of each sphere are determined randomly at
runtime. They include the
number of spheres - ranging from 1 to maxnum specified on
the command line
radius - range from 0.0 to 0.25
velocity - each coordinate ranges from 0.0 to 0.2
location - each coordinate ranges from -1.0 to 1.0
colors - each component ranges from 0.0 to 1.0
All of these parameters are then passed to the
SoBouncingSpheres class for processing. In order to get the
spheres within the SoBouncingSpheres node to move an
SoTimerSensor is created to schedule the executing of the
call to SoBouncingSpheres::moveSpheres(). The interval of
the Timer can be specified at the command line.
Type -h or -help at the command line for more information.
*/
#include <Inventor/Xt/SoXt.h>
#include <Inventor/Xt/viewers/SoXtExaminerViewer.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/sensors/SoTimerSensor.h>
#include <SoBouncingSpheres.h>
#include <SoUnitCube.h>
#include <iostream.h>
int sphereNum = 0;
const int maxSpheres = 10;
float timer = 0.04;
////////////////////////////////////////////////////////////
//
// The scene graph is constructed as indicated in the
// diagram below.
//
// root
// |
// -------------------
// | |
// SoUnitCube SoBouncingSpheres
SoSeparator *makeScene (int sphereNum) {
int numSpheres, i, j;
float *radii, loc;
SbVec3f *velocities, *locations;
SbColor *colors;
SoSeparator *root = new SoSeparator();
SoUnitCube *unitCube = new SoUnitCube();
root->addChild(unitCube);
if (sphereNum > 0)
numSpheres = sphereNum;
else
numSpheres = (int)((double)maxSpheres * drand48() + 1.0);
radii = new float[numSpheres];
velocities = new SbVec3f[numSpheres];
locations = new SbVec3f[numSpheres];
colors = new SbColor[numSpheres];
for (i = 0; i < numSpheres; i++) {
radii[i] = drand48() / 4.0;
for (j = 0; j < 3; j++) {
velocities[i][j] = (2.0 * drand48()) / 10.0;
loc = 2.0 * (drand48() - 0.5);
if (loc < 0.0)
locations[i][j] = loc + radii[i];
else
locations[i][j] = loc - radii[i];
colors[i][j] = drand48();
}
}
SoBouncingSpheres *bouncing = new SoBouncingSpheres(numSpheres);
bouncing->setRadii (0, numSpheres, radii);
bouncing->setVelocities(0, numSpheres, velocities);
bouncing->setLocations (0, numSpheres, locations);
bouncing->setColors (0, numSpheres, colors);
root->addChild(bouncing);
return root;
}
////////////////////////////////////////////////////////////
//
// This routine is repeatedly called from the Inventor
// main loop.
void animate(void *data, SoSensor *) {
// Retrieve the sphere and its transform from the scene graph.
SoSeparator *root = (SoSeparator *)data;
SoUnitCube *unitCube = (SoUnitCube *)(root->getChild(0));
SoBouncingSpheres *bouncing = (SoBouncingSpheres *)(root->getChild(1));
bouncing->moveSpheres(unitCube);
}
// checkArgs() checks the command line arguments and assigns all variables
// not listed on command to zero.
int checkArgs(int myargc, char **myargv) {
int i;
for (i = 1; i < myargc; i += 2) {
if (i + 1 == myargc) return 0;
if (!strcmp(myargv[i], "-spheres"))
sphereNum = atoi(myargv[i + 1]);
else if (!strcmp(myargv[i], "-timer"))
timer = atof(myargv[i + 1]);
else if (!strcmp(myargv[i], "-h"))
return 0;
else if (!strcmp(myargv[i], "-help"))
return 0;
else
return 0;
}
return 1;
}
void printUsage() {
cout << "Usage - bounce" << endl;
cout << " Description: Creates an interactive 3D examiner viewer with\n"
<< " <spheres> of spheres within a unit cube bouncing\n"
<< " around within the cube. When two or more spheres\n"
<< " intersect their colors are changed. \n"
<< " The scene is updated every <timer> seconds."
<< endl;
cout << " -<spheres>: Maximum number of spheres to be displayed within\n"
<< " the unit cube\n"
<< " -<timer>: Determines number of frames per second.\n"
<< endl;
}
////////////////////////////////////////////////////////////
//
// The main program gets a window from X,
// puts an interactive 3D examinerViewer in it,
// attaches the scene graph to the viewer,
// renders the scene graph,
// and hands control over to the Inventor main loop.
void main(int argc, char **argv) {
if (!checkArgs(argc, argv)){
printUsage();
exit(1);
}
// Initialize Inventor and Xt
Widget myWindow = SoXt::init(argv[0]);
if (myWindow == NULL) exit(1);
srand48(getpid());
// Create a scene graph
SoSeparator *root = makeScene(sphereNum);
SoTimerSensor *sensor = new SoTimerSensor(animate, root);
sensor->setInterval(SbTime(timer)); // 50 frames per second
sensor->schedule();
SoXtExaminerViewer *myViewer = new SoXtExaminerViewer(myWindow);
myViewer->setSceneGraph(root);
myViewer->setTitle("Sphere in Cube");
myViewer->show();
SoXt::show(myWindow);
SoXt::mainLoop();
}