initial commit for version 1.6.x patch release
[OpenFOAM-1.6.x.git] / applications / utilities / surface / surfaceCoarsen / bunnylod / bunnygut.C
bloba5e3d31268f2d822380c2e3b491240a3fc29c475
1 /*\r
2  *   Polygon Reduction Demo by Stan Melax (c) 1998\r
3  *  Permission to use any of this code wherever you want is granted..\r
4  *  Although, please do acknowledge authorship if appropriate.\r
5  *\r
6  *  This module initializes the bunny model data and calls\r
7  *  the polygon reduction routine.  At each frame the RenderModel()\r
8  *  routine is called to draw the model.  This module also\r
9  *  animates the parameters (such as number of vertices to\r
10  *  use) to show the model at various levels of detail.\r
11  */\r
13 #include <windows.h>\r
14 #include <stdio.h>  \r
15 #include <math.h>\r
16 #include <stdlib.h>\r
17 #include <assert.h>\r
18 #include <string.h>\r
19 #include <GL/gl.h>\r
20 #pragma warning(disable : 4244)\r
22 #include "vector.h"\r
23 #include "font.h"\r
24 #include "progmesh.h"\r
25 #include "rabdata.h"\r
27 extern float DeltaT;  // change in time since last frame\r
28 int   render_num;   // number of vertices to draw with\r
29 float lodbase=0.5f; // the fraction of vertices used to morph toward\r
30 float morph=1.0f;   // where to render between 2 levels of detail\r
31 List<Vector> vert;       // global list of vertices\r
32 List<tridata> tri;       // global list of triangles\r
33 List<int> collapse_map;  // to which neighbor each vertex collapses\r
34 int renderpolycount=0;   // polygons rendered in the current frame\r
35 Vector model_position;         // position of bunny\r
36 Quaternion model_orientation;  // orientation of bunny\r
38 // Note that the use of the Map() function and the collapse_map\r
39 // list isn't part of the polygon reduction algorithm.\r
40 // We just set up this system here in this module\r
41 // so that we could retrieve the model at any desired vertex count.\r
42 // Therefore if this part of the program confuses you, then\r
43 // dont worry about it.  It might help to look over the progmesh.cpp\r
44 // module first.\r
46 //       Map()\r
47 //\r
48 // When the model is rendered using a maximum of mx vertices\r
49 // then it is vertices 0 through mx-1 that are used.  \r
50 // We are able to do this because the vertex list \r
51 // gets sorted according to the collapse order.\r
52 // The Map() routine takes a vertex number 'a' and the\r
53 // maximum number of vertices 'mx' and returns the \r
54 // appropriate vertex in the range 0 to mx-1.\r
55 // When 'a' is greater than 'mx' the Map() routine\r
56 // follows the chain of edge collapses until a vertex\r
57 // within the limit is reached.\r
58 //   An example to make this clear: assume there is\r
59 //   a triangle with vertices 1, 3 and 12.  But when\r
60 //   rendering the model we limit ourselves to 10 vertices.\r
61 //   In that case we find out how vertex 12 was removed\r
62 //   by the polygon reduction algorithm.  i.e. which\r
63 //   edge was collapsed.  Lets say that vertex 12 was collapsed\r
64 //   to vertex number 7.  This number would have been stored\r
65 //   in the collapse_map array (i.e. collapse_map[12]==7).\r
66 //   Since vertex 7 is in range (less than max of 10) we\r
67 //   will want to render the triangle 1,3,7.  \r
68 //   Pretend now that we want to limit ourselves to 5 vertices.\r
69 //   and vertex 7 was collapsed to vertex 3 \r
70 //   (i.e. collapse_map[7]==3).  Then triangle 1,3,12 would now be\r
71 //   triangle 1,3,3.  i.e. this polygon was removed by the\r
72 //   progressive mesh polygon reduction algorithm by the time\r
73 //   it had gotten down to 5 vertices.\r
74 //   No need to draw a one dimensional polygon. :-)\r
75 int Map(int a,int mx) {\r
76         if(mx<=0) return 0;\r
77         while(a>=mx) {  \r
78                 a=collapse_map[a];\r
79         }\r
80         return a;\r
81 }\r
83 void DrawModelTriangles() {\r
84         assert(collapse_map.num);\r
85         renderpolycount=0;\r
86         int i=0;\r
87         for(i=0;i<tri.num;i++) {\r
88                 int p0= Map(tri[i].v[0],render_num);\r
89                 int p1= Map(tri[i].v[1],render_num);\r
90                 int p2= Map(tri[i].v[2],render_num);\r
91                 // note:  serious optimization opportunity here,\r
92                 //  by sorting the triangles the following "continue" \r
93                 //  could have been made into a "break" statement.\r
94                 if(p0==p1 || p1==p2 || p2==p0) continue;\r
95                 renderpolycount++;\r
96                 // if we are not currenly morphing between 2 levels of detail\r
97                 // (i.e. if morph=1.0) then q0,q1, and q2 are not necessary.\r
98                 int q0= Map(p0,(int)(render_num*lodbase));\r
99                 int q1= Map(p1,(int)(render_num*lodbase));\r
100                 int q2= Map(p2,(int)(render_num*lodbase));\r
101                 Vector v0,v1,v2; \r
102                 v0 = vert[p0]*morph + vert[q0]*(1-morph);\r
103                 v1 = vert[p1]*morph + vert[q1]*(1-morph);\r
104                 v2 = vert[p2]*morph + vert[q2]*(1-morph);\r
105                 glBegin(GL_POLYGON);\r
106                         // the purpose of the demo is to show polygons\r
107                         // therefore just use 1 face normal (flat shading)\r
108                         Vector nrml = (v1-v0) * (v2-v1);  // cross product\r
109                         if(0<magnitude(nrml)) {\r
110                                 glNormal3fv(normalize(nrml));\r
111                         }\r
112                         glVertex3fv(v0);\r
113                         glVertex3fv(v1);\r
114                         glVertex3fv(v2);\r
115                 glEnd();\r
116         }\r
120 void PermuteVertices(List<int> &permutation) {\r
121         // rearrange the vertex list \r
122         List<Vector> temp_list;\r
123         int i;\r
124         assert(permutation.num==vert.num);\r
125         for(i=0;i<vert.num;i++) {\r
126                 temp_list.Add(vert[i]);\r
127         }\r
128         for(i=0;i<vert.num;i++) {\r
129                 vert[permutation[i]]=temp_list[i];\r
130         }\r
131         // update the changes in the entries in the triangle list\r
132         for(i=0;i<tri.num;i++) {\r
133                 for(int j=0;j<3;j++) {\r
134                         tri[i].v[j] = permutation[tri[i].v[j]];\r
135                 }\r
136         }\r
139 void GetRabbitData(){\r
140         // Copy the geometry from the arrays of data in rabdata.cpp into\r
141         // the vert and tri lists which we send to the reduction routine\r
142         int i;\r
143         for(i=0;i<RABBIT_VERTEX_NUM;i++) {\r
144                 float *vp=rabbit_vertices[i];\r
145                 vert.Add(Vector(vp[0],vp[1],vp[2]));\r
146         }\r
147         for(i=0;i<RABBIT_TRIANGLE_NUM;i++) {\r
148                 tridata td;\r
149                 td.v[0]=rabbit_triangles[i][0];\r
150                 td.v[1]=rabbit_triangles[i][1];\r
151                 td.v[2]=rabbit_triangles[i][2];\r
152                 tri.Add(td);\r
153         }\r
154         render_num=vert.num;  // by default lets use all the model to render\r
158 void InitModel() {\r
159         List<int> permutation;\r
160         GetRabbitData();  \r
161         ProgressiveMesh(vert,tri,collapse_map,permutation);\r
162         PermuteVertices(permutation);\r
163         model_position    = Vector(0,0,-3);\r
164         Quaternion yaw(Vector(0,1,0),-3.14f/4);    // 45 degrees\r
165         Quaternion pitch(Vector(1,0,0),3.14f/12);  // 15 degrees \r
166         model_orientation = pitch*yaw;\r
169 void StatusDraw() {\r
170         //  Draw a slider type widget looking thing\r
171         // to show portion of vertices being used\r
172         float b = (float)render_num/(float)vert.num;\r
173         float a = b*(lodbase );\r
174         glDisable(GL_LIGHTING);\r
175         glMatrixMode( GL_PROJECTION );\r
176         glPushMatrix();\r
177         glLoadIdentity();\r
178         glOrtho(-0.15,15,-0.1,1.1,-0.1,100);\r
179         glMatrixMode( GL_MODELVIEW );\r
181         glPushMatrix();\r
182         glLoadIdentity();\r
183         glBegin(GL_POLYGON);\r
184         glColor3f(1,0,0);\r
185         glVertex2f(0,0);\r
186         glVertex2f(1,0);\r
187         glVertex2f(1,a);\r
188         glVertex2f(0,a);\r
189         glEnd();\r
190         glBegin(GL_POLYGON);\r
191         glColor3f(1,0,0);\r
192         glVertex2f(0,a);\r
193         glVertex2f(morph,a);\r
194         glVertex2f(morph,b);\r
195         glVertex2f(0,b);\r
196         glEnd();\r
197         glBegin(GL_POLYGON);\r
198         glColor3f(0,0,1);\r
199         glVertex2f(morph,a);\r
200         glVertex2f(1,a);\r
201         glVertex2f(1,b);\r
202         glVertex2f(morph,b);\r
203         glEnd();\r
204         glBegin(GL_POLYGON);\r
205         glColor3f(0,0,1);\r
206         glVertex2f(0,b);\r
207         glVertex2f(1,b);\r
208         glVertex2f(1,1);\r
209         glVertex2f(0,1);\r
210         glEnd();\r
211         glPopMatrix();\r
212         glMatrixMode( GL_PROJECTION );\r
213         glPopMatrix();\r
214         glMatrixMode( GL_MODELVIEW );\r
217 /*\r
218  *  The following is just a quick hack to animate\r
219  *  the object through various polygon reduced versions.\r
220  */\r
221 struct keyframethings {\r
222         float t;   // timestamp\r
223         float n;   // portion of vertices used to start\r
224         float dn;  // rate of change in "n"\r
225         float m;   // morph value\r
226         float dm;  // rate of change in "m"\r
227 } keys[]={\r
228         {0 ,1   ,0 ,1, 0},\r
229         {2 ,1   ,-1,1, 0},\r
230         {10,0   ,1 ,1, 0},\r
231         {18,1   ,0 ,1, 0},\r
232         {20,1   ,0 ,1,-1},\r
233         {24,0.5 ,0 ,1, 0},\r
234         {26,0.5 ,0 ,1,-1},\r
235         {30,0.25,0 ,1, 0},\r
236         {32,0.25,0 ,1,-1},\r
237         {36,0.125,0,1, 0},\r
238         {38,0.25,0 ,0, 1},\r
239         {42,0.5 ,0 ,0, 1},\r
240         {46,1   ,0 ,0, 1},\r
241         {50,1   ,0 ,1, 0},\r
242 };\r
243 void AnimateParameters() {\r
244         static float time=0;  // global time - used for animation\r
245         time+=DeltaT;\r
246         if(time>=50) time=0;  // repeat cycle every so many seconds\r
247         int k=0;\r
248         while(time>keys[k+1].t) {\r
249                 k++;\r
250         }\r
251         float interp = (time-keys[k].t)/(keys[k+1].t-keys[k].t);\r
252         render_num = vert.num*(keys[k].n + interp*keys[k].dn);\r
253         morph    = keys[k].m + interp*keys[k].dm;\r
254         morph = (morph>1.0f) ? 1.0f : morph;  // clamp value\r
255         if(render_num>vert.num) render_num=vert.num;\r
256         if(render_num<0       ) render_num=0;\r
259 void RenderModel() {\r
260         AnimateParameters();\r
261         \r
262         glEnable(GL_LIGHTING);\r
263         glEnable(GL_LIGHT0);\r
264         glColor3f(1,1,1);\r
265         glPushMatrix();\r
266         glTranslatef(model_position.x,model_position.y,model_position.z);\r
267         // Rotate by quaternion: model_orientation\r
268         Vector axis=model_orientation.axis();\r
269         float angle=model_orientation.angle()*180.0f/3.14f;\r
270         glRotatef(angle,axis.x,axis.y,axis.z);\r
271         DrawModelTriangles();\r
272         StatusDraw();\r
273         glPopMatrix();\r
275         char buf[256];\r
276         sprintf(buf,"Polys: %d  Vertices: %d ",renderpolycount,render_num);\r
277         if(morph<1.0) {\r
278                 sprintf(buf+strlen(buf),"<-> %d  morph: %4.2f ",\r
279                         (int)(lodbase *render_num),morph); \r
280         }\r
281         PostString(buf,0,-2,5);\r