/* --------------------------------------------------------------------------- */ /* geometry.c */ /* RP: 10/24/01 */ /* --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- */ /* INCLUDES */ #include /* the math library for sin, cos, etc. */ #include "agl.h" /* to get to the OpenGL commands */ #include "glu.h" /* to get to the OpenGL commands */ #include "glut.h" /* to get to the OpenGL commands */ #include #include "geometry.h" #define PI 3.14159 typedef struct xyz_struct { float x,y,z; } xyz_td; #define DRAW_FLAT_TRIANGLE(N,A,B,C) { \ glBegin(GL_POLYGON); \ glNormal3fv(N); \ glVertex3fv(A); \ glVertex3fv(B); \ glVertex3fv(C); \ glEnd(); \ } #define DRAW_FLAT_QUAD(N,A,B,C,D) { \ glBegin(GL_POLYGON); \ glNormal3fv(N); \ glVertex3fv(A); \ glVertex3fv(B); \ glVertex3fv(C); \ glVertex3fv(D); \ glEnd(); \ } #define DRAW_SMOOTH_TRIANGLE(NA,A,NB,B,NC,C) { \ glBegin(GL_POLYGON); \ glNormal3fv(NA); \ glVertex3fv(A); \ glNormal3fv(NB); \ glVertex3fv(B); \ glNormal3fv(NC); \ glVertex3fv(C); \ glEnd(); \ } #define DRAW_SMOOTH_QUAD(NA,A,NB,B,NC,C,ND,D) { \ glBegin(GL_POLYGON); \ glNormal3fv(NA); \ glVertex3fv(A); \ glNormal3fv(NB); \ glVertex3fv(B); \ glNormal3fv(NC); \ glVertex3fv(C); \ glNormal3fv(ND); \ glVertex3fv(D); \ glEnd(); \ } #define NORMAL_BY_AVERAGE(N,A,B,C) { \ N[0] = A[0]+B[0]+C[0]; \ N[1] = A[1]+B[1]+C[1]; \ N[2] = A[2]+B[2]+C[2]; \ len = sqrt(N[0]*N[0] + N[1]*N[1] + N[2]*N[2]); \ N[0] /= len; \ N[1] /= len; \ N[2] /= len; \ } /* --------------------------------------------------------------------------- */ /* Draw Flat Cylinder */ /* -1 < x < 1 */ /* -1 < z < 1 */ /* -1 < y < 1 - slices rotate about y-axis */ /* each vertex of face gets normal of face */ /* --------------------------------------------------------------------------- */ void draw_cylinder(int type,int n) { int i; float p1[3],p2[3],p3[3],p4[3]; float nv[3],nw[3],len; if (type == FLAT) { p1[0] = cos(0.0); p1[1] = 1.0; p1[2] = sin(0.0); p2[0] = cos(0.0); p2[1] = -1.0; p2[2] = sin(0.0); p3[1] = -1.0; p4[1] = 1.0; glShadeModel(GL_FLAT); for (i=1; i<=n; i++) { p3[0] = p4[0] = cos(2*i*PI/n); p3[2] = p4[2] = sin(2*i*PI/n); nv[0] = p1[0]+p3[0]; nv[2] = p1[2]+p3[2]; len = sqrt(nv[0]*nv[0]+nv[2]*nv[2]); nv[0] /= len; nv[2] /= len; DRAW_FLAT_QUAD(nv,p1,p2,p3,p4); p1[0] = p3[0]; p1[2] = p3[2]; p2[0] = p4[0]; p2[2] = p4[2]; } glBegin(GL_POLYGON); glNormal3f(0.0,1.0,0.0); for (i=0,p1[1]=1.0; i<=n; i++) { p1[0] = cos(2*i*PI/n); p1[2] = sin(2*i*PI/n); glVertex3fv(p1); } glEnd(); glBegin(GL_POLYGON); glNormal3f(0.0,-1.0,0.0); for (i=n,p1[1]=-1.0; i>=0; i--) { p1[0] = cos(2*i*PI/n); p1[2] = sin(2*i*PI/n); glVertex3fv(p1); } glEnd(); } else { // type == SMOOTH p1[0] = cos(0.0); p1[1] = 1.0; p1[2] = sin(0.0); p2[0] = cos(0.0); p2[1] = -1.0; p2[2] = sin(0.0); nv[0] = p1[0]; nv[1] = 0.0; nv[2] = p1[2]; p3[1] = -1.0; p4[1] = 1.0; nw[1] = 0.0; glShadeModel(GL_SMOOTH); for (i=1; i<=n; i++) { p3[0] = p4[0] = cos(2*i*PI/n); p3[2] = p4[2] = sin(2*i*PI/n); nw[0] = p3[0]; nw[2] = p3[2]; DRAW_SMOOTH_QUAD(nv,p1,nv,p2,nw,p3,nw,p4); p1[0] = p3[0]; p1[2] = p3[2]; p2[0] = p4[0]; p2[2] = p4[2]; nv[0] = nw[0]; nv[2] = nw[2]; } glShadeModel(GL_FLAT); glBegin(GL_POLYGON); glNormal3f(0.0,1.0,0.0); for (i=0,p1[1]=1.0; i<=n; i++) { p1[0] = cos(2*i*PI/n); p1[2] = sin(2*i*PI/n); glVertex3fv(p1); } glEnd(); glBegin(GL_POLYGON); glNormal3f(0.0,-1.0,0.0); for (i=n,p1[1]=-1.0; i>=0; i--) { p1[0] = cos(2*i*PI/n); p1[2] = sin(2*i*PI/n); glVertex3fv(p1); } glEnd(); } } /* --------------------------------------------------------------------------- */ /* Draw Cone */ /* -1 < x < 1 */ /* -1 < z < 1 */ /* -1 < y < 1 - slices rotate about y-axis */ /* apex is at (0,1,0) */ /* FLAT: each vertex of face gets normal of face */ /* SMOOTH: each vertex of face gets analytic normal*/ /* --------------------------------------------------------------------------- */ void draw_cone(int type, int n) { int i; float p0[3],p1[3],p2[3]; float nv[3],nw[3],n0[3],len; p0[0] = 0.0; p0[1] = 1.0; p0[2] = 0.0; if (type == FLAT) { glShadeModel(GL_FLAT); p1[0] = cos(0.0); p1[2] = sin(0.0); for (i=1,p1[1]=p2[1]=-1.0,nv[1]=0.5; i<=n; i++) { p2[0] = cos(2*i*PI/n); p2[2] = sin(2*i*PI/n); nv[0] = p1[0]+p2[0]; nv[2] = p1[2]+p2[2]; len = sqrt(nv[0]*nv[0]+0.25+nv[2]*nv[2]); nv[0] /= len; nv[2] /= len; DRAW_FLAT_TRIANGLE(nv,p0,p1,p2); p1[0] = p2[0]; p1[2] = p2[2]; } glBegin(GL_POLYGON); glNormal3f(0.0,-1.0,0.0); for (i=n; i>=0; i--) { p1[0] = cos(2*i*PI/n); p1[2] = sin(2*i*PI/n); glVertex3fv(p1); } glEnd(); } else { // type == SMOOTH glShadeModel(GL_SMOOTH); n0[0] = 0.0; n0[1] = 1.0; n0[2] = 0.0; p1[0] = cos(0.0); p1[2] = sin(0.0); nv[0] = p1[0]; nv[2] = p1[2]; len = sqrt(nv[0]*nv[0]+0.25+nv[2]*nv[2]); nv[0] /= len; nv[1] = 0.5; nv[2] /= len; for (i=1,p1[1]=p2[1]=-1.0,nw[1]=0.5; i<=n; i++) { p2[0] = cos(2*i*PI/n); p2[2] = sin(2*i*PI/n); nw[0] = p2[0]; nw[2] = p2[2]; len = sqrt(nw[0]*nw[0]+0.25+nw[2]*nw[2]); nw[0] /= len; nw[2] /= len; DRAW_SMOOTH_TRIANGLE(n0,p0,nv,p1,nw,p2); p1[0] = p2[0]; p1[2] = p2[2]; nv[0] = nw[0]; nv[2] = nw[2]; } glBegin(GL_POLYGON); glNormal3f(0.0,-1.0,0.0); for (i=n; i>=0; i--) { p1[0] = cos(2*i*PI/n); p1[2] = sin(2*i*PI/n); glVertex3fv(p1); } glEnd(); } } /* --------------------------------------------------------------------------- */ /* Draw Cube */ /* --------------------------------------------------------------------------- */ void draw_cube() { glShadeModel(GL_FLAT); // draw polygon at z=-1.0 glBegin(GL_POLYGON); glNormal3f(0.0,0.0,1.0); glVertex3f(-1.0,1.0,-1.0); glVertex3f(-1.0,-1.0,-1.0); glVertex3f(1.0,-1.0,-1.0); glVertex3f(1.0,1.0,-1.0); glEnd(); // draw polygon at z= 1.0 glBegin(GL_POLYGON); glNormal3f(0.0,0.0,1.0); glVertex3f(-1.0,1.0,1.0); glVertex3f(1.0,1.0,1.0); glVertex3f(1.0,-1.0,1.0); glVertex3f(-1.0,-1.0,1.0); glEnd(); // draw polygon at x= -1.0 glBegin(GL_POLYGON); glNormal3f(-1.0,0.0,0.0); glVertex3f(-1.0,1.0,1.0); glVertex3f(-1.0,-1.0,1.0); glVertex3f(-1.0,-1.0,-1.0); glVertex3f(-1.0,1.0,-1.0); glEnd(); // draw polygon at x= 1.0 glBegin(GL_POLYGON); glNormal3f(1.0,0.0,0.0); glVertex3f(1.0,1.0,1.0); glVertex3f(1.0,1.0,-1.0); glVertex3f(1.0,-1.0,-1.0); glVertex3f(1.0,-1.0,1.0); glEnd(); // draw polygon at y = 1.0 glBegin(GL_POLYGON); glNormal3f(0.0,1.0,0.0); glVertex3f(1.0,1.0,1.0); glVertex3f(-1.0,1.0,1.0); glVertex3f(-1.0,1.0,-1.0); glVertex3f(1.0,1.0,-1.0); glEnd(); // draw polygon at y = -1.0 glBegin(GL_POLYGON); glNormal3f(0.0,-1.0,0.0); glVertex3f(1.0,-1.0,1.0); glVertex3f(1.0,-1.0,-1.0); glVertex3f(-1.0,-1.0,-1.0); glVertex3f(-1.0,-1.0,1.0); glEnd(); } /* --------------------------------------------------------------------------- */ /* Draw Tetrahedron */ /* (0.0, 1.0, 0.0) /* (Cos(0), -1.0, Sin(0.0) */ /* (Cos(120), -1.0, Sin(120) */ /* (Cos(240), -1.0, Sin(240) */ /* --------------------------------------------------------------------------- */ void draw_tetrahedron() { float p0[3] = { 0.0, 1.0, 0.0 }; float p1[3] = { 0.0, -0.333333, 0.942809 }; float p2[3] = { -0.816497, -0.333333, -0.471405 }; float p3[3] = { 0.816497, -0.333333, -0.471405 }; float nv[3],len; glShadeModel(GL_FLAT); NORMAL_BY_AVERAGE(nv,p0,p1,p2) DRAW_FLAT_TRIANGLE(nv,p0,p1,p2) NORMAL_BY_AVERAGE(nv,p0,p2,p3) DRAW_FLAT_TRIANGLE(nv,p0,p2,p3) NORMAL_BY_AVERAGE(nv,p0,p3,p1) DRAW_FLAT_TRIANGLE(nv,p0,p3,p1) nv[0] = 0.0; nv[1] = -1.0; nv[2] = 0.0; DRAW_FLAT_TRIANGLE(nv,p3,p2,p1) } /* --------------------------------------------------------------------------- */ /* Draw Sphere */ /* recursively subdivides a tetrahedron */ /* --------------------------------------------------------------------------- */ void draw_sphere(int type, int subdivisions) { float p0[3] = { 0.0, 1.0, 0.0 }; float p1[3] = { 0.0, -0.333333, 0.942809 }; float p2[3] = { 0.816497, -0.333333, -0.471405 }; float p3[3] = { -0.816497, -0.333333, -0.471405 }; if (type == FLAT) glShadeModel(GL_FLAT); else glShadeModel(GL_SMOOTH); sphere_subdivide(type,p0,p2,p1,1,subdivisions); sphere_subdivide(type,p0,p3,p2,1,subdivisions); sphere_subdivide(type,p0,p1,p3,1,subdivisions); sphere_subdivide(type,p1,p2,p3,1,subdivisions); } void sphere_subdivide(int type, point p1, point p2, point p3,int m,int limit) { point p12,p23,p31; float nv[3]; float len; if (m >=limit ) { if (type == FLAT) { NORMAL_BY_AVERAGE(nv,p1,p2,p3) DRAW_FLAT_TRIANGLE(nv,p1,p2,p3); } else { DRAW_SMOOTH_TRIANGLE(p1,p1,p2,p2,p3,p3); } } else { m = m+1; p12[0] = p1[0]+p2[0]; p12[1] = p1[1]+p2[1]; p12[2] = p1[2]+p2[2]; len = sqrt(p12[0]*p12[0] + p12[1]*p12[1] + p12[2]*p12[2]); p12[0] /= len; p12[1] /= len; p12[2] /= len; p23[0] = p2[0]+p3[0]; p23[1] = p2[1]+p3[1]; p23[2] = p2[2]+p3[2]; len = sqrt(p23[0]*p23[0] + p23[1]*p23[1] + p23[2]*p23[2]); p23[0] /= len; p23[1] /= len; p23[2] /= len; p31[0] = p3[0]+p1[0]; p31[1] = p3[1]+p1[1]; p31[2] = p3[2]+p1[2]; len = sqrt(p31[0]*p31[0] + p31[1]*p31[1] + p31[2]*p31[2]); p31[0] /= len; p31[1] /= len; p31[2] /= len; sphere_subdivide(type,p12,p2,p23,m,limit); sphere_subdivide(type,p23,p3,p31,m,limit); sphere_subdivide(type,p31,p1,p12,m,limit); sphere_subdivide(type,p12,p23,p31,m,limit); } }