/* * Copyright (C) 1996, Christopher John Kline * Electronic mail: ckline@acm.org * * This software may be freely copied, modified, and redistributed * for academic purposes and by not-for-profit organizations, provided that * this copyright notice is preserved on all copies, and that the source * code is included or notice is given informing the end-user that the source * code is publicly available under the terms described here. * * Persons or organizations wishing to use this code or any modified version * of this code in a commercial and/or for-profit manner must contact the * author via electronic mail (preferred) or other method to arrange the terms * of usage. These terms may be as simple as giving the author visible credit * in the final product. * * There is no warranty or other guarantee of fitness for this software, * it is provided solely "as is". Bug reports or fixes may be sent * to the author, who may or may not act on them as he desires. * * If you use this software the author politely requests that you inform him via * electronic mail. * */ #include "Boid.h" #include "Obstacle.h" #include "ivBoid.h" #include #include #include #include #include #include #include SoSeparator *loadModel(char *name); #define NUMBOIDS 40 // Number of boids. #define UPDATEFPS 25 // Update rate of the boids (internally) in frames-per-second. /* --- This is a good value for an Indy --- */ #define GRAPHICSFPS 4 // Update rate of the graphics in frames-per-second. /* --- This is a good value if you have a Reality Engine, or if you are running the program remotely and displaying on an Indy. #define GRAPHICSFPS 12 // Update rate of the graphics in frames-per-second. --- */ //#define SPHERE // Use the sphere as bounding object? If this is // not defined, a rectangle will be used. double RAD = 25; // RAD of the bounding sphere of the world. //---------------- Globals --------------------------- SoSeparator *IVBoid::boidModel = NULL; IVBoid **myBoid; // array of IVBoid pointers Widget myWindow; SoXtExaminerViewer *myViewer; SoSeparator *root; //------------------Support Routines------------------------ static void animateBoids(void *, SoSensor *) { for (int i = 0; i < NUMBOIDS; i++) { myBoid[i]->updateGraphics(); } } static void updateBoids(void *, SoSensor *) { static double elapsedTime = 0; for (int i = 0; i < NUMBOIDS; i++) { myBoid[i]->update(elapsedTime); } // increment elapsed time elapsedTime += 1.0/UPDATEFPS; } void setUpGraphics(void) { myWindow = SoXt::init("Boids"); if (myWindow == NULL) { cerr << "myWindow is null. bye!\n"; exit(1); } root = new SoSeparator; root->ref(); SoEnvironment *Env = new SoEnvironment; Env->ambientIntensity.setValue(.5); root->addChild(Env); // Set up viewer: myViewer = new SoXtExaminerViewer(myWindow); //myViewer->setDrawStyle(SoXtViewer::STILL, SoXtViewer::VIEW_LINE); myViewer->setSize(SbVec2s(900, 850)); myViewer->setTitle("Boids"); myViewer->setTransparencyType(SoGLRenderAction::DELAYED_ADD); myViewer->setSceneGraph(root); myViewer->setHeadlight(TRUE); myViewer->show(); SoXt::show(myWindow); } void makeObstacles(void) { // Make a subgraph for the boundary obstacle SoSeparator *boundary = new SoSeparator; SoMaterial *m = new SoMaterial; m->transparency.setValue(.9); m->ambientColor.setValue(1, 1, 1); boundary->addChild(m); // Make a subgraph for the other obstacles SoSeparator *r = new SoSeparator; r->addChild(boundary); SoMaterial *m2 = new SoMaterial; m2->ambientColor.setValue(0, 0, 1); m2->diffuseColor.setValue(0, 0, 1); m2->specularColor.setValue(.5, .5, .5); m2->shininess.setValue(0.2); r->addChild(m2); root->addChild(r); #ifdef SPHERE // make bounding sphere IVSphere *bs; bs = new IVSphere(boundary, &(myBoid[0]->boid->obstacles), Vector(0,0,0), RAD, SoDrawStyle::LINES); #else // make bounding box IVBox *b; b = new IVBox(boundary, &(myBoid[0]->boid->obstacles), Vector(RAD, RAD*0.75, 1.5*RAD), Vector(-RAD, -RAD*0.75, -1.5*RAD), SoDrawStyle::LINES); #endif IVSphere *s2; s2 = new IVSphere(r, &(myBoid[0]->boid->obstacles), Vector(RAD/3, RAD/5, -RAD/3), RAD/6); IVSphere *s3; s3 = new IVSphere(r, &(myBoid[0]->boid->obstacles), Vector(-RAD/3, -RAD/5, RAD/3), RAD/6); IVBox *b2; b2 = new IVBox(r, &(myBoid[0]->boid->obstacles), Vector((RAD*0.25), -(RAD*0.75), -(0.5)), Vector((RAD*0.75), -(RAD*0.25), (0.5))); IVBox *b3; b3 = new IVBox(r, &(myBoid[0]->boid->obstacles), Vector(-(RAD*0.25), (RAD*0.75), -(0.5)), Vector(-(RAD*0.75), (RAD*0.25), (0.5))); IVBox *b4; b4 = new IVBox(r, &(myBoid[0]->boid->obstacles), Vector(-(0.5), -(RAD*0.25), (RAD*0.25)), Vector((0.5), (RAD*0.25), (RAD*0.75))); IVBox *b5; b5 = new IVBox(r, &(myBoid[0]->boid->obstacles), Vector(-(0.5), -(RAD*0.25), -(RAD*0.25)), Vector((0.5), (RAD*0.25), -(RAD*0.75))); } void setupUpdateCallbacks() { SoTimerSensor *updateTimer = new SoTimerSensor(updateBoids, NULL); updateTimer->setInterval(1.0/UPDATEFPS); updateTimer->schedule(); SoTimerSensor *graphicsTimer = new SoTimerSensor(animateBoids, NULL); graphicsTimer->setInterval(1.0/GRAPHICSFPS); graphicsTimer->schedule(); } bool makeBoids(void) { Vector p; Vector attitude; // roll, pitch, yaw Vector v; // velocity vector Vector d(1, .2, .75); // dimensions of boid (RAD, height, length) double mv = 25; myBoid = new IVBoid*[NUMBOIDS]; for (int i=0; iboid->maxAcceleration = 0.65; myBoid[i]->boid->cruiseDistance = 0.75; myBoid[i]->boid->maxVelocity = mv; } return TRUE; } //----------------Simulation Routines----------------------- void initSimulation() { setUpGraphics(); cerr << "Graphics set up\n"; if (makeBoids() == FALSE) cerr << "\nmakeBoids() returned an error\n"; cerr << "Made boids\n"; makeObstacles(); cerr << "Obstacles set up\n"; // Set up an asynchronous callback to update boids. setupUpdateCallbacks(); } int main (int argc, char **argv) { initSimulation(); myViewer->viewAll(); SoXt::mainLoop(); // This will never be reached, but it stops compiler warnings. return 0; }