bunnygut.C
Go to the documentation of this file.
1 /*
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.
5  *
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.
11  */
12 
13 #include <windows.h>
14 #include <stdio.h>
15 #include <math.h>
16 #include <stdlib.h>
17 #include <assert.h>
18 #include <string.h>
19 #include <GL/gl.h>
20 #pragma warning(disable : 4244)
21 
22 #include "vector.h"
23 #include "font.h"
24 #include "progmesh.h"
25 #include "rabdata.h"
26 
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
37 
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
44 // module first.
45 
46 // Map()
47 //
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) {
76  if(mx<=0) return 0;
77  while(a>=mx) {
78  a=collapse_map[a];
79  }
80  return a;
81 }
82 
83 void DrawModelTriangles() {
84  assert(collapse_map.num);
85  renderpolycount=0;
86  int i=0;
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;
95  renderpolycount++;
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));
101  Vector v0,v1,v2;
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);
105  glBegin(GL_POLYGON);
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));
111  }
112  glVertex3fv(v0);
113  glVertex3fv(v1);
114  glVertex3fv(v2);
115  glEnd();
116  }
117 }
118 
119 
120 void PermuteVertices(List<int> &permutation) {
121  // rearrange the vertex list
122  List<Vector> temp_list;
123  int i;
124  assert(permutation.num==vert.num);
125  for(i=0;i<vert.num;i++) {
126  temp_list.Add(vert[i]);
127  }
128  for(i=0;i<vert.num;i++) {
129  vert[permutation[i]]=temp_list[i];
130  }
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]];
135  }
136  }
137 }
138 
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
142  int i;
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]));
146  }
147  for(i=0;i<RABBIT_TRIANGLE_NUM;i++) {
148  tridata td;
149  td.v[0]=rabbit_triangles[i][0];
150  td.v[1]=rabbit_triangles[i][1];
151  td.v[2]=rabbit_triangles[i][2];
152  tri.Add(td);
153  }
154  render_num=vert.num; // by default lets use all the model to render
155 }
156 
157 
158 void InitModel() {
159  List<int> permutation;
160  GetRabbitData();
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;
167 }
168 
169 void StatusDraw() {
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 );
176  glPushMatrix();
177  glLoadIdentity();
178  glOrtho(-0.15,15,-0.1,1.1,-0.1,100);
179  glMatrixMode( GL_MODELVIEW );
180 
181  glPushMatrix();
182  glLoadIdentity();
183  glBegin(GL_POLYGON);
184  glColor3f(1,0,0);
185  glVertex2f(0,0);
186  glVertex2f(1,0);
187  glVertex2f(1,a);
188  glVertex2f(0,a);
189  glEnd();
190  glBegin(GL_POLYGON);
191  glColor3f(1,0,0);
192  glVertex2f(0,a);
193  glVertex2f(morph,a);
194  glVertex2f(morph,b);
195  glVertex2f(0,b);
196  glEnd();
197  glBegin(GL_POLYGON);
198  glColor3f(0,0,1);
199  glVertex2f(morph,a);
200  glVertex2f(1,a);
201  glVertex2f(1,b);
202  glVertex2f(morph,b);
203  glEnd();
204  glBegin(GL_POLYGON);
205  glColor3f(0,0,1);
206  glVertex2f(0,b);
207  glVertex2f(1,b);
208  glVertex2f(1,1);
209  glVertex2f(0,1);
210  glEnd();
211  glPopMatrix();
212  glMatrixMode( GL_PROJECTION );
213  glPopMatrix();
214  glMatrixMode( GL_MODELVIEW );
215 }
216 
217 /*
218  * The following is just a quick hack to animate
219  * the object through various polygon reduced versions.
220  */
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"
227 } keys[]={
228  {0 ,1 ,0 ,1, 0},
229  {2 ,1 ,-1,1, 0},
230  {10,0 ,1 ,1, 0},
231  {18,1 ,0 ,1, 0},
232  {20,1 ,0 ,1,-1},
233  {24,0.5 ,0 ,1, 0},
234  {26,0.5 ,0 ,1,-1},
235  {30,0.25,0 ,1, 0},
236  {32,0.25,0 ,1,-1},
237  {36,0.125,0,1, 0},
238  {38,0.25,0 ,0, 1},
239  {42,0.5 ,0 ,0, 1},
240  {46,1 ,0 ,0, 1},
241  {50,1 ,0 ,1, 0},
242 };
243 void AnimateParameters() {
244  static float time=0; // global time - used for animation
245  time+=DeltaT;
246  if(time>=50) time=0; // repeat cycle every so many seconds
247  int k=0;
248  while(time>keys[k+1].t) {
249  k++;
250  }
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;
257 }
258 
259 void RenderModel() {
260  AnimateParameters();
261 
262  glEnable(GL_LIGHTING);
263  glEnable(GL_LIGHT0);
264  glColor3f(1,1,1);
265  glPushMatrix();
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();
272  StatusDraw();
273  glPopMatrix();
274 
275  char buf[256];
276  sprintf(buf,"Polys: %d Vertices: %d ",renderpolycount,render_num);
277  if(morph<1.0) {
278  sprintf(buf+strlen(buf),"<-> %d morph: %4.2f ",
279  (int)(lodbase *render_num),morph);
280  }
281  PostString(buf,0,-2,5);
282 }
label k
Boltzmann constant.
quaternion normalize(const quaternion &q)
Return the normalized (unit) quaternion of the given quaternion.
Definition: quaternionI.H:609
labelList f(nPoints)
label n