/* * Polygon Reduction Demo by Stan Melax (c) 1998 * Permission to use any of this code wherever you want is granted.. * Although, please do acknowledge authorship if appropriate. * * This module initializes the bunny model data and calls * the polygon reduction routine. At each frame the RenderModel() * routine is called to draw the model. This module also * animates the parameters (such as number of vertices to * use) to show the model at various levels of detail. */ #include #include #include #include #include #include #include #pragma warning(disable : 4244) #include "vector.h" #include "font.h" #include "progmesh.h" #include "rabdata.h" extern float DeltaT; // change in time since last frame int render_num; // number of vertices to draw with float lodbase=0.5f; // the fraction of vertices used to morph toward float morph=1.0f; // where to render between 2 levels of detail List vert; // global list of vertices List tri; // global list of triangles List collapse_map; // to which neighbor each vertex collapses int renderpolycount=0; // polygons rendered in the current frame Vector model_position; // position of bunny Quaternion model_orientation; // orientation of bunny // Note that the use of the Map() function and the collapse_map // list isn't part of the polygon reduction algorithm. // We just set up this system here in this module // so that we could retrieve the model at any desired vertex count. // Therefore if this part of the program confuses you, then // dont worry about it. It might help to look over the progmesh.cpp // module first. // Map() // // When the model is rendered using a maximum of mx vertices // then it is vertices 0 through mx-1 that are used. // We are able to do this because the vertex list // gets sorted according to the collapse order. // The Map() routine takes a vertex number 'a' and the // maximum number of vertices 'mx' and returns the // appropriate vertex in the range 0 to mx-1. // When 'a' is greater than 'mx' the Map() routine // follows the chain of edge collapses until a vertex // within the limit is reached. // An example to make this clear: assume there is // a triangle with vertices 1, 3 and 12. But when // rendering the model we limit ourselves to 10 vertices. // In that case we find out how vertex 12 was removed // by the polygon reduction algorithm. i.e. which // edge was collapsed. Lets say that vertex 12 was collapsed // to vertex number 7. This number would have been stored // in the collapse_map array (i.e. collapse_map[12]==7). // Since vertex 7 is in range (less than max of 10) we // will want to render the triangle 1,3,7. // Pretend now that we want to limit ourselves to 5 vertices. // and vertex 7 was collapsed to vertex 3 // (i.e. collapse_map[7]==3). Then triangle 1,3,12 would now be // triangle 1,3,3. i.e. this polygon was removed by the // progressive mesh polygon reduction algorithm by the time // it had gotten down to 5 vertices. // No need to draw a one dimensional polygon. :-) int Map(int a,int mx) { if(mx<=0) return 0; while(a>=mx) { a=collapse_map[a]; } return a; } void DrawModelTriangles() { assert(collapse_map.num); renderpolycount=0; int i=0; for(i=0;i &permutation) { // rearrange the vertex list List temp_list; int i; assert(permutation.num==vert.num); for(i=0;i permutation; GetRabbitData(); ProgressiveMesh(vert,tri,collapse_map,permutation); PermuteVertices(permutation); model_position = Vector(0,0,-3); Quaternion yaw(Vector(0,1,0),-3.14f/4); // 45 degrees Quaternion pitch(Vector(1,0,0),3.14f/12); // 15 degrees model_orientation = pitch*yaw; } void StatusDraw() { // Draw a slider type widget looking thing // to show portion of vertices being used float b = (float)render_num/(float)vert.num; float a = b*(lodbase ); glDisable(GL_LIGHTING); glMatrixMode( GL_PROJECTION ); glPushMatrix(); glLoadIdentity(); glOrtho(-0.15,15,-0.1,1.1,-0.1,100); glMatrixMode( GL_MODELVIEW ); glPushMatrix(); glLoadIdentity(); glBegin(GL_POLYGON); glColor3f(1,0,0); glVertex2f(0,0); glVertex2f(1,0); glVertex2f(1,a); glVertex2f(0,a); glEnd(); glBegin(GL_POLYGON); glColor3f(1,0,0); glVertex2f(0,a); glVertex2f(morph,a); glVertex2f(morph,b); glVertex2f(0,b); glEnd(); glBegin(GL_POLYGON); glColor3f(0,0,1); glVertex2f(morph,a); glVertex2f(1,a); glVertex2f(1,b); glVertex2f(morph,b); glEnd(); glBegin(GL_POLYGON); glColor3f(0,0,1); glVertex2f(0,b); glVertex2f(1,b); glVertex2f(1,1); glVertex2f(0,1); glEnd(); glPopMatrix(); glMatrixMode( GL_PROJECTION ); glPopMatrix(); glMatrixMode( GL_MODELVIEW ); } /* * The following is just a quick hack to animate * the object through various polygon reduced versions. */ struct keyframethings { float t; // timestamp float n; // portion of vertices used to start float dn; // rate of change in "n" float m; // morph value float dm; // rate of change in "m" } keys[]={ {0 ,1 ,0 ,1, 0}, {2 ,1 ,-1,1, 0}, {10,0 ,1 ,1, 0}, {18,1 ,0 ,1, 0}, {20,1 ,0 ,1,-1}, {24,0.5 ,0 ,1, 0}, {26,0.5 ,0 ,1,-1}, {30,0.25,0 ,1, 0}, {32,0.25,0 ,1,-1}, {36,0.125,0,1, 0}, {38,0.25,0 ,0, 1}, {42,0.5 ,0 ,0, 1}, {46,1 ,0 ,0, 1}, {50,1 ,0 ,1, 0}, }; void AnimateParameters() { static float time=0; // global time - used for animation time+=DeltaT; if(time>=50) time=0; // repeat cycle every so many seconds int k=0; while(time>keys[k+1].t) { k++; } float interp = (time-keys[k].t)/(keys[k+1].t-keys[k].t); render_num = vert.num*(keys[k].n + interp*keys[k].dn); morph = keys[k].m + interp*keys[k].dm; morph = (morph>1.0f) ? 1.0f : morph; // clamp value if(render_num>vert.num) render_num=vert.num; if(render_num<0 ) render_num=0; } void RenderModel() { AnimateParameters(); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glColor3f(1,1,1); glPushMatrix(); glTranslatef(model_position.x,model_position.y,model_position.z); // Rotate by quaternion: model_orientation Vector axis=model_orientation.axis(); float angle=model_orientation.angle()*180.0f/3.14f; glRotatef(angle,axis.x,axis.y,axis.z); DrawModelTriangles(); StatusDraw(); glPopMatrix(); char buf[256]; sprintf(buf,"Polys: %d Vertices: %d ",renderpolycount,render_num); if(morph<1.0) { sprintf(buf+strlen(buf),"<-> %d morph: %4.2f ", (int)(lodbase *render_num),morph); } PostString(buf,0,-2,5); }