Handout 3 CS 116A Fall 2003

//SAMPLE Mesh code has NOT been compiled or tested. 

//===========MESH.H======================

#include "vectormatrix.h"

#include <vector>

using namespace std

 

//################ Face ##################

class cFace

{

  public:

        vector<int> _vertexid; // the list of vertex indices

        vector<int> _normalid; // the list of normal indices

        cFace(){} // constructor

        ~cFace(){}// destructor

};

//###################### Mesh #######################

class cMesh

{

   private:

        vector<cVector> _vertex;       // array of 3D vertices

        vector<cVector> _normal;    // array of normals

        vector<cFace> _face;      // array of face data

   public:

        cMesh();               // constructor

        ~cMesh();          // destructor

        int facecount(){return _face.size();}

        int vertcount(int faceindex){return _face[faceindex].size();}

        cVector vertex(int faceindex, int i)

               {return _vertex[_face[faceindex]._vertexid[i]];|

        cVector normal(int faceindex, int i)

               {return _normal[_face[faceindex]._normalid[i]];|

        void draw(int drawflags);

};     

//===========MESH.CPP======================

//Simple method.

void cMesh:: draw(int drawflags)

{ 

        static int displayid = 0;

        if (!displayid) //Only do this the first time

        {

                displayid = glGenLists(1);

                glNewList(displayid, GL_COMPILE);

               for(int j = 0; j < facecount(); j++) // draw each face

               {

                       glBegin(GL_POLYGON);

                        for(int i = 0; i < face[j].vertcount(); i++) // for each one..

                       {

                               glNormal3d(normal(j, i).x(), normal(j, i).y(),

                                       normal(j, i).z());

                               glVertex3d(vertex(j, i).x(), vertex(j, i).y(),

                                       vertex(j, i).z());

                       }

                       glEnd();

               }

                glEndList();

        } //End of the part you onlythe first time.

        glCallList(displaylistid); //Always do this.

}

 

//Faster, more complicated Vector Array method

void cMesh:: draw(int drawflags)

{            

/* Don't have time to write it.  Uses calls to

        glEnableClientState(GL_VERTEX_ARRAY);

        allocate Real *vertices = new Real[...]

        fill with lines like this: vertices[3+3*i] = ppolygon->getVertex(i).x();

        allocate GLushort *quadindices = new GLushort[4*size];

        fill with lines like this: quadindices[4*i] = 1 + i;

        Use with lines like

        ::glBegin(GL_QUADS);

                ::glArrayElement(quadindices[quadindex++]);

                ::glArrayElement(quadindices[quadindex++]);

                ::glArrayElement(quadindices[quadindex++]);

                ::glArrayElement(quadindices[quadindex++]);

        ::glEnd();

       

        You can do something similar for the normals.

*/

}

==================================ASSEMBLY.H CODE from MOLECULES1, has been tested.

class cAssembly

{

public:

        static cAssembly* cAssembly::makeRandomAssembly(int maxdepth = MAXDEPTH);

               /* makeRandomAssembly is a static (think "global") method that creates

               random assembliess. Methods of this kind are called factory methods,

               in that they create new objects for you.  The meaning of the maxdepth

                argument is that we guarantee not to return a nested cAssemblyComposite

               with more than maxdepth levels.  You use this method in your main program

               by picking some value of MAXDEPTH maybe between 2 and 5 and writing a

               line like

                cAssembly *pnew = cAssembly::makeRandomAssembly(MAXDEPTH);              */

protected:

//Geometry

        Real _actualradius; /* Make this be the actual radius of the most

               distant point form the origin. */

//Transformation

        cVector _scale;

        Real _spinangle;

        cVector _spinaxis;

        cVector _position;

//Motion

        Real _spinrate;

public:

//Construtor, Destructor, Copy

        cAssembly();

//Mutators

        //Randomizer

        virtual void randomize(); //Randomizes spinaxis and spinangle

//etcetera..

//Essential methods

        virtual void animate(Real dt);

        virtual void draw(int drawflags = 0){} //If drawflags is 1, we draw wireframe.

};

 

class cAssemblyComposite : public cAssembly

{

private:

        vector <cAssembly*> _pchild;

public:

//Constructor, etc.

        cAssemblyComposite(){} //Default constructor makes empty _pchild array

//Special methods

        void add(cAssembly *pa);

        void addRandomChildren(int maxdepth = cAssembly::MAXDEPTH);

//Overloads

        virtual void fixActualRadius(); /* Try to adjust

                _actualradius to include all the pieces. */

        virtual int depth(); //Return 1 + max depth of children.

        virtual void animate(Real dt);

        virtual void draw(int drawflags = 0);

};

 

class cPolyhedron : public cAssembly

{ //as before

}

====================================ASSEMBLY.CPP

//========Good Stuff for cAssembly====================

void cAssembly::randomize()

{

        _spinaxis = cVector::randomUnitVector();

        _spinrate = cRandomizer::pinst()->randomReal(3.0*(2*PI), 20.0*(2*PI));

}

 

cAssembly* cAssembly::makeRandomAssembly(int depth)

{

        cAssembly *pnewassembly;

        if (depth >= 1)

        {

                pnewassembly = new cAssemblyComposite();

                ((cAssemblyComposite*)pnewassembly)-> //Have to cast so I can use method

                       addRandomChildren(depth); //Allow  maxdepth more levels.

        }

        else

                pnewassembly = new cPolyhedron();

        pnewassembly->randomize(); /* Randomizes the spinaxis and spinrate, also,

               if it's a polyhedron, randomizes the color and shape. */

        pnewassembly->fixActualRadius();

        return pnewassembly;

}      

 

void cAssembly::animate(Real dt)

{

        _position += dt*_velocity;

        _spinangle += dt*_spinrate;

}

//===========Good cAssemblyComposite Stuff===============

 

void cAssemblyComposite::addRandomChildren(int maxdepth)

{

        cAssembly *pnew;

        int childcount = cRandomizer::pinst()->random(2, 3);

        for (int i=0; i<childcount; i++)

        {

               pnew = cAssembly::makeRandomAssembly(maxdepth - 1);

#ifdef PLANETARY

               if (i>0)

        // I'll move the later guys out to be on periphery of the first guy.

               {

                       cAssembly* pboss = _pchild[0];

                       cVector displacedir = cVector::randomUnitVector();

                       Real howfar = cRandomizer::pinst()->randomReal(0.5, 1.3);

                       pnew->setPosition(howfar * pboss->radius() * displacedir);

#ifdef SMALLCHILDREN

                       // I'll scale the later guys to be smaller.

                       Real shrinkfactor = cRandomizer::pinst()->randomReal(0.5, 0.8);

                       pnew->multiplyScale(shrinkfactor);

#endif //SMALLCHILDREN

               }

#endif //PLANETARY

                add(pnew);

        }

}

 

void cAssemblyComposite::animate(Real dt)

{

        cAssembly::animate(dt);

        for (int i=0; i<_pchild.size(); i++)

                _pchild[i]->animate(dt);

}

 

 

int cAssemblyComposite::depth()

{

        int maxdepth = 0;

        for (int i=0; i<_pchild.size(); i++)

               if (maxdepth < _pchild[i]->depth())

                       maxdepth = _pchild[i]->depth();

        return maxdepth + 1;

}

//===============new drawFlurry in DONUTS.CPP

void drawFlurry() //Uses the global dt param.

{

        while (assemblyarray.size() < maxassemblycount)

        {

                cAssembly *pnewpoly;

                pnewpoly = cAssembly::makeRandomAssembly(maxassemblycomplexity);

                pnewpoly->setPosition(cVector(cRandomizer::pinst()->

                       randomReal(-0.5* xradius, 0.5 * xradius),

                       cRandomizer::pinst()->randomReal(-0.5* yradius, 0.5* yradius),

                       cRandomizer::pinst()->randomReal(0.0, zradius)));

                assemblyarray.push_back(pnewpoly);

                //push_back adds the pointer to the array.

        }

        for (int i=0; i<assemblyarray.size(); i++)

        {

                assemblyarray[i]->animate(dt);

               if (fallflag)

                       assemblyarray[i]->translate(-FALLSPEED * dt * cVector::ZAXIS);

                assemblyarray[i]->draw(wireflag | showconnectorflag | showradiusflag);

               if (assemblyarray[i]->position().z() <

                       -zradius + assemblyarray[i]->radius())

               {

                       delete assemblyarray[i]; //Delete it before removing from the deque.

                       assemblyarray.erase(assemblyarray.begin()+i); //Erase when you hit bottom.

               }

        }

} 

==========MOLECULE 1 CONTROLS===========

' ': Space singlesteps if animation flag is turned off.

        'a': Toggles the running animation.

'b': Toggles wireframe balls around the assemblies.  The colors of

        the balls indicate the "depth" of the assmbly, that is, how many

        levels of subassemblies it has.

'c': Toggles wireframe lines connecting the first member of an assembly

        to the other.  Color = depth as in 'b'.

'd': Decrements maximum depth or complexity of assemblies. The minumum

        depth of 0 is a polyhedron.

D': Increments depth.

'f': Toggles the falling-towards-the-viwer motion.

'n': Decrements the number of assemblies on screen.

'N': Increments the number of assemblies on screen.

'q': Quit

'r': Randomize the assemblies on screen.

'w': Toggle a wireframe view.

'z': Zoom in.

'Z': Zoom out.

'2': Use a 2d orthogonal projection.

'3': Use a 3d perspective projection.