#ifndef _VCG_GL_GEOMETRY_ #define _VCG_GL_GEOMETRY_ /* Portion of this file were more or less adapted from * freeglut_geometry.c * * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. * that was Written by Pawel W. Olszta, <olszta@sourceforge.net> */ #include<stdlib.h> #include<math.h> /* * Compute lookup table of cos and sin values forming a cirle * * Notes: * It is the responsibility of the caller to free these tables * The size of the table is (n+1) to form a connected loop * The last entry is exactly the same as the first * The sign of n can be flipped to get the reverse loop */ static void fghCircleTable(double **sint,double **cost,const int n) { int i; /* Table size, the sign of n flips the circle direction */ const int size = abs(n); /* Determine the angle between samples */ const double angle = 2*M_PI/(double)( ( n == 0 ) ? 1 : n ); /* Allocate memory for n samples, plus duplicate of first entry at the end */ *sint = (double *) calloc(sizeof(double), size+1); *cost = (double *) calloc(sizeof(double), size+1); /* Bail out if memory allocation fails, fgError never returns */ if (!(*sint) || !(*cost)) { free(*sint); free(*cost); abort(); //fgError("Failed to allocate memory in fghCircleTable"); } /* Compute cos and sin around the circle */ (*sint)[0] = 0.0; (*cost)[0] = 1.0; for (i=1; i<size; i++) { (*sint)[i] = sin(angle*i); (*cost)[i] = cos(angle*i); } /* Last sample is duplicate of the first */ (*sint)[size] = (*sint)[0]; (*cost)[size] = (*cost)[0]; } /* * Draws a solid sphere */ static void glutSolidSphere(GLdouble radius, GLint slices, GLint stacks) { int i,j; /* Adjust z and radius as stacks are drawn. */ double z0,z1; double r0,r1; /* Pre-computed circle */ double *sint1,*cost1; double *sint2,*cost2; // FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSphere" ); fghCircleTable(&sint1,&cost1,-slices); fghCircleTable(&sint2,&cost2,stacks*2); /* The top stack is covered with a triangle fan */ z0 = 1.0; z1 = cost2[(stacks>0)?1:0]; r0 = 0.0; r1 = sint2[(stacks>0)?1:0]; glBegin(GL_TRIANGLE_FAN); glNormal3d(0,0,1); glVertex3d(0,0,radius); for (j=slices; j>=0; j--) { glNormal3d(cost1[j]*r1, sint1[j]*r1, z1 ); glVertex3d(cost1[j]*r1*radius, sint1[j]*r1*radius, z1*radius); } glEnd(); /* Cover each stack with a quad strip, except the top and bottom stacks */ for( i=1; i<stacks-1; i++ ) { z0 = z1; z1 = cost2[i+1]; r0 = r1; r1 = sint2[i+1]; glBegin(GL_QUAD_STRIP); for(j=0; j<=slices; j++) { glNormal3d(cost1[j]*r1, sint1[j]*r1, z1 ); glVertex3d(cost1[j]*r1*radius, sint1[j]*r1*radius, z1*radius); glNormal3d(cost1[j]*r0, sint1[j]*r0, z0 ); glVertex3d(cost1[j]*r0*radius, sint1[j]*r0*radius, z0*radius); } glEnd(); } /* The bottom stack is covered with a triangle fan */ z0 = z1; r0 = r1; glBegin(GL_TRIANGLE_FAN); glNormal3d(0,0,-1); glVertex3d(0,0,-radius); for (j=0; j<=slices; j++) { glNormal3d(cost1[j]*r0, sint1[j]*r0, z0 ); glVertex3d(cost1[j]*r0*radius, sint1[j]*r0*radius, z0*radius); } glEnd(); /* Release sin and cos tables */ free(sint1); free(cost1); free(sint2); free(cost2); } /* * Draws a wire sphere */ static void glutWireSphere(GLdouble radius, GLint slices, GLint stacks) { int i,j; /* Adjust z and radius as stacks and slices are drawn. */ double r; double x,y,z; /* Pre-computed circle */ double *sint1,*cost1; double *sint2,*cost2; //FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSphere" ); fghCircleTable(&sint1,&cost1,-slices ); fghCircleTable(&sint2,&cost2, stacks*2); /* Draw a line loop for each stack */ for (i=1; i<stacks; i++) { z = cost2[i]; r = sint2[i]; glBegin(GL_LINE_LOOP); for(j=0; j<=slices; j++) { x = cost1[j]; y = sint1[j]; glNormal3d(x,y,z); glVertex3d(x*r*radius,y*r*radius,z*radius); } glEnd(); } /* Draw a line loop for each slice */ for (i=0; i<slices; i++) { glBegin(GL_LINE_STRIP); for(j=0; j<=stacks; j++) { x = cost1[i]*sint2[j]; y = sint1[i]*sint2[j]; z = cost2[j]; glNormal3d(x,y,z); glVertex3d(x*radius,y*radius,z*radius); } glEnd(); } /* Release sin and cos tables */ free(sint1); free(cost1); free(sint2); free(cost2); } #endif