mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
STYLE: Fixing code style requirements for more files - those not
picked up by a copyright change.
This commit is contained in:
@ -1,283 +1,282 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
#ifndef FONT_H
|
||||
#define FONT_H
|
||||
|
||||
void PrintString(char *s,int x=0,int y=-1);
|
||||
void PostString(char *_s,int _x,int _y,float _life=5.0);
|
||||
void RenderStrings();
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef FONT_H
|
||||
#define FONT_H
|
||||
|
||||
void PrintString(char *s,int x=0,int y=-1);
|
||||
void PostString(char *_s,int _x,int _y,float _life=5.0);
|
||||
void RenderStrings();
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,128 +1,130 @@
|
||||
/*
|
||||
* A generic template list class.
|
||||
* Fairly typical of the list example you would
|
||||
* find in any c++ book.
|
||||
*/
|
||||
#ifndef GENERIC_LIST_H
|
||||
#define GENERIC_LIST_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
template <class Type> class List {
|
||||
public:
|
||||
List(int s=0);
|
||||
~List();
|
||||
void allocate(int s);
|
||||
void SetSize(int s);
|
||||
void Pack();
|
||||
void Add(Type);
|
||||
void AddUnique(Type);
|
||||
int Contains(Type);
|
||||
void Remove(Type);
|
||||
void DelIndex(int i);
|
||||
Type * element;
|
||||
int num;
|
||||
int array_size;
|
||||
Type &operator[](int i){assert(i>=0 && i<num); return element[i];}
|
||||
};
|
||||
|
||||
|
||||
template <class Type>
|
||||
List<Type>::List(int s){
|
||||
num=0;
|
||||
array_size = 0;
|
||||
element = NULL;
|
||||
if(s) {
|
||||
allocate(s);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
List<Type>::~List(){
|
||||
delete element;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void List<Type>::allocate(int s){
|
||||
assert(s>0);
|
||||
assert(s>=num);
|
||||
Type *old = element;
|
||||
array_size =s;
|
||||
element = new Type[array_size];
|
||||
assert(element);
|
||||
for(int i=0;i<num;i++){
|
||||
element[i]=old[i];
|
||||
}
|
||||
if(old) delete old;
|
||||
}
|
||||
template <class Type>
|
||||
void List<Type>::SetSize(int s){
|
||||
if(s==0) { if(element) delete element;}
|
||||
else { allocate(s); }
|
||||
num=s;
|
||||
}
|
||||
template <class Type>
|
||||
void List<Type>::Pack(){
|
||||
allocate(num);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void List<Type>::Add(Type t){
|
||||
assert(num<=array_size);
|
||||
if(num==array_size) {
|
||||
allocate((array_size)?array_size *2:16);
|
||||
}
|
||||
//int i;
|
||||
//for(i=0;i<num;i++) {
|
||||
// dissallow duplicates
|
||||
// assert(element[i] != t);
|
||||
//}
|
||||
element[num++] = t;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
int List<Type>::Contains(Type t){
|
||||
int i;
|
||||
int count=0;
|
||||
for(i=0;i<num;i++) {
|
||||
if(element[i] == t) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void List<Type>::AddUnique(Type t){
|
||||
if(!Contains(t)) Add(t);
|
||||
}
|
||||
|
||||
|
||||
template <class Type>
|
||||
void List<Type>::DelIndex(int i){
|
||||
assert(i<num);
|
||||
num--;
|
||||
while(i<num){
|
||||
element[i] = element[i+1];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void List<Type>::Remove(Type t){
|
||||
int i;
|
||||
for(i=0;i<num;i++) {
|
||||
if(element[i] == t) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
DelIndex(i);
|
||||
for(i=0;i<num;i++) {
|
||||
assert(element[i] != t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
/*
|
||||
* A generic template list class.
|
||||
* Fairly typical of the list example you would
|
||||
* find in any c++ book.
|
||||
*/
|
||||
#ifndef GENERIC_LIST_H
|
||||
#define GENERIC_LIST_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
template <class Type> class List {
|
||||
public:
|
||||
List(int s=0);
|
||||
~List();
|
||||
void allocate(int s);
|
||||
void SetSize(int s);
|
||||
void Pack();
|
||||
void Add(Type);
|
||||
void AddUnique(Type);
|
||||
int Contains(Type);
|
||||
void Remove(Type);
|
||||
void DelIndex(int i);
|
||||
Type * element;
|
||||
int num;
|
||||
int array_size;
|
||||
Type &operator[](int i){
|
||||
assert(i>=0 && i<num);
|
||||
return element[i];}
|
||||
};
|
||||
|
||||
|
||||
template <class Type>
|
||||
List<Type>::List(int s){
|
||||
num=0;
|
||||
array_size = 0;
|
||||
element = NULL;
|
||||
if(s) {
|
||||
allocate(s);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
List<Type>::~List(){
|
||||
delete element;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void List<Type>::allocate(int s){
|
||||
assert(s>0);
|
||||
assert(s>=num);
|
||||
Type *old = element;
|
||||
array_size =s;
|
||||
element = new Type[array_size];
|
||||
assert(element);
|
||||
for(int i=0;i<num;i++){
|
||||
element[i]=old[i];
|
||||
}
|
||||
if(old) delete old;
|
||||
}
|
||||
template <class Type>
|
||||
void List<Type>::SetSize(int s){
|
||||
if(s==0) { if(element) delete element;}
|
||||
else { allocate(s); }
|
||||
num=s;
|
||||
}
|
||||
template <class Type>
|
||||
void List<Type>::Pack(){
|
||||
allocate(num);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void List<Type>::Add(Type t){
|
||||
assert(num<=array_size);
|
||||
if(num==array_size) {
|
||||
allocate((array_size)?array_size *2:16);
|
||||
}
|
||||
//int i;
|
||||
//for(i=0;i<num;i++) {
|
||||
// dissallow duplicates
|
||||
// assert(element[i] != t);
|
||||
//}
|
||||
element[num++] = t;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
int List<Type>::Contains(Type t){
|
||||
int i;
|
||||
int count=0;
|
||||
for(i=0;i<num;i++) {
|
||||
if(element[i] == t) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void List<Type>::AddUnique(Type t){
|
||||
if(!Contains(t)) Add(t);
|
||||
}
|
||||
|
||||
|
||||
template <class Type>
|
||||
void List<Type>::DelIndex(int i){
|
||||
assert(i<num);
|
||||
num--;
|
||||
while(i<num){
|
||||
element[i] = element[i+1];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void List<Type>::Remove(Type t){
|
||||
int i;
|
||||
for(i=0;i<num;i++) {
|
||||
if(element[i] == t) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
DelIndex(i);
|
||||
for(i=0;i<num;i++) {
|
||||
assert(element[i] != t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,313 +1,315 @@
|
||||
/*
|
||||
* Progressive Mesh type Polygon Reduction Algorithm
|
||||
* by Stan Melax (c) 1998
|
||||
* Permission to use any of this code wherever you want is granted..
|
||||
* Although, please do acknowledge authorship if appropriate.
|
||||
*
|
||||
* See the header file progmesh.h for a description of this module
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
//#include <windows.h>
|
||||
|
||||
#include "vector.h"
|
||||
#include "list.h"
|
||||
#include "progmesh.h"
|
||||
|
||||
#define min(x,y) (((x) <= (y)) ? (x) : (y))
|
||||
#define max(x,y) (((x) >= (y)) ? (x) : (y))
|
||||
|
||||
|
||||
/*
|
||||
* For the polygon reduction algorithm we use data structures
|
||||
* that contain a little bit more information than the usual
|
||||
* indexed face set type of data structure.
|
||||
* From a vertex we wish to be able to quickly get the
|
||||
* neighboring faces and vertices.
|
||||
*/
|
||||
class Triangle;
|
||||
class Vertex;
|
||||
|
||||
class Triangle {
|
||||
public:
|
||||
Vertex * vertex[3]; // the 3 points that make this tri
|
||||
Vector normal; // unit vector othogonal to this face
|
||||
Triangle(Vertex *v0,Vertex *v1,Vertex *v2);
|
||||
~Triangle();
|
||||
void ComputeNormal();
|
||||
void ReplaceVertex(Vertex *vold,Vertex *vnew);
|
||||
int HasVertex(Vertex *v);
|
||||
};
|
||||
class Vertex {
|
||||
public:
|
||||
Vector position; // location of point in euclidean space
|
||||
int id; // place of vertex in original list
|
||||
List<Vertex *> neighbor; // adjacent vertices
|
||||
List<Triangle *> face; // adjacent triangles
|
||||
float objdist; // cached cost of collapsing edge
|
||||
Vertex * collapse; // candidate vertex for collapse
|
||||
Vertex(Vector v,int _id);
|
||||
~Vertex();
|
||||
void RemoveIfNonNeighbor(Vertex *n);
|
||||
};
|
||||
List<Vertex *> vertices;
|
||||
List<Triangle *> triangles;
|
||||
|
||||
|
||||
Triangle::Triangle(Vertex *v0,Vertex *v1,Vertex *v2){
|
||||
assert(v0!=v1 && v1!=v2 && v2!=v0);
|
||||
vertex[0]=v0;
|
||||
vertex[1]=v1;
|
||||
vertex[2]=v2;
|
||||
ComputeNormal();
|
||||
triangles.Add(this);
|
||||
for(int i=0;i<3;i++) {
|
||||
vertex[i]->face.Add(this);
|
||||
for(int j=0;j<3;j++) if(i!=j) {
|
||||
vertex[i]->neighbor.AddUnique(vertex[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Triangle::~Triangle(){
|
||||
int i;
|
||||
triangles.Remove(this);
|
||||
for(i=0;i<3;i++) {
|
||||
if(vertex[i]) vertex[i]->face.Remove(this);
|
||||
}
|
||||
for(i=0;i<3;i++) {
|
||||
int i2 = (i+1)%3;
|
||||
if(!vertex[i] || !vertex[i2]) continue;
|
||||
vertex[i ]->RemoveIfNonNeighbor(vertex[i2]);
|
||||
vertex[i2]->RemoveIfNonNeighbor(vertex[i ]);
|
||||
}
|
||||
}
|
||||
int Triangle::HasVertex(Vertex *v) {
|
||||
return (v==vertex[0] ||v==vertex[1] || v==vertex[2]);
|
||||
}
|
||||
void Triangle::ComputeNormal(){
|
||||
Vector v0=vertex[0]->position;
|
||||
Vector v1=vertex[1]->position;
|
||||
Vector v2=vertex[2]->position;
|
||||
normal = (v1-v0)*(v2-v1);
|
||||
if(magnitude(normal)==0)return;
|
||||
normal = normalize(normal);
|
||||
}
|
||||
void Triangle::ReplaceVertex(Vertex *vold,Vertex *vnew) {
|
||||
assert(vold && vnew);
|
||||
assert(vold==vertex[0] || vold==vertex[1] || vold==vertex[2]);
|
||||
assert(vnew!=vertex[0] && vnew!=vertex[1] && vnew!=vertex[2]);
|
||||
if(vold==vertex[0]){
|
||||
vertex[0]=vnew;
|
||||
}
|
||||
else if(vold==vertex[1]){
|
||||
vertex[1]=vnew;
|
||||
}
|
||||
else {
|
||||
assert(vold==vertex[2]);
|
||||
vertex[2]=vnew;
|
||||
}
|
||||
int i;
|
||||
vold->face.Remove(this);
|
||||
assert(!vnew->face.Contains(this));
|
||||
vnew->face.Add(this);
|
||||
for(i=0;i<3;i++) {
|
||||
vold->RemoveIfNonNeighbor(vertex[i]);
|
||||
vertex[i]->RemoveIfNonNeighbor(vold);
|
||||
}
|
||||
for(i=0;i<3;i++) {
|
||||
assert(vertex[i]->face.Contains(this)==1);
|
||||
for(int j=0;j<3;j++) if(i!=j) {
|
||||
vertex[i]->neighbor.AddUnique(vertex[j]);
|
||||
}
|
||||
}
|
||||
ComputeNormal();
|
||||
}
|
||||
|
||||
Vertex::Vertex(Vector v,int _id) {
|
||||
position =v;
|
||||
id=_id;
|
||||
vertices.Add(this);
|
||||
}
|
||||
|
||||
Vertex::~Vertex(){
|
||||
assert(face.num==0);
|
||||
while(neighbor.num) {
|
||||
neighbor[0]->neighbor.Remove(this);
|
||||
neighbor.Remove(neighbor[0]);
|
||||
}
|
||||
vertices.Remove(this);
|
||||
}
|
||||
void Vertex::RemoveIfNonNeighbor(Vertex *n) {
|
||||
// removes n from neighbor list if n isn't a neighbor.
|
||||
if(!neighbor.Contains(n)) return;
|
||||
for(int i=0;i<face.num;i++) {
|
||||
if(face[i]->HasVertex(n)) return;
|
||||
}
|
||||
neighbor.Remove(n);
|
||||
}
|
||||
|
||||
|
||||
float ComputeEdgeCollapseCost(Vertex *u,Vertex *v) {
|
||||
// if we collapse edge uv by moving u to v then how
|
||||
// much different will the model change, i.e. how much "error".
|
||||
// Texture, vertex normal, and border vertex code was removed
|
||||
// to keep this demo as simple as possible.
|
||||
// The method of determining cost was designed in order
|
||||
// to exploit small and coplanar regions for
|
||||
// effective polygon reduction.
|
||||
// Is is possible to add some checks here to see if "folds"
|
||||
// would be generated. i.e. normal of a remaining face gets
|
||||
// flipped. I never seemed to run into this problem and
|
||||
// therefore never added code to detect this case.
|
||||
int i;
|
||||
float edgelength = magnitude(v->position - u->position);
|
||||
float curvature=0;
|
||||
|
||||
// find the "sides" triangles that are on the edge uv
|
||||
List<Triangle *> sides;
|
||||
for(i=0;i<u->face.num;i++) {
|
||||
if(u->face[i]->HasVertex(v)){
|
||||
sides.Add(u->face[i]);
|
||||
}
|
||||
}
|
||||
// use the triangle facing most away from the sides
|
||||
// to determine our curvature term
|
||||
for(i=0;i<u->face.num;i++) {
|
||||
float mincurv=1; // curve for face i and closer side to it
|
||||
for(int j=0;j<sides.num;j++) {
|
||||
// use dot product of face normals. '^' defined in vector
|
||||
float dotprod = u->face[i]->normal ^ sides[j]->normal;
|
||||
mincurv = min(mincurv,(1-dotprod)/2.0f);
|
||||
}
|
||||
curvature = max(curvature,mincurv);
|
||||
}
|
||||
// the more coplanar the lower the curvature term
|
||||
return edgelength * curvature;
|
||||
}
|
||||
|
||||
void ComputeEdgeCostAtVertex(Vertex *v) {
|
||||
// compute the edge collapse cost for all edges that start
|
||||
// from vertex v. Since we are only interested in reducing
|
||||
// the object by selecting the min cost edge at each step, we
|
||||
// only cache the cost of the least cost edge at this vertex
|
||||
// (in member variable collapse) as well as the value of the
|
||||
// cost (in member variable objdist).
|
||||
if(v->neighbor.num==0) {
|
||||
// v doesn't have neighbors so it costs nothing to collapse
|
||||
v->collapse=NULL;
|
||||
v->objdist=-0.01f;
|
||||
return;
|
||||
}
|
||||
v->objdist = 1000000;
|
||||
v->collapse=NULL;
|
||||
// search all neighboring edges for "least cost" edge
|
||||
for(int i=0;i<v->neighbor.num;i++) {
|
||||
float dist;
|
||||
dist = ComputeEdgeCollapseCost(v,v->neighbor[i]);
|
||||
if(dist<v->objdist) {
|
||||
v->collapse=v->neighbor[i]; // candidate for edge collapse
|
||||
v->objdist=dist; // cost of the collapse
|
||||
}
|
||||
}
|
||||
}
|
||||
void ComputeAllEdgeCollapseCosts() {
|
||||
// For all the edges, compute the difference it would make
|
||||
// to the model if it was collapsed. The least of these
|
||||
// per vertex is cached in each vertex object.
|
||||
for(int i=0;i<vertices.num;i++) {
|
||||
ComputeEdgeCostAtVertex(vertices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Collapse(Vertex *u,Vertex *v){
|
||||
// Collapse the edge uv by moving vertex u onto v
|
||||
// Actually remove tris on uv, then update tris that
|
||||
// have u to have v, and then remove u.
|
||||
if(!v) {
|
||||
// u is a vertex all by itself so just delete it
|
||||
delete u;
|
||||
return;
|
||||
}
|
||||
int i;
|
||||
List<Vertex *>tmp;
|
||||
// make tmp a list of all the neighbors of u
|
||||
for(i=0;i<u->neighbor.num;i++) {
|
||||
tmp.Add(u->neighbor[i]);
|
||||
}
|
||||
// delete triangles on edge uv:
|
||||
for(i=u->face.num-1;i>=0;i--) {
|
||||
if(u->face[i]->HasVertex(v)) {
|
||||
delete(u->face[i]);
|
||||
}
|
||||
}
|
||||
// update remaining triangles to have v instead of u
|
||||
for(i=u->face.num-1;i>=0;i--) {
|
||||
u->face[i]->ReplaceVertex(u,v);
|
||||
}
|
||||
delete u;
|
||||
// recompute the edge collapse costs for neighboring vertices
|
||||
for(i=0;i<tmp.num;i++) {
|
||||
ComputeEdgeCostAtVertex(tmp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void AddVertex(List<Vector> &vert){
|
||||
for(int i=0;i<vert.num;i++) {
|
||||
new Vertex(vert[i],i);
|
||||
}
|
||||
}
|
||||
void AddFaces(List<tridata> &tri){
|
||||
for(int i=0;i<tri.num;i++) {
|
||||
new Triangle(
|
||||
vertices[tri[i].v[0]],
|
||||
vertices[tri[i].v[1]],
|
||||
vertices[tri[i].v[2]] );
|
||||
}
|
||||
}
|
||||
|
||||
Vertex *MinimumCostEdge(){
|
||||
// Find the edge that when collapsed will affect model the least.
|
||||
// This funtion actually returns a Vertex, the second vertex
|
||||
// of the edge (collapse candidate) is stored in the vertex data.
|
||||
// Serious optimization opportunity here: this function currently
|
||||
// does a sequential search through an unsorted list :-(
|
||||
// Our algorithm could be O(n*lg(n)) instead of O(n*n)
|
||||
Vertex *mn=vertices[0];
|
||||
for(int i=0;i<vertices.num;i++) {
|
||||
if(vertices[i]->objdist < mn->objdist) {
|
||||
mn = vertices[i];
|
||||
}
|
||||
}
|
||||
return mn;
|
||||
}
|
||||
|
||||
void ProgressiveMesh(List<Vector> &vert, List<tridata> &tri,
|
||||
List<int> &map, List<int> &permutation)
|
||||
{
|
||||
AddVertex(vert); // put input data into our data structures
|
||||
AddFaces(tri);
|
||||
ComputeAllEdgeCollapseCosts(); // cache all edge collapse costs
|
||||
permutation.SetSize(vertices.num); // allocate space
|
||||
map.SetSize(vertices.num); // allocate space
|
||||
// reduce the object down to nothing:
|
||||
while(vertices.num > 0) {
|
||||
// get the next vertex to collapse
|
||||
Vertex *mn = MinimumCostEdge();
|
||||
// keep track of this vertex, i.e. the collapse ordering
|
||||
permutation[mn->id]=vertices.num-1;
|
||||
// keep track of vertex to which we collapse to
|
||||
map[vertices.num-1] = (mn->collapse)?mn->collapse->id:-1;
|
||||
// Collapse this edge
|
||||
Collapse(mn,mn->collapse);
|
||||
}
|
||||
// reorder the map list based on the collapse ordering
|
||||
for(int i=0;i<map.num;i++) {
|
||||
map[i] = (map[i]==-1)?0:permutation[map[i]];
|
||||
}
|
||||
// The caller of this function should reorder their vertices
|
||||
// according to the returned "permutation".
|
||||
}
|
||||
|
||||
/*
|
||||
* Progressive Mesh type Polygon Reduction Algorithm
|
||||
* by Stan Melax (c) 1998
|
||||
* Permission to use any of this code wherever you want is granted..
|
||||
* Although, please do acknowledge authorship if appropriate.
|
||||
*
|
||||
* See the header file progmesh.h for a description of this module
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
//#include <windows.h>
|
||||
|
||||
#include "vector.h"
|
||||
#include "list.h"
|
||||
#include "progmesh.h"
|
||||
|
||||
#define min(x,y) (((x) <= (y)) ? (x) : (y))
|
||||
#define max(x,y) (((x) >= (y)) ? (x) : (y))
|
||||
|
||||
|
||||
/*
|
||||
* For the polygon reduction algorithm we use data structures
|
||||
* that contain a little bit more information than the usual
|
||||
* indexed face set type of data structure.
|
||||
* From a vertex we wish to be able to quickly get the
|
||||
* neighboring faces and vertices.
|
||||
*/
|
||||
class Triangle;
|
||||
class Vertex;
|
||||
|
||||
class Triangle {
|
||||
public:
|
||||
Vertex * vertex[3]; // the 3 points that make this tri
|
||||
Vector normal; // unit vector othogonal to this face
|
||||
Triangle(Vertex *v0,Vertex *v1,Vertex *v2);
|
||||
~Triangle();
|
||||
void ComputeNormal();
|
||||
void ReplaceVertex(Vertex *vold,Vertex *vnew);
|
||||
int HasVertex(Vertex *v);
|
||||
};
|
||||
class Vertex {
|
||||
public:
|
||||
Vector position; // location of point in euclidean space
|
||||
int id; // place of vertex in original list
|
||||
List<Vertex *> neighbor; // adjacent vertices
|
||||
List<Triangle *> face; // adjacent triangles
|
||||
float objdist; // cached cost of collapsing edge
|
||||
Vertex * collapse; // candidate vertex for collapse
|
||||
Vertex(Vector v,int _id);
|
||||
~Vertex();
|
||||
void RemoveIfNonNeighbor(Vertex *n);
|
||||
};
|
||||
List<Vertex *> vertices;
|
||||
List<Triangle *> triangles;
|
||||
|
||||
|
||||
Triangle::Triangle(Vertex *v0,Vertex *v1,Vertex *v2){
|
||||
assert(v0!=v1 && v1!=v2 && v2!=v0);
|
||||
vertex[0]=v0;
|
||||
vertex[1]=v1;
|
||||
vertex[2]=v2;
|
||||
ComputeNormal();
|
||||
triangles.Add(this);
|
||||
for(int i=0;i<3;i++) {
|
||||
vertex[i]->face.Add(this);
|
||||
for(int j=0;j<3;j++) if(i!=j) {
|
||||
vertex[i]->neighbor.AddUnique(vertex[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Triangle::~Triangle(){
|
||||
int i;
|
||||
triangles.Remove(this);
|
||||
for(i=0;i<3;i++) {
|
||||
if(vertex[i]) vertex[i]->face.Remove(this);
|
||||
}
|
||||
for(i=0;i<3;i++) {
|
||||
int i2 = (i+1)%3;
|
||||
if(!vertex[i] || !vertex[i2]) continue;
|
||||
vertex[i ]->RemoveIfNonNeighbor(vertex[i2]);
|
||||
vertex[i2]->RemoveIfNonNeighbor(vertex[i ]);
|
||||
}
|
||||
}
|
||||
int Triangle::HasVertex(Vertex *v) {
|
||||
return (v==vertex[0] ||v==vertex[1] || v==vertex[2]);
|
||||
}
|
||||
void Triangle::ComputeNormal(){
|
||||
Vector v0=vertex[0]->position;
|
||||
Vector v1=vertex[1]->position;
|
||||
Vector v2=vertex[2]->position;
|
||||
normal = (v1-v0)*(v2-v1);
|
||||
if(magnitude(normal)==0)return;
|
||||
normal = normalize(normal);
|
||||
}
|
||||
void Triangle::ReplaceVertex(Vertex *vold,Vertex *vnew) {
|
||||
assert(vold && vnew);
|
||||
assert(vold==vertex[0] || vold==vertex[1] || vold==vertex[2]);
|
||||
assert(vnew!=vertex[0] && vnew!=vertex[1] && vnew!=vertex[2]);
|
||||
if(vold==vertex[0]){
|
||||
vertex[0]=vnew;
|
||||
}
|
||||
else if(vold==vertex[1]){
|
||||
vertex[1]=vnew;
|
||||
}
|
||||
else {
|
||||
assert(vold==vertex[2]);
|
||||
vertex[2]=vnew;
|
||||
}
|
||||
int i;
|
||||
vold->face.Remove(this);
|
||||
assert(!vnew->face.Contains(this));
|
||||
vnew->face.Add(this);
|
||||
for(i=0;i<3;i++) {
|
||||
vold->RemoveIfNonNeighbor(vertex[i]);
|
||||
vertex[i]->RemoveIfNonNeighbor(vold);
|
||||
}
|
||||
for(i=0;i<3;i++) {
|
||||
assert(vertex[i]->face.Contains(this)==1);
|
||||
for(int j=0;j<3;j++) if(i!=j) {
|
||||
vertex[i]->neighbor.AddUnique(vertex[j]);
|
||||
}
|
||||
}
|
||||
ComputeNormal();
|
||||
}
|
||||
|
||||
Vertex::Vertex(Vector v,int _id) {
|
||||
position =v;
|
||||
id=_id;
|
||||
vertices.Add(this);
|
||||
}
|
||||
|
||||
Vertex::~Vertex(){
|
||||
assert(face.num==0);
|
||||
while(neighbor.num) {
|
||||
neighbor[0]->neighbor.Remove(this);
|
||||
neighbor.Remove(neighbor[0]);
|
||||
}
|
||||
vertices.Remove(this);
|
||||
}
|
||||
void Vertex::RemoveIfNonNeighbor(Vertex *n) {
|
||||
// removes n from neighbor list if n isn't a neighbor.
|
||||
if(!neighbor.Contains(n)) return;
|
||||
for(int i=0;i<face.num;i++) {
|
||||
if(face[i]->HasVertex(n)) return;
|
||||
}
|
||||
neighbor.Remove(n);
|
||||
}
|
||||
|
||||
|
||||
float ComputeEdgeCollapseCost(Vertex *u,Vertex *v) {
|
||||
// if we collapse edge uv by moving u to v then how
|
||||
// much different will the model change, i.e. how much "error".
|
||||
// Texture, vertex normal, and border vertex code was removed
|
||||
// to keep this demo as simple as possible.
|
||||
// The method of determining cost was designed in order
|
||||
// to exploit small and coplanar regions for
|
||||
// effective polygon reduction.
|
||||
// Is is possible to add some checks here to see if "folds"
|
||||
// would be generated. i.e. normal of a remaining face gets
|
||||
// flipped. I never seemed to run into this problem and
|
||||
// therefore never added code to detect this case.
|
||||
int i;
|
||||
float edgelength = magnitude(v->position - u->position);
|
||||
float curvature=0;
|
||||
|
||||
// find the "sides" triangles that are on the edge uv
|
||||
List<Triangle *> sides;
|
||||
for(i=0;i<u->face.num;i++) {
|
||||
if(u->face[i]->HasVertex(v)){
|
||||
sides.Add(u->face[i]);
|
||||
}
|
||||
}
|
||||
// use the triangle facing most away from the sides
|
||||
// to determine our curvature term
|
||||
for(i=0;i<u->face.num;i++) {
|
||||
float mincurv=1; // curve for face i and closer side to it
|
||||
for(int j=0;j<sides.num;j++) {
|
||||
// use dot product of face normals. '^'
|
||||
// defined in vector
|
||||
float dotprod = u->face[i]->normal ^ sides[j]->normal;
|
||||
mincurv = min(mincurv,(1-dotprod)/2.0f);
|
||||
}
|
||||
curvature = max(curvature,mincurv);
|
||||
}
|
||||
// the more coplanar the lower the curvature term
|
||||
return edgelength * curvature;
|
||||
}
|
||||
|
||||
void ComputeEdgeCostAtVertex(Vertex *v) {
|
||||
// compute the edge collapse cost for all edges that start
|
||||
// from vertex v. Since we are only interested in reducing
|
||||
// the object by selecting the min cost edge at each step, we
|
||||
// only cache the cost of the least cost edge at this vertex
|
||||
// (in member variable collapse) as well as the value of the
|
||||
// cost (in member variable objdist).
|
||||
if(v->neighbor.num==0) {
|
||||
// v doesn't have neighbors so it costs nothing to collapse
|
||||
v->collapse=NULL;
|
||||
v->objdist=-0.01f;
|
||||
return;
|
||||
}
|
||||
v->objdist = 1000000;
|
||||
v->collapse=NULL;
|
||||
// search all neighboring edges for "least cost" edge
|
||||
for(int i=0;i<v->neighbor.num;i++) {
|
||||
float dist;
|
||||
dist = ComputeEdgeCollapseCost(v,v->neighbor[i]);
|
||||
if(dist<v->objdist) {
|
||||
// candidate for edge collapse
|
||||
v->collapse=v->neighbor[i];
|
||||
// cost of the collapse
|
||||
v->objdist=dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
void ComputeAllEdgeCollapseCosts() {
|
||||
// For all the edges, compute the difference it would make
|
||||
// to the model if it was collapsed. The least of these
|
||||
// per vertex is cached in each vertex object.
|
||||
for(int i=0;i<vertices.num;i++) {
|
||||
ComputeEdgeCostAtVertex(vertices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Collapse(Vertex *u,Vertex *v){
|
||||
// Collapse the edge uv by moving vertex u onto v
|
||||
// Actually remove tris on uv, then update tris that
|
||||
// have u to have v, and then remove u.
|
||||
if(!v) {
|
||||
// u is a vertex all by itself so just delete it
|
||||
delete u;
|
||||
return;
|
||||
}
|
||||
int i;
|
||||
List<Vertex *>tmp;
|
||||
// make tmp a list of all the neighbors of u
|
||||
for(i=0;i<u->neighbor.num;i++) {
|
||||
tmp.Add(u->neighbor[i]);
|
||||
}
|
||||
// delete triangles on edge uv:
|
||||
for(i=u->face.num-1;i>=0;i--) {
|
||||
if(u->face[i]->HasVertex(v)) {
|
||||
delete(u->face[i]);
|
||||
}
|
||||
}
|
||||
// update remaining triangles to have v instead of u
|
||||
for(i=u->face.num-1;i>=0;i--) {
|
||||
u->face[i]->ReplaceVertex(u,v);
|
||||
}
|
||||
delete u;
|
||||
// recompute the edge collapse costs for neighboring vertices
|
||||
for(i=0;i<tmp.num;i++) {
|
||||
ComputeEdgeCostAtVertex(tmp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void AddVertex(List<Vector> &vert){
|
||||
for(int i=0;i<vert.num;i++) {
|
||||
new Vertex(vert[i],i);
|
||||
}
|
||||
}
|
||||
void AddFaces(List<tridata> &tri){
|
||||
for(int i=0;i<tri.num;i++) {
|
||||
new Triangle(
|
||||
vertices[tri[i].v[0]],
|
||||
vertices[tri[i].v[1]],
|
||||
vertices[tri[i].v[2]] );
|
||||
}
|
||||
}
|
||||
|
||||
Vertex *MinimumCostEdge(){
|
||||
// Find the edge that when collapsed will affect model the least.
|
||||
// This funtion actually returns a Vertex, the second vertex
|
||||
// of the edge (collapse candidate) is stored in the vertex data.
|
||||
// Serious optimization opportunity here: this function currently
|
||||
// does a sequential search through an unsorted list :-(
|
||||
// Our algorithm could be O(n*lg(n)) instead of O(n*n)
|
||||
Vertex *mn=vertices[0];
|
||||
for(int i=0;i<vertices.num;i++) {
|
||||
if(vertices[i]->objdist < mn->objdist) {
|
||||
mn = vertices[i];
|
||||
}
|
||||
}
|
||||
return mn;
|
||||
}
|
||||
|
||||
void ProgressiveMesh(List<Vector> &vert, List<tridata> &tri,
|
||||
List<int> &map, List<int> &permutation)
|
||||
{
|
||||
AddVertex(vert); // put input data into our data structures
|
||||
AddFaces(tri);
|
||||
ComputeAllEdgeCollapseCosts(); // cache all edge collapse costs
|
||||
permutation.SetSize(vertices.num); // allocate space
|
||||
map.SetSize(vertices.num); // allocate space
|
||||
// reduce the object down to nothing:
|
||||
while(vertices.num > 0) {
|
||||
// get the next vertex to collapse
|
||||
Vertex *mn = MinimumCostEdge();
|
||||
// keep track of this vertex, i.e. the collapse ordering
|
||||
permutation[mn->id]=vertices.num-1;
|
||||
// keep track of vertex to which we collapse to
|
||||
map[vertices.num-1] = (mn->collapse)?mn->collapse->id:-1;
|
||||
// Collapse this edge
|
||||
Collapse(mn,mn->collapse);
|
||||
}
|
||||
// reorder the map list based on the collapse ordering
|
||||
for(int i=0;i<map.num;i++) {
|
||||
map[i] = (map[i]==-1)?0:permutation[map[i]];
|
||||
}
|
||||
// The caller of this function should reorder their vertices
|
||||
// according to the returned "permutation".
|
||||
}
|
||||
|
||||
@ -1,33 +1,33 @@
|
||||
/*
|
||||
* Progressive Mesh type Polygon Reduction Algorithm
|
||||
* by Stan Melax (c) 1998
|
||||
*
|
||||
* The function ProgressiveMesh() takes a model in an "indexed face
|
||||
* set" sort of way. i.e. list of vertices and list of triangles.
|
||||
* The function then does the polygon reduction algorithm
|
||||
* internally and reduces the model all the way down to 0
|
||||
* vertices and then returns the order in which the
|
||||
* vertices are collapsed and to which neighbor each vertex
|
||||
* is collapsed to. More specifically the returned "permutation"
|
||||
* indicates how to reorder your vertices so you can render
|
||||
* an object by using the first n vertices (for the n
|
||||
* vertex version). After permuting your vertices, the
|
||||
* map list indicates to which vertex each vertex is collapsed to.
|
||||
*/
|
||||
|
||||
#ifndef PROGRESSIVE_MESH_H
|
||||
#define PROGRESSIVE_MESH_H
|
||||
|
||||
#include "vector.h"
|
||||
#include "list.h"
|
||||
|
||||
class tridata {
|
||||
public:
|
||||
int v[3]; // indices to vertex list
|
||||
// texture and vertex normal info removed for this demo
|
||||
};
|
||||
|
||||
void ProgressiveMesh(List<Vector> &vert, List<tridata> &tri,
|
||||
List<int> &map, List<int> &permutation );
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Progressive Mesh type Polygon Reduction Algorithm
|
||||
* by Stan Melax (c) 1998
|
||||
*
|
||||
* The function ProgressiveMesh() takes a model in an "indexed face
|
||||
* set" sort of way. i.e. list of vertices and list of triangles.
|
||||
* The function then does the polygon reduction algorithm
|
||||
* internally and reduces the model all the way down to 0
|
||||
* vertices and then returns the order in which the
|
||||
* vertices are collapsed and to which neighbor each vertex
|
||||
* is collapsed to. More specifically the returned "permutation"
|
||||
* indicates how to reorder your vertices so you can render
|
||||
* an object by using the first n vertices (for the n
|
||||
* vertex version). After permuting your vertices, the
|
||||
* map list indicates to which vertex each vertex is collapsed to.
|
||||
*/
|
||||
|
||||
#ifndef PROGRESSIVE_MESH_H
|
||||
#define PROGRESSIVE_MESH_H
|
||||
|
||||
#include "vector.h"
|
||||
#include "list.h"
|
||||
|
||||
class tridata {
|
||||
public:
|
||||
int v[3]; // indices to vertex list
|
||||
// texture and vertex normal info removed for this demo
|
||||
};
|
||||
|
||||
void ProgressiveMesh(List<Vector> &vert, List<tridata> &tri,
|
||||
List<int> &map, List<int> &permutation );
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,31 +1,32 @@
|
||||
/* Copyright 1996, Viewpoint Datalabs Int'l, www.viewpoint.com, 1-800-DATASET */
|
||||
/*
|
||||
# Usage Rights: You (the user) may use this model to help build cool personal
|
||||
# vrml worlds, but please give us credit when you do ("3D model provided by
|
||||
# Viewpoint Datalabs, www,viewpoint.com"). Please don't sell it or use it to
|
||||
# make money indirectly. Don't redistribute it or put it on a web site except
|
||||
# as a part of your personal, non-commerical vrml world. If you want to do a
|
||||
# commercial project, give us a call at 1-800-DATASET or visit www.viewpoint.com
|
||||
# and we'll help you obtain the rights to do so.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note that this data was put directly into the program
|
||||
* to provide a demo program on the net that people could
|
||||
* just run without having to fetch datafiles.
|
||||
* i.e. more convienent for the user this way
|
||||
*/
|
||||
|
||||
|
||||
#ifndef RABBIT_DATA_H
|
||||
#define RABBIT_DATA_H
|
||||
|
||||
#define RABBIT_VERTEX_NUM (453)
|
||||
#define RABBIT_TRIANGLE_NUM (902)
|
||||
|
||||
extern float rabbit_vertices[RABBIT_VERTEX_NUM][3];
|
||||
extern int rabbit_triangles[RABBIT_TRIANGLE_NUM][3];
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
/* Copyright 1996, Viewpoint Datalabs Int'l, www.viewpoint.com, 1-800-DATASET */
|
||||
/*
|
||||
# Usage Rights: You (the user) may use this model to help build
|
||||
# cool personal vrml worlds, but please give us credit when you do
|
||||
# ("3D model provided by Viewpoint Datalabs, www,viewpoint.com").
|
||||
# Please don't sell it or use it to make money indirectly. Don't
|
||||
# redistribute it or put it on a web site except as a part of your
|
||||
# personal, non-commerical vrml world. If you want to do a
|
||||
# commercial project, give us a call at 1-800-DATASET or visit
|
||||
# www.viewpoint.com and we'll help you obtain the rights to do so.
|
||||
# */
|
||||
|
||||
/*
|
||||
* Note that this data was put directly into the program
|
||||
* to provide a demo program on the net that people could
|
||||
* just run without having to fetch datafiles.
|
||||
* i.e. more convienent for the user this way
|
||||
*/
|
||||
|
||||
|
||||
#ifndef RABBIT_DATA_H
|
||||
#define RABBIT_DATA_H
|
||||
|
||||
#define RABBIT_VERTEX_NUM (453)
|
||||
#define RABBIT_TRIANGLE_NUM (902)
|
||||
|
||||
extern float rabbit_vertices[RABBIT_VERTEX_NUM][3];
|
||||
extern int rabbit_triangles[RABBIT_TRIANGLE_NUM][3];
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,108 +1,117 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "vector.h"
|
||||
|
||||
float sqr(float a) {return a*a;}
|
||||
|
||||
// vector (floating point) implementation
|
||||
|
||||
float magnitude(Vector v) {
|
||||
return float(sqrt(sqr(v.x) + sqr( v.y)+ sqr(v.z)));
|
||||
}
|
||||
Vector normalize(Vector v) {
|
||||
float d=magnitude(v);
|
||||
if (d==0) {
|
||||
printf("Cant normalize ZERO vector\n");
|
||||
assert(0);
|
||||
d=0.1f;
|
||||
}
|
||||
v.x/=d;
|
||||
v.y/=d;
|
||||
v.z/=d;
|
||||
return v;
|
||||
}
|
||||
|
||||
Vector operator+(Vector v1,Vector v2) {return Vector(v1.x+v2.x,v1.y+v2.y,v1.z+v2.z);}
|
||||
Vector operator-(Vector v1,Vector v2) {return Vector(v1.x-v2.x,v1.y-v2.y,v1.z-v2.z);}
|
||||
Vector operator-(Vector v) {return Vector(-v.x,-v.y,-v.z);}
|
||||
Vector operator*(Vector v1,float s) {return Vector(v1.x*s,v1.y*s,v1.z*s);}
|
||||
Vector operator*(float s, Vector v1) {return Vector(v1.x*s,v1.y*s,v1.z*s);}
|
||||
Vector operator/(Vector v1,float s) {return v1*(1.0f/s);}
|
||||
float operator^(Vector v1,Vector v2) {return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;}
|
||||
Vector operator*(Vector v1,Vector v2) {
|
||||
return Vector(
|
||||
v1.y * v2.z - v1.z*v2.y,
|
||||
v1.z * v2.x - v1.x*v2.z,
|
||||
v1.x * v2.y - v1.y*v2.x);
|
||||
}
|
||||
Vector planelineintersection(Vector n,float d,Vector p1,Vector p2){
|
||||
// returns the point where the line p1-p2 intersects the plane n&d
|
||||
Vector dif = p2-p1;
|
||||
float dn= n^dif;
|
||||
float t = -(d+(n^p1) )/dn;
|
||||
return p1 + (dif*t);
|
||||
}
|
||||
int concurrent(Vector a,Vector b) {
|
||||
return(a.x==b.x && a.y==b.y && a.z==b.z);
|
||||
}
|
||||
|
||||
|
||||
// Matrix Implementation
|
||||
matrix transpose(matrix m) {
|
||||
return matrix( Vector(m.x.x,m.y.x,m.z.x),
|
||||
Vector(m.x.y,m.y.y,m.z.y),
|
||||
Vector(m.x.z,m.y.z,m.z.z));
|
||||
}
|
||||
Vector operator*(matrix m,Vector v){
|
||||
m=transpose(m); // since column ordered
|
||||
return Vector(m.x^v,m.y^v,m.z^v);
|
||||
}
|
||||
matrix operator*(matrix m1,matrix m2){
|
||||
m1=transpose(m1);
|
||||
return matrix(m1*m2.x,m1*m2.y,m1*m2.z);
|
||||
}
|
||||
|
||||
//Quaternion Implementation
|
||||
Quaternion operator*(Quaternion a,Quaternion b) {
|
||||
Quaternion c;
|
||||
c.r = a.r*b.r - a.x*b.x - a.y*b.y - a.z*b.z;
|
||||
c.x = a.r*b.x + a.x*b.r + a.y*b.z - a.z*b.y;
|
||||
c.y = a.r*b.y - a.x*b.z + a.y*b.r + a.z*b.x;
|
||||
c.z = a.r*b.z + a.x*b.y - a.y*b.x + a.z*b.r;
|
||||
return c;
|
||||
}
|
||||
Quaternion operator-(Quaternion q) {
|
||||
return Quaternion(q.r*-1,q.x,q.y,q.z);
|
||||
}
|
||||
Quaternion operator*(Quaternion a,float b) {
|
||||
return Quaternion(a.r*b, a.x*b, a.y*b, a.z*b);
|
||||
}
|
||||
Vector operator*(Quaternion q,Vector v) {
|
||||
return q.getmatrix() * v;
|
||||
}
|
||||
Vector operator*(Vector v,Quaternion q){
|
||||
assert(0); // must multiply with the quat on the left
|
||||
return Vector(0.0f,0.0f,0.0f);
|
||||
}
|
||||
|
||||
Quaternion operator+(Quaternion a,Quaternion b) {
|
||||
return Quaternion(a.r+b.r, a.x+b.x, a.y+b.y, a.z+b.z);
|
||||
}
|
||||
float operator^(Quaternion a,Quaternion b) {
|
||||
return (a.r*b.r + a.x*b.x + a.y*b.y + a.z*b.z);
|
||||
}
|
||||
Quaternion slerp(Quaternion a,Quaternion b,float interp){
|
||||
if((a^b) <0.0) {
|
||||
a.r=-a.r;
|
||||
a.x=-a.x;
|
||||
a.y=-a.y;
|
||||
a.z=-a.z;
|
||||
}
|
||||
float theta = float(acos(a^b));
|
||||
if(theta==0.0f) { return(a);}
|
||||
return a*float(sin(theta-interp*theta)/sin(theta)) + b*float(sin(interp*theta)/sin(theta));
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "vector.h"
|
||||
|
||||
float sqr(float a) {return a*a;}
|
||||
|
||||
// vector (floating point) implementation
|
||||
|
||||
float magnitude(Vector v) {
|
||||
return float(sqrt(sqr(v.x) + sqr( v.y)+ sqr(v.z)));
|
||||
}
|
||||
Vector normalize(Vector v) {
|
||||
float d=magnitude(v);
|
||||
if (d==0) {
|
||||
printf("Cant normalize ZERO vector\n");
|
||||
assert(0);
|
||||
d=0.1f;
|
||||
}
|
||||
v.x/=d;
|
||||
v.y/=d;
|
||||
v.z/=d;
|
||||
return v;
|
||||
}
|
||||
|
||||
Vector operator+(Vector v1,Vector v2)
|
||||
{
|
||||
return Vector(v1.x+v2.x,v1.y+v2.y,v1.z+v2.z);
|
||||
}
|
||||
Vector operator-(Vector v1,Vector v2)
|
||||
{
|
||||
return Vector(v1.x-v2.x,v1.y-v2.y,v1.z-v2.z);
|
||||
}
|
||||
Vector operator-(Vector v) {return Vector(-v.x,-v.y,-v.z);}
|
||||
Vector operator*(Vector v1,float s) {return Vector(v1.x*s,v1.y*s,v1.z*s);}
|
||||
Vector operator*(float s, Vector v1) {return Vector(v1.x*s,v1.y*s,v1.z*s);}
|
||||
Vector operator/(Vector v1,float s) {return v1*(1.0f/s);}
|
||||
float operator^(Vector v1,Vector v2)
|
||||
{
|
||||
return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
|
||||
}
|
||||
Vector operator*(Vector v1,Vector v2) {
|
||||
return Vector(
|
||||
v1.y * v2.z - v1.z*v2.y,
|
||||
v1.z * v2.x - v1.x*v2.z,
|
||||
v1.x * v2.y - v1.y*v2.x);
|
||||
}
|
||||
Vector planelineintersection(Vector n,float d,Vector p1,Vector p2){
|
||||
// returns the point where the line p1-p2 intersects the plane n&d
|
||||
Vector dif = p2-p1;
|
||||
float dn= n^dif;
|
||||
float t = -(d+(n^p1) )/dn;
|
||||
return p1 + (dif*t);
|
||||
}
|
||||
int concurrent(Vector a,Vector b) {
|
||||
return(a.x==b.x && a.y==b.y && a.z==b.z);
|
||||
}
|
||||
|
||||
|
||||
// Matrix Implementation
|
||||
matrix transpose(matrix m) {
|
||||
return matrix( Vector(m.x.x,m.y.x,m.z.x),
|
||||
Vector(m.x.y,m.y.y,m.z.y),
|
||||
Vector(m.x.z,m.y.z,m.z.z));
|
||||
}
|
||||
Vector operator*(matrix m,Vector v){
|
||||
m=transpose(m); // since column ordered
|
||||
return Vector(m.x^v,m.y^v,m.z^v);
|
||||
}
|
||||
matrix operator*(matrix m1,matrix m2){
|
||||
m1=transpose(m1);
|
||||
return matrix(m1*m2.x,m1*m2.y,m1*m2.z);
|
||||
}
|
||||
|
||||
//Quaternion Implementation
|
||||
Quaternion operator*(Quaternion a,Quaternion b) {
|
||||
Quaternion c;
|
||||
c.r = a.r*b.r - a.x*b.x - a.y*b.y - a.z*b.z;
|
||||
c.x = a.r*b.x + a.x*b.r + a.y*b.z - a.z*b.y;
|
||||
c.y = a.r*b.y - a.x*b.z + a.y*b.r + a.z*b.x;
|
||||
c.z = a.r*b.z + a.x*b.y - a.y*b.x + a.z*b.r;
|
||||
return c;
|
||||
}
|
||||
Quaternion operator-(Quaternion q) {
|
||||
return Quaternion(q.r*-1,q.x,q.y,q.z);
|
||||
}
|
||||
Quaternion operator*(Quaternion a,float b) {
|
||||
return Quaternion(a.r*b, a.x*b, a.y*b, a.z*b);
|
||||
}
|
||||
Vector operator*(Quaternion q,Vector v) {
|
||||
return q.getmatrix() * v;
|
||||
}
|
||||
Vector operator*(Vector v,Quaternion q){
|
||||
assert(0); // must multiply with the quat on the left
|
||||
return Vector(0.0f,0.0f,0.0f);
|
||||
}
|
||||
|
||||
Quaternion operator+(Quaternion a,Quaternion b) {
|
||||
return Quaternion(a.r+b.r, a.x+b.x, a.y+b.y, a.z+b.z);
|
||||
}
|
||||
float operator^(Quaternion a,Quaternion b) {
|
||||
return (a.r*b.r + a.x*b.x + a.y*b.y + a.z*b.z);
|
||||
}
|
||||
Quaternion slerp(Quaternion a,Quaternion b,float interp){
|
||||
if((a^b) <0.0) {
|
||||
a.r=-a.r;
|
||||
a.x=-a.x;
|
||||
a.y=-a.y;
|
||||
a.z=-a.z;
|
||||
}
|
||||
float theta = float(acos(a^b));
|
||||
if(theta==0.0f) { return(a);}
|
||||
return
|
||||
a*float(sin(theta-interp*theta)/sin(theta))
|
||||
+ b*float(sin(interp*theta)/sin(theta));
|
||||
}
|
||||
|
||||
@ -1,66 +1,79 @@
|
||||
//
|
||||
// This module contains a bunch of well understood functions
|
||||
// I apologise if the conventions used here are slightly
|
||||
// different than what you are used to.
|
||||
//
|
||||
|
||||
#ifndef GENERIC_VECTOR_H
|
||||
#define GENERIC_VECTOR_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
class Vector {
|
||||
public:
|
||||
float x,y,z;
|
||||
Vector(float _x=0.0,float _y=0.0,float _z=0.0){x=_x;y=_y;z=_z;};
|
||||
operator float *() { return &x;};
|
||||
};
|
||||
|
||||
float magnitude(Vector v);
|
||||
Vector normalize(Vector v);
|
||||
|
||||
Vector operator+(Vector v1,Vector v2);
|
||||
Vector operator-(Vector v);
|
||||
Vector operator-(Vector v1,Vector v2);
|
||||
Vector operator*(Vector v1,float s) ;
|
||||
Vector operator*(float s,Vector v1) ;
|
||||
Vector operator/(Vector v1,float s) ;
|
||||
float operator^(Vector v1,Vector v2); // DOT product
|
||||
Vector operator*(Vector v1,Vector v2); // CROSS product
|
||||
Vector planelineintersection(Vector n,float d,Vector p1,Vector p2);
|
||||
|
||||
class matrix{
|
||||
public:
|
||||
Vector x,y,z;
|
||||
matrix(){x=Vector(1.0f,0.0f,0.0f);
|
||||
y=Vector(0.0f,1.0f,0.0f);
|
||||
z=Vector(0.0f,0.0f,1.0f);};
|
||||
matrix(Vector _x,Vector _y,Vector _z){x=_x;y=_y;z=_z;};
|
||||
};
|
||||
matrix transpose(matrix m);
|
||||
Vector operator*(matrix m,Vector v);
|
||||
matrix operator*(matrix m1,matrix m2);
|
||||
|
||||
class Quaternion{
|
||||
public:
|
||||
float r,x,y,z;
|
||||
Quaternion(){x=y=z=0.0f;r=1.0f;};
|
||||
Quaternion(Vector v,float t){v=normalize(v);r=float(cos(t/2.0));v=v*float(sin(t/2.0));x=v.x;y=v.y;z=v.z;};
|
||||
Quaternion(float _r,float _x,float _y,float _z){r=_r;x=_x;y=_y;z=_z;};
|
||||
float angle(){return float(acos(r)*2.0);}
|
||||
Vector axis(){Vector a(x,y,z); return a*float(1/sin(angle()/2.0));}
|
||||
Vector xdir(){return Vector(1-2*(y*y+z*z), 2*(x*y+r*z), 2*(x*z-r*y));}
|
||||
Vector ydir(){return Vector( 2*(x*y-r*z),1-2*(x*x+z*z), 2*(y*z+r*x));}
|
||||
Vector zdir(){return Vector( 2*(x*z+r*y), 2*(y*z-r*x),1-2*(x*x+y*y));}
|
||||
matrix getmatrix(){return matrix(xdir(),ydir(),zdir());}
|
||||
//operator matrix(){return getmatrix();}
|
||||
};
|
||||
Quaternion operator-(Quaternion q);
|
||||
Quaternion operator*(Quaternion a,Quaternion b);
|
||||
Vector operator*(Quaternion q,Vector v);
|
||||
Vector operator*(Vector v,Quaternion q);
|
||||
Quaternion slerp(Quaternion a,Quaternion b,float interp);
|
||||
|
||||
#endif
|
||||
//
|
||||
// This module contains a bunch of well understood functions
|
||||
// I apologise if the conventions used here are slightly
|
||||
// different than what you are used to.
|
||||
//
|
||||
|
||||
#ifndef GENERIC_VECTOR_H
|
||||
#define GENERIC_VECTOR_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
class Vector {
|
||||
public:
|
||||
float x,y,z;
|
||||
Vector(float _x=0.0,float _y=0.0,float _z=0.0){x=_x;y=_y;z=_z;};
|
||||
operator float *() { return &x;};
|
||||
};
|
||||
|
||||
float magnitude(Vector v);
|
||||
Vector normalize(Vector v);
|
||||
|
||||
Vector operator+(Vector v1,Vector v2);
|
||||
Vector operator-(Vector v);
|
||||
Vector operator-(Vector v1,Vector v2);
|
||||
Vector operator*(Vector v1,float s) ;
|
||||
Vector operator*(float s,Vector v1) ;
|
||||
Vector operator/(Vector v1,float s) ;
|
||||
float operator^(Vector v1,Vector v2); // DOT product
|
||||
Vector operator*(Vector v1,Vector v2); // CROSS product
|
||||
Vector planelineintersection(Vector n,float d,Vector p1,Vector p2);
|
||||
|
||||
class matrix{
|
||||
public:
|
||||
Vector x,y,z;
|
||||
matrix(){x=Vector(1.0f,0.0f,0.0f);
|
||||
y=Vector(0.0f,1.0f,0.0f);
|
||||
z=Vector(0.0f,0.0f,1.0f);};
|
||||
matrix(Vector _x,Vector _y,Vector _z){x=_x;y=_y;z=_z;};
|
||||
};
|
||||
matrix transpose(matrix m);
|
||||
Vector operator*(matrix m,Vector v);
|
||||
matrix operator*(matrix m1,matrix m2);
|
||||
|
||||
class Quaternion{
|
||||
public:
|
||||
float r,x,y,z;
|
||||
Quaternion(){x=y=z=0.0f;r=1.0f;};
|
||||
Quaternion(Vector v,float t){
|
||||
v=normalize(v);
|
||||
r=float(cos(t/2.0));
|
||||
v=v*float(sin(t/2.0));
|
||||
x=v.x;
|
||||
y=v.y;
|
||||
z=v.z;
|
||||
};
|
||||
Quaternion(float _r,float _x,float _y,float _z){r=_r;x=_x;y=_y;z=_z;};
|
||||
float angle(){return float(acos(r)*2.0);}
|
||||
Vector axis(){Vector a(x,y,z); return a*float(1/sin(angle()/2.0));}
|
||||
Vector xdir(){
|
||||
return Vector(1-2*(y*y+z*z), 2*(x*y+r*z), 2*(x*z-r*y));
|
||||
}
|
||||
Vector ydir(){
|
||||
return Vector( 2*(x*y-r*z),1-2*(x*x+z*z), 2*(y*z+r*x));
|
||||
}
|
||||
Vector zdir(){
|
||||
return Vector( 2*(x*z+r*y), 2*(y*z-r*x),1-2*(x*x+y*y));
|
||||
}
|
||||
matrix getmatrix(){return matrix(xdir(),ydir(),zdir());}
|
||||
//operator matrix(){return getmatrix();}
|
||||
};
|
||||
Quaternion operator-(Quaternion q);
|
||||
Quaternion operator*(Quaternion a,Quaternion b);
|
||||
Vector operator*(Quaternion q,Vector v);
|
||||
Vector operator*(Vector v,Quaternion q);
|
||||
Quaternion slerp(Quaternion a,Quaternion b,float interp);
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,155 +1,155 @@
|
||||
|
||||
/*
|
||||
* 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 contains the window setup code, mouse input, timing
|
||||
* routines, and that sort of stuff. The interesting modules
|
||||
* to see are bunnygut.cpp and progmesh.cpp.
|
||||
*
|
||||
* The windows 95 specific code for this application was taken from
|
||||
/*
|
||||
* 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 contains the window setup code, mouse input, timing
|
||||
* routines, and that sort of stuff. The interesting modules
|
||||
* to see are bunnygut.cpp and progmesh.cpp.
|
||||
*
|
||||
* The windows 95 specific code for this application was taken from
|
||||
* an example of processing mouse events in an OpenGL program using
|
||||
* the Win32 API from the www.opengl.org web site.
|
||||
*
|
||||
* Under Project->Settings, Link Options, General Category
|
||||
* Add:
|
||||
* Opengl32.lib glu32.lib winmm.lib
|
||||
* to the Object/Library Modules
|
||||
*
|
||||
* You will need have OpenGL libs and include files to compile this
|
||||
* Go to the www.opengl.org web site if you need help with this.
|
||||
* the Win32 API from the www.opengl.org web site.
|
||||
*
|
||||
* Under Project->Settings, Link Options, General Category
|
||||
* Add:
|
||||
* Opengl32.lib glu32.lib winmm.lib
|
||||
* to the Object/Library Modules
|
||||
*
|
||||
* You will need have OpenGL libs and include files to compile this
|
||||
* Go to the www.opengl.org web site if you need help with this.
|
||||
*/
|
||||
|
||||
|
||||
#include <windows.h> /* must include this before GL/gl.h */
|
||||
#include <GL/gl.h> /* OpenGL header file */
|
||||
#include <GL/glu.h> /* OpenGL utilities header file */
|
||||
#include <windows.h> /* must include this before GL/gl.h */
|
||||
#include <GL/gl.h> /* OpenGL header file */
|
||||
#include <GL/glu.h> /* OpenGL utilities header file */
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/timeb.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "vector.h"
|
||||
#include "font.h"
|
||||
|
||||
// Functions and Variables from bunny module
|
||||
extern void InitModel();
|
||||
extern void RenderModel();
|
||||
extern Vector model_position; // position of bunny
|
||||
extern Quaternion model_orientation; // orientation of bunny
|
||||
|
||||
// Global Variables
|
||||
float DeltaT = 0.1f;
|
||||
float FPS;
|
||||
int Width = 512;
|
||||
int Height = 512;
|
||||
int MouseX = 0;
|
||||
int MouseY = 0;
|
||||
Vector MouseVector; // 3D direction mouse points
|
||||
Vector OldMouseVector;
|
||||
int MouseState=0; // true iff left button down
|
||||
float ViewAngle=45.0f;
|
||||
|
||||
HDC hDC; /* device context */
|
||||
HPALETTE hPalette = 0; /* custom palette (if needed) */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/timeb.h>
|
||||
#include <time.h>
|
||||
|
||||
void CalcFPSDeltaT(){
|
||||
static int timeinit=0;
|
||||
static int start,start2,current,last;
|
||||
static int frame=0, frame2=0;
|
||||
if(!timeinit){
|
||||
frame=0;
|
||||
start=timeGetTime();
|
||||
timeinit=1;
|
||||
}
|
||||
frame++;
|
||||
frame2++;
|
||||
current=timeGetTime(); // found in winmm.lib
|
||||
double dif=(double)(current-start)/CLOCKS_PER_SEC;
|
||||
double rv = (dif)? (double)frame/(double)dif:-1.0;
|
||||
if(dif>2.0 && frame >10) {
|
||||
start = start2;
|
||||
frame = frame2;
|
||||
start2 = timeGetTime();
|
||||
frame2 = 0;
|
||||
}
|
||||
DeltaT = (float)(current-last)/CLOCKS_PER_SEC;
|
||||
if(current==last) {
|
||||
DeltaT = 0.1f/CLOCKS_PER_SEC; // it just cant be 0
|
||||
}
|
||||
// if(DeltaT>1.0) DeltaT=1.0;
|
||||
FPS = (float)rv;
|
||||
last = current;
|
||||
}
|
||||
|
||||
|
||||
void ComputeMouseVector(){
|
||||
OldMouseVector=MouseVector;
|
||||
float spread = (float)tan(ViewAngle/2*3.14/180);
|
||||
float y = spread * ((Height-MouseY)-Height/2.0f) /(Height/2.0f);
|
||||
float x = spread * (MouseX-Width/2.0f) /(Height/2.0f);
|
||||
Vector v(x ,y,-1);
|
||||
// v=UserOrientation *v;
|
||||
v=normalize(v);
|
||||
MouseVector = v;
|
||||
}
|
||||
|
||||
Quaternion VirtualTrackBall(Vector cop,Vector cor,Vector dir1,Vector dir2) {
|
||||
// Implement track ball functionality to spin stuf on the screen
|
||||
// cop center of projection
|
||||
// cor center of rotation
|
||||
// dir1 old mouse direction
|
||||
// dir2 new mouse direction
|
||||
// pretend there is a sphere around cor. Then find the points
|
||||
// where dir1 and dir2 intersect that sphere. Find the
|
||||
// rotation that takes the first point to the second.
|
||||
float m;
|
||||
// compute plane
|
||||
Vector nrml = cor - cop;
|
||||
float fudgefactor = 1.0f/(magnitude(nrml) * 0.25f); // since trackball proportional to distance from cop
|
||||
nrml = normalize(nrml);
|
||||
float dist = -(nrml^cor);
|
||||
Vector u= planelineintersection(nrml,dist,cop,cop+dir1);
|
||||
u=u-cor;
|
||||
u=u*fudgefactor;
|
||||
m= magnitude(u);
|
||||
if(m>1) {u=u*1.0f/m;}
|
||||
else {
|
||||
u=u - (nrml * (float)sqrt(1-m*m));
|
||||
}
|
||||
Vector v= planelineintersection(nrml,dist,cop,cop+dir2);
|
||||
v=v-cor;
|
||||
v=v*fudgefactor;
|
||||
m= magnitude(v);
|
||||
if(m>1) {v=v*1.0f/m;}
|
||||
else {
|
||||
v=v - (nrml * (float)sqrt(1-m*m));
|
||||
}
|
||||
Vector axis = u*v;
|
||||
float angle;
|
||||
m=magnitude(axis);
|
||||
if(m>1)m=1; // avoid potential floating point error
|
||||
Quaternion q(Vector(1.0f,0.0f,0.0f),0.0f);
|
||||
if(m>0 && (angle=(float)asin(m))>3.14/180) {
|
||||
axis = normalize(axis);
|
||||
q=Quaternion(axis,angle);
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
void SpinIt(){
|
||||
// Change the orientation of the bunny according to mouse drag
|
||||
Quaternion q=VirtualTrackBall(Vector(0,0,0),model_position,
|
||||
OldMouseVector,MouseVector);
|
||||
model_orientation=q*model_orientation;
|
||||
}
|
||||
|
||||
void Reshape(int width, int height){
|
||||
// called initially and when the window changes size
|
||||
Width=width;
|
||||
Height=height;
|
||||
#include "vector.h"
|
||||
#include "font.h"
|
||||
|
||||
// Functions and Variables from bunny module
|
||||
extern void InitModel();
|
||||
extern void RenderModel();
|
||||
extern Vector model_position; // position of bunny
|
||||
extern Quaternion model_orientation; // orientation of bunny
|
||||
|
||||
// Global Variables
|
||||
float DeltaT = 0.1f;
|
||||
float FPS;
|
||||
int Width = 512;
|
||||
int Height = 512;
|
||||
int MouseX = 0;
|
||||
int MouseY = 0;
|
||||
Vector MouseVector; // 3D direction mouse points
|
||||
Vector OldMouseVector;
|
||||
int MouseState=0; // true iff left button down
|
||||
float ViewAngle=45.0f;
|
||||
|
||||
HDC hDC; /* device context */
|
||||
HPALETTE hPalette = 0; /* custom palette (if needed) */
|
||||
|
||||
|
||||
void CalcFPSDeltaT(){
|
||||
static int timeinit=0;
|
||||
static int start,start2,current,last;
|
||||
static int frame=0, frame2=0;
|
||||
if(!timeinit){
|
||||
frame=0;
|
||||
start=timeGetTime();
|
||||
timeinit=1;
|
||||
}
|
||||
frame++;
|
||||
frame2++;
|
||||
current=timeGetTime(); // found in winmm.lib
|
||||
double dif=(double)(current-start)/CLOCKS_PER_SEC;
|
||||
double rv = (dif)? (double)frame/(double)dif:-1.0;
|
||||
if(dif>2.0 && frame >10) {
|
||||
start = start2;
|
||||
frame = frame2;
|
||||
start2 = timeGetTime();
|
||||
frame2 = 0;
|
||||
}
|
||||
DeltaT = (float)(current-last)/CLOCKS_PER_SEC;
|
||||
if(current==last) {
|
||||
DeltaT = 0.1f/CLOCKS_PER_SEC; // it just cant be 0
|
||||
}
|
||||
// if(DeltaT>1.0) DeltaT=1.0;
|
||||
FPS = (float)rv;
|
||||
last = current;
|
||||
}
|
||||
|
||||
|
||||
void ComputeMouseVector(){
|
||||
OldMouseVector=MouseVector;
|
||||
float spread = (float)tan(ViewAngle/2*3.14/180);
|
||||
float y = spread * ((Height-MouseY)-Height/2.0f) /(Height/2.0f);
|
||||
float x = spread * (MouseX-Width/2.0f) /(Height/2.0f);
|
||||
Vector v(x ,y,-1);
|
||||
// v=UserOrientation *v;
|
||||
v=normalize(v);
|
||||
MouseVector = v;
|
||||
}
|
||||
|
||||
Quaternion VirtualTrackBall(Vector cop,Vector cor,Vector dir1,Vector dir2) {
|
||||
// Implement track ball functionality to spin stuf on the screen
|
||||
// cop center of projection
|
||||
// cor center of rotation
|
||||
// dir1 old mouse direction
|
||||
// dir2 new mouse direction
|
||||
// pretend there is a sphere around cor. Then find the points
|
||||
// where dir1 and dir2 intersect that sphere. Find the
|
||||
// rotation that takes the first point to the second.
|
||||
float m;
|
||||
// compute plane
|
||||
Vector nrml = cor - cop;
|
||||
// since trackball proportional to distance from cop
|
||||
float fudgefactor = 1.0f/(magnitude(nrml) * 0.25f);
|
||||
nrml = normalize(nrml);
|
||||
float dist = -(nrml^cor);
|
||||
Vector u= planelineintersection(nrml,dist,cop,cop+dir1);
|
||||
u=u-cor;
|
||||
u=u*fudgefactor;
|
||||
m= magnitude(u);
|
||||
if(m>1) {u=u*1.0f/m;}
|
||||
else {
|
||||
u=u - (nrml * (float)sqrt(1-m*m));
|
||||
}
|
||||
Vector v= planelineintersection(nrml,dist,cop,cop+dir2);
|
||||
v=v-cor;
|
||||
v=v*fudgefactor;
|
||||
m= magnitude(v);
|
||||
if(m>1) {v=v*1.0f/m;}
|
||||
else {
|
||||
v=v - (nrml * (float)sqrt(1-m*m));
|
||||
}
|
||||
Vector axis = u*v;
|
||||
float angle;
|
||||
m=magnitude(axis);
|
||||
if(m>1)m=1; // avoid potential floating point error
|
||||
Quaternion q(Vector(1.0f,0.0f,0.0f),0.0f);
|
||||
if(m>0 && (angle=(float)asin(m))>3.14/180) {
|
||||
axis = normalize(axis);
|
||||
q=Quaternion(axis,angle);
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
void SpinIt(){
|
||||
// Change the orientation of the bunny according to mouse drag
|
||||
Quaternion q=VirtualTrackBall(Vector(0,0,0),model_position,
|
||||
OldMouseVector,MouseVector);
|
||||
model_orientation=q*model_orientation;
|
||||
}
|
||||
|
||||
void Reshape(int width, int height){
|
||||
// called initially and when the window changes size
|
||||
Width=width;
|
||||
Height=height;
|
||||
glViewport(0, 0, width, height);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
@ -157,111 +157,111 @@ void Reshape(int width, int height){
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
void PrintStats(){
|
||||
char buf[1024];buf[0]='\0';
|
||||
sprintf(buf,"FPS: %5.2f ",FPS);
|
||||
PostString(buf,0,-1,0);
|
||||
}
|
||||
|
||||
void Display(){
|
||||
// main drawing routine - called every frame
|
||||
|
||||
void PrintStats(){
|
||||
char buf[1024];buf[0]='\0';
|
||||
sprintf(buf,"FPS: %5.2f ",FPS);
|
||||
PostString(buf,0,-1,0);
|
||||
}
|
||||
|
||||
void Display(){
|
||||
// main drawing routine - called every frame
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
// camera at default (zero) position and orientation
|
||||
RenderModel();
|
||||
PrintStats();
|
||||
glLoadIdentity();
|
||||
RenderStrings();
|
||||
glPopMatrix();
|
||||
glLoadIdentity();
|
||||
// camera at default (zero) position and orientation
|
||||
RenderModel();
|
||||
PrintStats();
|
||||
glLoadIdentity();
|
||||
RenderStrings();
|
||||
glPopMatrix();
|
||||
glFlush();
|
||||
SwapBuffers(hDC); /* nop if singlebuffered */
|
||||
SwapBuffers(hDC); /* nop if singlebuffered */
|
||||
}
|
||||
|
||||
|
||||
LONG WINAPI WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
{
|
||||
static PAINTSTRUCT ps;
|
||||
static GLboolean left = GL_FALSE; /* left button currently down? */
|
||||
static GLboolean right = GL_FALSE; /* right button currently down? */
|
||||
static GLboolean left = GL_FALSE; /* left button currently down? */
|
||||
static GLboolean right = GL_FALSE; /* right button currently down? */
|
||||
static int omx, omy, mx, my;
|
||||
|
||||
switch(uMsg) {
|
||||
case WM_PAINT:
|
||||
BeginPaint(hWnd, &ps);
|
||||
EndPaint(hWnd, &ps);
|
||||
return 0;
|
||||
BeginPaint(hWnd, &ps);
|
||||
EndPaint(hWnd, &ps);
|
||||
return 0;
|
||||
case WM_SIZE:
|
||||
Reshape(LOWORD(lParam), HIWORD(lParam));
|
||||
PostMessage(hWnd, WM_PAINT, 0, 0);
|
||||
return 0;
|
||||
Reshape(LOWORD(lParam), HIWORD(lParam));
|
||||
PostMessage(hWnd, WM_PAINT, 0, 0);
|
||||
return 0;
|
||||
case WM_CHAR:
|
||||
switch (wParam) {
|
||||
case 27: /* ESC key */
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
/* if we don't set the capture we won't get mouse move
|
||||
switch (wParam) {
|
||||
case 27: /* ESC key */
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
/* if we don't set the capture we won't get mouse move
|
||||
messages when the mouse moves outside the window. */
|
||||
SetCapture(hWnd);
|
||||
MouseX = LOWORD(lParam);
|
||||
MouseY = HIWORD(lParam);
|
||||
ComputeMouseVector();
|
||||
MouseState = 1;
|
||||
return 0;
|
||||
SetCapture(hWnd);
|
||||
MouseX = LOWORD(lParam);
|
||||
MouseY = HIWORD(lParam);
|
||||
ComputeMouseVector();
|
||||
MouseState = 1;
|
||||
return 0;
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
MouseX = LOWORD(lParam);
|
||||
MouseY = HIWORD(lParam);
|
||||
if(MouseX & 1 << 15) MouseX -= (1 << 16);
|
||||
if(MouseY & 1 << 15) MouseY -= (1 << 16);
|
||||
ComputeMouseVector();
|
||||
if(MouseState) SpinIt();
|
||||
MouseState=0;
|
||||
/* remember to release the capture when we are finished. */
|
||||
ReleaseCapture();
|
||||
return 0;
|
||||
MouseX = LOWORD(lParam);
|
||||
MouseY = HIWORD(lParam);
|
||||
if(MouseX & 1 << 15) MouseX -= (1 << 16);
|
||||
if(MouseY & 1 << 15) MouseY -= (1 << 16);
|
||||
ComputeMouseVector();
|
||||
if(MouseState) SpinIt();
|
||||
MouseState=0;
|
||||
/* remember to release the capture when we are finished. */
|
||||
ReleaseCapture();
|
||||
return 0;
|
||||
|
||||
case WM_MOUSEMOVE:
|
||||
MouseX = LOWORD(lParam);
|
||||
MouseY = HIWORD(lParam);
|
||||
/* Win32 is pretty braindead about the x, y position that
|
||||
it returns when the mouse is off the left or top edge
|
||||
of the window (due to them being unsigned). therefore,
|
||||
roll the Win32's 0..2^16 pointer co-ord range to the
|
||||
more amenable (and useful) 0..+/-2^15. */
|
||||
if(MouseX & 1 << 15) MouseX -= (1 << 16);
|
||||
if(MouseY & 1 << 15) MouseY -= (1 << 16);
|
||||
ComputeMouseVector();
|
||||
if(MouseState) SpinIt();
|
||||
return 0;
|
||||
MouseX = LOWORD(lParam);
|
||||
MouseY = HIWORD(lParam);
|
||||
/* Win32 is pretty braindead about the x, y position that
|
||||
it returns when the mouse is off the left or top edge
|
||||
of the window (due to them being unsigned). therefore,
|
||||
roll the Win32's 0..2^16 pointer co-ord range to the
|
||||
more amenable (and useful) 0..+/-2^15. */
|
||||
if(MouseX & 1 << 15) MouseX -= (1 << 16);
|
||||
if(MouseY & 1 << 15) MouseY -= (1 << 16);
|
||||
ComputeMouseVector();
|
||||
if(MouseState) SpinIt();
|
||||
return 0;
|
||||
|
||||
case WM_PALETTECHANGED:
|
||||
if (hWnd == (HWND)wParam) break;
|
||||
/* fall through to WM_QUERYNEWPALETTE */
|
||||
if (hWnd == (HWND)wParam) break;
|
||||
/* fall through to WM_QUERYNEWPALETTE */
|
||||
case WM_QUERYNEWPALETTE:
|
||||
if (hPalette) {
|
||||
UnrealizeObject(hPalette);
|
||||
SelectPalette(hDC, hPalette, FALSE);
|
||||
RealizePalette(hDC);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
if (hPalette) {
|
||||
UnrealizeObject(hPalette);
|
||||
SelectPalette(hDC, hPalette, FALSE);
|
||||
RealizePalette(hDC);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
case WM_CLOSE:
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
}
|
||||
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
HWND CreateOpenGLWindow(char* title)
|
||||
{
|
||||
// make a double-buffered, rgba, opengl window
|
||||
// make a double-buffered, rgba, opengl window
|
||||
int n, pf;
|
||||
HWND hWnd;
|
||||
WNDCLASS wc;
|
||||
@ -271,33 +271,35 @@ HWND CreateOpenGLWindow(char* title)
|
||||
|
||||
/* only register the window class once - use hInstance as a flag. */
|
||||
if (!hInstance) {
|
||||
hInstance = GetModuleHandle(NULL);
|
||||
wc.style = CS_OWNDC;
|
||||
wc.lpfnWndProc = (WNDPROC)WindowProc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = hInstance;
|
||||
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.hbrBackground = NULL;
|
||||
wc.lpszMenuName = NULL;
|
||||
wc.lpszClassName = "OpenGL";
|
||||
hInstance = GetModuleHandle(NULL);
|
||||
wc.style = CS_OWNDC;
|
||||
wc.lpfnWndProc = (WNDPROC)WindowProc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = hInstance;
|
||||
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.hbrBackground = NULL;
|
||||
wc.lpszMenuName = NULL;
|
||||
wc.lpszClassName = "OpenGL";
|
||||
|
||||
if (!RegisterClass(&wc)) {
|
||||
MessageBox(NULL, "RegisterClass() failed: "
|
||||
"Cannot register window class.", "Error", MB_OK);
|
||||
return NULL;
|
||||
}
|
||||
if (!RegisterClass(&wc)) {
|
||||
MessageBox(NULL, "RegisterClass() failed: "
|
||||
"Cannot register window class.",
|
||||
"Error", MB_OK);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
hWnd = CreateWindow("OpenGL", title, WS_OVERLAPPEDWINDOW |
|
||||
WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
|
||||
0,0,Width,Height, NULL, NULL, hInstance, NULL);
|
||||
WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
|
||||
0,0,Width,Height, NULL, NULL, hInstance, NULL);
|
||||
|
||||
if (hWnd == NULL) {
|
||||
MessageBox(NULL, "CreateWindow() failed: Cannot create a window.",
|
||||
"Error", MB_OK);
|
||||
return NULL;
|
||||
MessageBox(NULL,
|
||||
"CreateWindow() failed: Cannot create a window.",
|
||||
"Error", MB_OK);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hDC = GetDC(hWnd);
|
||||
@ -307,134 +309,141 @@ HWND CreateOpenGLWindow(char* title)
|
||||
memset(&pfd, 0, sizeof(pfd));
|
||||
pfd.nSize = sizeof(pfd);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
||||
pfd.dwFlags = PFD_DRAW_TO_WINDOW
|
||||
| PFD_SUPPORT_OPENGL
|
||||
| PFD_DOUBLEBUFFER;
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.cDepthBits = 32;
|
||||
pfd.cColorBits = 32;
|
||||
|
||||
pf = ChoosePixelFormat(hDC, &pfd);
|
||||
if (pf == 0) {
|
||||
MessageBox(NULL, "ChoosePixelFormat() failed: "
|
||||
"Cannot find a suitable pixel format.", "Error", MB_OK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MessageBox(NULL, "ChoosePixelFormat() failed: "
|
||||
"Cannot find a suitable pixel format.",
|
||||
"Error", MB_OK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (SetPixelFormat(hDC, pf, &pfd) == FALSE) {
|
||||
MessageBox(NULL, "SetPixelFormat() failed: "
|
||||
"Cannot set format specified.", "Error", MB_OK);
|
||||
return 0;
|
||||
}
|
||||
MessageBox(NULL, "SetPixelFormat() failed: "
|
||||
"Cannot set format specified.", "Error", MB_OK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
|
||||
|
||||
if (pfd.dwFlags & PFD_NEED_PALETTE ||
|
||||
pfd.iPixelType == PFD_TYPE_COLORINDEX) {
|
||||
pfd.iPixelType == PFD_TYPE_COLORINDEX) {
|
||||
|
||||
n = 1 << pfd.cColorBits;
|
||||
if (n > 256) n = 256;
|
||||
n = 1 << pfd.cColorBits;
|
||||
if (n > 256) n = 256;
|
||||
|
||||
lpPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +
|
||||
sizeof(PALETTEENTRY) * n);
|
||||
memset(lpPal, 0, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * n);
|
||||
lpPal->palVersion = 0x300;
|
||||
lpPal->palNumEntries = n;
|
||||
lpPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +
|
||||
sizeof(PALETTEENTRY) * n);
|
||||
memset(lpPal, 0, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * n);
|
||||
lpPal->palVersion = 0x300;
|
||||
lpPal->palNumEntries = n;
|
||||
|
||||
GetSystemPaletteEntries(hDC, 0, n, &lpPal->palPalEntry[0]);
|
||||
|
||||
/* if the pixel type is RGBA, then we want to make an RGB ramp,
|
||||
otherwise (color index) set individual colors. */
|
||||
if (pfd.iPixelType == PFD_TYPE_RGBA) {
|
||||
int redMask = (1 << pfd.cRedBits) - 1;
|
||||
int greenMask = (1 << pfd.cGreenBits) - 1;
|
||||
int blueMask = (1 << pfd.cBlueBits) - 1;
|
||||
int i;
|
||||
GetSystemPaletteEntries(hDC, 0, n, &lpPal->palPalEntry[0]);
|
||||
|
||||
/* fill in the entries with an RGB color ramp. */
|
||||
for (i = 0; i < n; ++i) {
|
||||
lpPal->palPalEntry[i].peRed =
|
||||
(((i >> pfd.cRedShift) & redMask) * 255)/redMask;
|
||||
lpPal->palPalEntry[i].peGreen =
|
||||
(((i >> pfd.cGreenShift) & greenMask) * 255)/greenMask;
|
||||
lpPal->palPalEntry[i].peBlue =
|
||||
(((i >> pfd.cBlueShift) & blueMask) * 255)/blueMask;
|
||||
lpPal->palPalEntry[i].peFlags = 0;
|
||||
}
|
||||
} else {
|
||||
lpPal->palPalEntry[0].peRed = 0;
|
||||
lpPal->palPalEntry[0].peGreen = 0;
|
||||
lpPal->palPalEntry[0].peBlue = 0;
|
||||
lpPal->palPalEntry[0].peFlags = PC_NOCOLLAPSE;
|
||||
lpPal->palPalEntry[1].peRed = 255;
|
||||
lpPal->palPalEntry[1].peGreen = 0;
|
||||
lpPal->palPalEntry[1].peBlue = 0;
|
||||
lpPal->palPalEntry[1].peFlags = PC_NOCOLLAPSE;
|
||||
lpPal->palPalEntry[2].peRed = 0;
|
||||
lpPal->palPalEntry[2].peGreen = 255;
|
||||
lpPal->palPalEntry[2].peBlue = 0;
|
||||
lpPal->palPalEntry[2].peFlags = PC_NOCOLLAPSE;
|
||||
lpPal->palPalEntry[3].peRed = 0;
|
||||
lpPal->palPalEntry[3].peGreen = 0;
|
||||
lpPal->palPalEntry[3].peBlue = 255;
|
||||
lpPal->palPalEntry[3].peFlags = PC_NOCOLLAPSE;
|
||||
}
|
||||
/* if the pixel type is RGBA, then we want to make an RGB ramp,
|
||||
otherwise (color index) set individual colors. */
|
||||
if (pfd.iPixelType == PFD_TYPE_RGBA) {
|
||||
int redMask = (1 << pfd.cRedBits) - 1;
|
||||
int greenMask = (1 << pfd.cGreenBits) - 1;
|
||||
int blueMask = (1 << pfd.cBlueBits) - 1;
|
||||
int i;
|
||||
|
||||
hPalette = CreatePalette(lpPal);
|
||||
if (hPalette) {
|
||||
SelectPalette(hDC, hPalette, FALSE);
|
||||
RealizePalette(hDC);
|
||||
}
|
||||
/* fill in the entries with an RGB color ramp. */
|
||||
for (i = 0; i < n; ++i) {
|
||||
lpPal->palPalEntry[i].peRed =
|
||||
(((i >> pfd.cRedShift) & redMask) * 255)
|
||||
/redMask;
|
||||
lpPal->palPalEntry[i].peGreen =
|
||||
(((i >> pfd.cGreenShift) & greenMask) * 255)
|
||||
/greenMask;
|
||||
lpPal->palPalEntry[i].peBlue =
|
||||
(((i >> pfd.cBlueShift) & blueMask) * 255)
|
||||
/blueMask;
|
||||
lpPal->palPalEntry[i].peFlags = 0;
|
||||
}
|
||||
} else {
|
||||
lpPal->palPalEntry[0].peRed = 0;
|
||||
lpPal->palPalEntry[0].peGreen = 0;
|
||||
lpPal->palPalEntry[0].peBlue = 0;
|
||||
lpPal->palPalEntry[0].peFlags = PC_NOCOLLAPSE;
|
||||
lpPal->palPalEntry[1].peRed = 255;
|
||||
lpPal->palPalEntry[1].peGreen = 0;
|
||||
lpPal->palPalEntry[1].peBlue = 0;
|
||||
lpPal->palPalEntry[1].peFlags = PC_NOCOLLAPSE;
|
||||
lpPal->palPalEntry[2].peRed = 0;
|
||||
lpPal->palPalEntry[2].peGreen = 255;
|
||||
lpPal->palPalEntry[2].peBlue = 0;
|
||||
lpPal->palPalEntry[2].peFlags = PC_NOCOLLAPSE;
|
||||
lpPal->palPalEntry[3].peRed = 0;
|
||||
lpPal->palPalEntry[3].peGreen = 0;
|
||||
lpPal->palPalEntry[3].peBlue = 255;
|
||||
lpPal->palPalEntry[3].peFlags = PC_NOCOLLAPSE;
|
||||
}
|
||||
|
||||
free(lpPal);
|
||||
hPalette = CreatePalette(lpPal);
|
||||
if (hPalette) {
|
||||
SelectPalette(hDC, hPalette, FALSE);
|
||||
RealizePalette(hDC);
|
||||
}
|
||||
|
||||
free(lpPal);
|
||||
}
|
||||
|
||||
ReleaseDC(hDC, hWnd);
|
||||
return hWnd;
|
||||
}
|
||||
}
|
||||
|
||||
int APIENTRY WinMain(HINSTANCE hCurrentInst, HINSTANCE hPreviousInst,
|
||||
LPSTR lpszCmdLine, int nCmdShow)
|
||||
LPSTR lpszCmdLine, int nCmdShow)
|
||||
{
|
||||
HGLRC hRC; /* opengl context */
|
||||
HWND hWnd; /* window */
|
||||
MSG msg; /* message */
|
||||
HGLRC hRC; /* opengl context */
|
||||
HWND hWnd; /* window */
|
||||
MSG msg; /* message */
|
||||
|
||||
// InitModel() initializes some data structures and
|
||||
// does the progressive mesh polygon reduction algorithm
|
||||
// on the model.
|
||||
CalcFPSDeltaT(); // to time the algorithm
|
||||
InitModel();
|
||||
CalcFPSDeltaT();
|
||||
|
||||
hWnd = CreateOpenGLWindow("bunnylod by Stan Melax");
|
||||
// InitModel() initializes some data structures and
|
||||
// does the progressive mesh polygon reduction algorithm
|
||||
// on the model.
|
||||
CalcFPSDeltaT(); // to time the algorithm
|
||||
InitModel();
|
||||
CalcFPSDeltaT();
|
||||
|
||||
hWnd = CreateOpenGLWindow("bunnylod by Stan Melax");
|
||||
if (hWnd == NULL) exit(1);
|
||||
|
||||
hDC = GetDC(hWnd);
|
||||
hRC = wglCreateContext(hDC);
|
||||
wglMakeCurrent(hDC, hRC);
|
||||
ShowWindow(hWnd, nCmdShow);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
PostString("Demo by Stan Melax (c)1998",5,-5,20);
|
||||
PostString("Model by Viewpoint Datalabs (c)1996",5,-4,20);
|
||||
char buf[128];
|
||||
PostString("Mesh Reduction Algorithm (non-optimized)",1,0,5);
|
||||
sprintf(buf,"was executed in %5.3f seconds",DeltaT);
|
||||
PostString(buf,2,1,6);
|
||||
|
||||
while (1) {
|
||||
while(PeekMessage(&msg, hWnd, 0, 0, PM_NOREMOVE)) {
|
||||
if(GetMessage(&msg, hWnd, 0, 0)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
} else {
|
||||
goto quit; // This 'goto' was in the sample code
|
||||
}
|
||||
}
|
||||
CalcFPSDeltaT();
|
||||
Display();
|
||||
}
|
||||
|
||||
quit:
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
PostString("Demo by Stan Melax (c)1998",5,-5,20);
|
||||
PostString("Model by Viewpoint Datalabs (c)1996",5,-4,20);
|
||||
char buf[128];
|
||||
PostString("Mesh Reduction Algorithm (non-optimized)",1,0,5);
|
||||
sprintf(buf,"was executed in %5.3f seconds",DeltaT);
|
||||
PostString(buf,2,1,6);
|
||||
|
||||
while (1) {
|
||||
while(PeekMessage(&msg, hWnd, 0, 0, PM_NOREMOVE)) {
|
||||
if(GetMessage(&msg, hWnd, 0, 0)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
} else {
|
||||
// This 'goto' was in the sample code
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
CalcFPSDeltaT();
|
||||
Display();
|
||||
}
|
||||
|
||||
quit:
|
||||
wglMakeCurrent(NULL, NULL);
|
||||
ReleaseDC(hDC, hWnd);
|
||||
wglDeleteContext(hRC);
|
||||
|
||||
@ -364,7 +364,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
|
||||
|
||||
Info<< "writing surfMesh again well: " << surfOut.objectPath() << endl;
|
||||
Info<< "writing surfMesh again well: " << surfOut.objectPath()
|
||||
<< endl;
|
||||
surfOut.write();
|
||||
|
||||
// write directly
|
||||
|
||||
@ -88,7 +88,8 @@ int main(int argc, char *argv[])
|
||||
// - explicitly named patches only (-patches (at your option)
|
||||
// - all patches (default in sequential mode)
|
||||
// - all non-processor patches (default in parallel mode)
|
||||
// - all non-processor patches (sequential mode, -excludeProcPatches (at your option)
|
||||
// - all non-processor patches (sequential mode, -excludeProcPatches
|
||||
// (at your option)
|
||||
|
||||
// Construct table of patches to include.
|
||||
const polyBoundaryMesh& bMesh = mesh.boundaryMesh();
|
||||
|
||||
@ -481,8 +481,8 @@ label sharedFace
|
||||
}
|
||||
|
||||
|
||||
// Calculate (inward pointing) normals on edges shared by faces in faceToEdge and
|
||||
// averages them to pointNormals.
|
||||
// Calculate (inward pointing) normals on edges shared by faces in
|
||||
// faceToEdge and averages them to pointNormals.
|
||||
void calcPointVecs
|
||||
(
|
||||
const triSurface& surf,
|
||||
@ -696,8 +696,9 @@ int main(int argc, char *argv[])
|
||||
boolList borderEdge(surf.nEdges(), false);
|
||||
markBorderEdges(debug, surf, borderEdge);
|
||||
|
||||
// Points on two sides connected to borderEdges are called borderPoints and
|
||||
// will be duplicated. borderPoint contains label of newly introduced vertex.
|
||||
// Points on two sides connected to borderEdges are called
|
||||
// borderPoints and will be duplicated. borderPoint contains label
|
||||
// of newly introduced vertex.
|
||||
labelList borderPoint(surf.nPoints(), -1);
|
||||
markBorderPoints(debug, surf, borderEdge, borderPoint);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user