/applications/utilities/surface/surfaceCoarsen/bunnylod/bunnygut.C
C | 282 lines | 200 code | 17 blank | 65 comment | 16 complexity | 8bfb5796732fac3c4f180a785a06b1be MD5 | raw file
- /*
- * 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 <windows.h>
- #include <stdio.h>
- #include <math.h>
- #include <stdlib.h>
- #include <assert.h>
- #include <string.h>
- #include <GL/gl.h>
- #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<Vector> vert; // global list of vertices
- List<tridata> tri; // global list of triangles
- List<int> 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<tri.num;i++) {
- int p0= Map(tri[i].v[0],render_num);
- int p1= Map(tri[i].v[1],render_num);
- int p2= Map(tri[i].v[2],render_num);
- // note: serious optimization opportunity here,
- // by sorting the triangles the following "continue"
- // could have been made into a "break" statement.
- if(p0==p1 || p1==p2 || p2==p0) continue;
- renderpolycount++;
- // if we are not currenly morphing between 2 levels of detail
- // (i.e. if morph=1.0) then q0,q1, and q2 are not necessary.
- int q0= Map(p0,(int)(render_num*lodbase));
- int q1= Map(p1,(int)(render_num*lodbase));
- int q2= Map(p2,(int)(render_num*lodbase));
- Vector v0,v1,v2;
- v0 = vert[p0]*morph + vert[q0]*(1-morph);
- v1 = vert[p1]*morph + vert[q1]*(1-morph);
- v2 = vert[p2]*morph + vert[q2]*(1-morph);
- glBegin(GL_POLYGON);
- // the purpose of the demo is to show polygons
- // therefore just use 1 face normal (flat shading)
- Vector nrml = (v1-v0) * (v2-v1); // cross product
- if(0<magnitude(nrml)) {
- glNormal3fv(normalize(nrml));
- }
- glVertex3fv(v0);
- glVertex3fv(v1);
- glVertex3fv(v2);
- glEnd();
- }
- }
- void PermuteVertices(List<int> &permutation) {
- // rearrange the vertex list
- List<Vector> temp_list;
- int i;
- assert(permutation.num==vert.num);
- for(i=0;i<vert.num;i++) {
- temp_list.Add(vert[i]);
- }
- for(i=0;i<vert.num;i++) {
- vert[permutation[i]]=temp_list[i];
- }
- // update the changes in the entries in the triangle list
- for(i=0;i<tri.num;i++) {
- for(int j=0;j<3;j++) {
- tri[i].v[j] = permutation[tri[i].v[j]];
- }
- }
- }
- void GetRabbitData(){
- // Copy the geometry from the arrays of data in rabdata.cpp into
- // the vert and tri lists which we send to the reduction routine
- int i;
- for(i=0;i<RABBIT_VERTEX_NUM;i++) {
- float *vp=rabbit_vertices[i];
- vert.Add(Vector(vp[0],vp[1],vp[2]));
- }
- for(i=0;i<RABBIT_TRIANGLE_NUM;i++) {
- tridata td;
- td.v[0]=rabbit_triangles[i][0];
- td.v[1]=rabbit_triangles[i][1];
- td.v[2]=rabbit_triangles[i][2];
- tri.Add(td);
- }
- render_num=vert.num; // by default lets use all the model to render
- }
- void InitModel() {
- List<int> 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);
- }