2 * Polygon Reduction Demo by Stan Melax (c) 1998
3 * Permission to use any of this code wherever you want is granted..
4 * Although, please do acknowledge authorship if appropriate.
6 * This module initializes the bunny model data and calls
7 * the polygon reduction routine. At each frame the RenderModel()
8 * routine is called to draw the model. This module also
9 * animates the parameters (such as number of vertices to
10 * use) to show the model at various levels of detail.
20 #pragma warning(disable : 4244)
27 extern float DeltaT; // change in time since last frame
28 int render_num; // number of vertices to draw with
29 float lodbase=0.5f; // the fraction of vertices used to morph toward
30 float morph=1.0f; // where to render between 2 levels of detail
31 List<Vector> vert; // global list of vertices
32 List<tridata> tri; // global list of triangles
33 List<int> collapse_map; // to which neighbor each vertex collapses
34 int renderpolycount=0; // polygons rendered in the current frame
35 Vector model_position; // position of bunny
36 Quaternion model_orientation; // orientation of bunny
38 // Note that the use of the Map() function and the collapse_map
39 // list isn't part of the polygon reduction algorithm.
40 // We just set up this system here in this module
41 // so that we could retrieve the model at any desired vertex count.
42 // Therefore if this part of the program confuses you, then
43 // dont worry about it. It might help to look over the progmesh.cpp
48 // When the model is rendered using a maximum of mx vertices
49 // then it is vertices 0 through mx-1 that are used.
50 // We are able to do this because the vertex list
51 // gets sorted according to the collapse order.
52 // The Map() routine takes a vertex number 'a' and the
53 // maximum number of vertices 'mx' and returns the
54 // appropriate vertex in the range 0 to mx-1.
55 // When 'a' is greater than 'mx' the Map() routine
56 // follows the chain of edge collapses until a vertex
57 // within the limit is reached.
58 // An example to make this clear: assume there is
59 // a triangle with vertices 1, 3 and 12. But when
60 // rendering the model we limit ourselves to 10 vertices.
61 // In that case we find out how vertex 12 was removed
62 // by the polygon reduction algorithm. i.e. which
63 // edge was collapsed. Lets say that vertex 12 was collapsed
64 // to vertex number 7. This number would have been stored
65 // in the collapse_map array (i.e. collapse_map[12]==7).
66 // Since vertex 7 is in range (less than max of 10) we
67 // will want to render the triangle 1,3,7.
68 // Pretend now that we want to limit ourselves to 5 vertices.
69 // and vertex 7 was collapsed to vertex 3
70 // (i.e. collapse_map[7]==3). Then triangle 1,3,12 would now be
71 // triangle 1,3,3. i.e. this polygon was removed by the
72 // progressive mesh polygon reduction algorithm by the time
73 // it had gotten down to 5 vertices.
74 // No need to draw a one dimensional polygon. :-)
75 int Map(int a,int mx) {
83 void DrawModelTriangles() {
84 assert(collapse_map.num);
87 for(i=0;i<tri.num;i++) {
88 int p0= Map(tri[i].v[0],render_num);
89 int p1= Map(tri[i].v[1],render_num);
90 int p2= Map(tri[i].v[2],render_num);
91 // note: serious optimization opportunity here,
92 // by sorting the triangles the following "continue"
93 // could have been made into a "break" statement.
94 if(p0==p1 || p1==p2 || p2==p0) continue;
96 // if we are not currenly morphing between 2 levels of detail
97 // (i.e. if morph=1.0) then q0,q1, and q2 are not necessary.
98 int q0= Map(p0,(int)(render_num*lodbase));
99 int q1= Map(p1,(int)(render_num*lodbase));
100 int q2= Map(p2,(int)(render_num*lodbase));
102 v0 = vert[p0]*morph + vert[q0]*(1-morph);
103 v1 = vert[p1]*morph + vert[q1]*(1-morph);
104 v2 = vert[p2]*morph + vert[q2]*(1-morph);
106 // the purpose of the demo is to show polygons
107 // therefore just use 1 face normal (flat shading)
108 Vector nrml = (v1-v0) * (v2-v1); // cross product
109 if(0<magnitude(nrml)) {
110 glNormal3fv(normalize(nrml));
120 void PermuteVertices(List<int> &permutation) {
121 // rearrange the vertex list
122 List<Vector> temp_list;
124 assert(permutation.num==vert.num);
125 for(i=0;i<vert.num;i++) {
126 temp_list.Add(vert[i]);
128 for(i=0;i<vert.num;i++) {
129 vert[permutation[i]]=temp_list[i];
131 // update the changes in the entries in the triangle list
132 for(i=0;i<tri.num;i++) {
133 for(int j=0;j<3;j++) {
134 tri[i].v[j] = permutation[tri[i].v[j]];
139 void GetRabbitData(){
140 // Copy the geometry from the arrays of data in rabdata.cpp into
141 // the vert and tri lists which we send to the reduction routine
143 for(i=0;i<RABBIT_VERTEX_NUM;i++) {
144 float *vp=rabbit_vertices[i];
145 vert.Add(Vector(vp[0],vp[1],vp[2]));
147 for(i=0;i<RABBIT_TRIANGLE_NUM;i++) {
149 td.v[0]=rabbit_triangles[i][0];
150 td.v[1]=rabbit_triangles[i][1];
151 td.v[2]=rabbit_triangles[i][2];
154 render_num=vert.num; // by default lets use all the model to render
159 List<int> permutation;
161 ProgressiveMesh(vert,tri,collapse_map,permutation);
162 PermuteVertices(permutation);
163 model_position = Vector(0,0,-3);
164 Quaternion yaw(Vector(0,1,0),-3.14f/4); // 45 degrees
165 Quaternion pitch(Vector(1,0,0),3.14f/12); // 15 degrees
166 model_orientation = pitch*yaw;
170 // Draw a slider type widget looking thing
171 // to show portion of vertices being used
172 float b = (float)render_num/(float)vert.num;
173 float a = b*(lodbase );
174 glDisable(GL_LIGHTING);
175 glMatrixMode( GL_PROJECTION );
178 glOrtho(-0.15,15,-0.1,1.1,-0.1,100);
179 glMatrixMode( GL_MODELVIEW );
212 glMatrixMode( GL_PROJECTION );
214 glMatrixMode( GL_MODELVIEW );
218 * The following is just a quick hack to animate
219 * the object through various polygon reduced versions.
221 struct keyframethings {
222 float t; // timestamp
223 float n; // portion of vertices used to start
224 float dn; // rate of change in "n"
225 float m; // morph value
226 float dm; // rate of change in "m"
243 void AnimateParameters() {
244 static float time=0; // global time - used for animation
246 if(time>=50) time=0; // repeat cycle every so many seconds
248 while(time>keys[k+1].t) {
251 float interp = (time-keys[k].t)/(keys[k+1].t-keys[k].t);
252 render_num = vert.num*(keys[k].n + interp*keys[k].dn);
253 morph = keys[k].m + interp*keys[k].dm;
254 morph = (morph>1.0f) ? 1.0f : morph; // clamp value
255 if(render_num>vert.num) render_num=vert.num;
256 if(render_num<0 ) render_num=0;
262 glEnable(GL_LIGHTING);
266 glTranslatef(model_position.x,model_position.y,model_position.z);
267 // Rotate by quaternion: model_orientation
268 Vector axis=model_orientation.axis();
269 float angle=model_orientation.angle()*180.0f/3.14f;
270 glRotatef(angle,axis.x,axis.y,axis.z);
271 DrawModelTriangles();
276 sprintf(buf,"Polys: %d Vertices: %d ",renderpolycount,render_num);
278 sprintf(buf+strlen(buf),"<-> %d morph: %4.2f ",
279 (int)(lodbase *render_num),morph);
281 PostString(buf,0,-2,5);