#include <math.h>
#include <stdio.h>
#include <GL/glut.h>
#include "GluCylinders.h"
// There's no real need to comment includes.
// What a include supplies normally is obvious from the file name
void animate(float t, float&, float&, float&);
void renderCylinder(float x1, float y1, float z1,
float x2,float y2, float z2,
float radius, int subdivisions,
GLUquadricObj *quadric);
void renderCylinder_convenient(float x1, float y1, float z1,
float x2,float y2, float z2,
float radius,int subdivisions);
// The next global variable controls the animation's state and speed.
float RotateAngle = 0.0f; // Angle in degrees of rotation around y-axis
float Azimuth = 0.0; // Rotated up or down by this amount
float AngleStepSize = 3.0f; // Step three degrees at a time
const float AngleStepMax = 10.0f;
const float AngleStepMin = 0.1f;
int WireFrameOn = 1; // == 1 for wire frame mode
//points
// I would not call this geometry but control points...
float Geometry[9][3] = {
{ 4,2.0,0},
{ 4,2.0,0}, // Point1
{-1.5,0.2,0},
{-2,0.3,0},
{-2.5,0.6,0},
{-3,0.8,0},
{-3.5,1.0,0},
{ -5.5,1.8,0}, //point 2
{ -5.5,1.8,0}
};
int x2[5],y2[5],z2[5];
// LOD? Level of Detail? Length of Delay?
// This is a case where a comment makes sense: Explaining abbreviations.
// unsigned int LOD=20;
void myKeyboardFunc( unsigned char key, int x, int y )
{
switch ( key ) {
case 'w':
WireFrameOn = 1-WireFrameOn;
glutPostRedisplay();
break;
case 'R':
AngleStepSize *= 1.5;
if (AngleStepSize>AngleStepMax ) {
AngleStepSize = AngleStepMax;
}
break;
case 'r':
AngleStepSize /= 1.5;
if (AngleStepSize<AngleStepMin ) {
AngleStepSize = AngleStepMin;
}
break;
case 27: // Escape key
exit(1);
}
}
// glutSpecialFunc is called below to set this function to handle
// all "special" key presses. See glut.h for the names of
// special keys.
void mySpecialKeyFunc( int key, int x, int y )
{
switch ( key ) {
case GLUT_KEY_UP:
Azimuth += AngleStepSize;
if ( Azimuth>80.0f ) {
Azimuth = 80.0f;
}
break;
case GLUT_KEY_DOWN:
Azimuth -= AngleStepSize;
if ( Azimuth < -80.0f ) {
Azimuth = -80.0f;
}
break;
case GLUT_KEY_LEFT:
RotateAngle += AngleStepSize;
if ( RotateAngle > 180.0f ) {
RotateAngle -= 360.0f;
}
break;
case GLUT_KEY_RIGHT:
RotateAngle -= AngleStepSize;
if ( RotateAngle < -180.0f ) {
RotateAngle += 360.0f;
}
break;
}
glutPostRedisplay();
}
/*
* drawScene() handles the animation and the redrawing of the
* graphics window contents.
*/
void drawScene(void)
{
// Those should not be a drawScene static, but part of
// a scene management structure. Which your code lacks,
// unfortunately, and I'm not gonna introduce one.
static float animation_time = 0.;
static int j = 1; // why 1 indexed? This is not Lua
if ( WireFrameOn ) {
glPolygonMode ( GL_FRONT_AND_BACK, GL_LINE ); // Just show wireframes
} else {
glPolygonMode ( GL_FRONT_AND_BACK, GL_FILL ); // Show solid polygons
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslatef( -0.5, 0.0, -35.0 );
glRotatef( RotateAngle, 0.0, 1.0, 0.0 );
glRotatef( Azimuth, 1.0, 0.0, 0.0 );
// Please, don't /code/ your geometry, it's ugly and unmaintainable. I omit that code here
// (...)
// Okay, I can just guess here, but it looks like you're intending to draw
// a trace of the sphere as it moves around. I have no idea what that j
// loop is meant for, though. But I guess you want to show the control points,
// one after another. This another case _FOR_ comments: Explaining the idea of
// the overall scheme. Don't write in a comment what a single statement does. I
// can see that from the statement.
// use the parametric time value 0 to current animation time.
float x3, y3, z3;
// first draw the trace
glBegin(GL_LINE_STRIP);
for(float t = 0; t < animation_time; t+=0.05) {
animate(t, x3, y3, z3);
glVertex3f( x3,y3,z3 );
}
glEnd();
// Then draw the control point markers
glColor3f(1,1,0);
for(float t = 0; t < animation_time; t+=0.05) {
animate(t, x3, y3, z3);
renderCylinder_convenient(
Geometry[j][0],Geometry[j][1],Geometry[j][2],
x3,y3,z3,
0.3, 32);
}
// Last but not least draw sphere at the position for animation_time.
animate(animation_time, x3, y3, z3);
glutDrawSphere(...);
// now, we want to play that animation a few times in
// succession, but with different control points visible
// or so I presume so after each animation time has reached 1
// we increment the control point counter. And after that hit
// its maximum we stop advancing the animation
if(j<3) {
if(animation_time < 1.0) {
// Animation step should be a measured
// value. However in case of your simple
// graphics and in the case of v-synced
// buffer swap, and the prevalence of LCD
// screens updating at 60Hz we can make this
// a constant:
// One frame is 1/60th of a second and we
// want to take the animation 5 seconds to
// play:
float animation_step = (1./60.) / (5.);
animation_time += animation_step;
} else {
animation_time = 0.;
j++;
}
}
glutSwapBuffers();
}
// Called when the window is resized
// w, h - width and height of the window in pixels.
void resizeWindow(int w, int h)
{
double aspectRatio;
// Technically all this should be done in the display function!
// Define the portion of the window used for OpenGL rendering.
glViewport( 0, 0, w, h ); // View port uses whole window
// Set up the projection view matrix: perspective projection
// Determine the min and max values for x and y that should appear in the window.
// The complication is that the aspect ratio of the window may not match the
// aspect ratio of the scene we want to view.
w = (w==0) ? 1 : w;
h = (h==0) ? 1 : h;
aspectRatio = (double)w / (double)h;
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 15.0, aspectRatio, 25.0, 45.0 );
}
// Main routine
// Set up OpenGL, define the callbacks and start the main loop
int main( int argc, char** argv )
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
glutInitWindowPosition( 10, 60 );
glutInitWindowSize( 360, 360 );
glutCreateWindow( "GluCylinders" );
glutKeyboardFunc( myKeyboardFunc );
glutSpecialFunc( mySpecialKeyFunc );
glutReshapeFunc( resizeWindow );
glutIdleFunc( glutPostRedisplay ); // when idle -> redraw
glutDisplayFunc( drawScene );
fprintf(stdout, "Arrow keys control viewpoint.\n");
fprintf(stdout, "Press \"w\" to toggle wireframe mode.\n");
fprintf(stdout, "Press \"R\" or \"r\" to increase or decrease rate of movement (respectively).\n");
// Start the main loop. glutMainLoop never returns.
glutMainLoop( );
return 0;
}
GLUquadricObj* myReusableQuadric = 0;
void drawGluCylinder( double height, double radius, int slices, int stacks ) {
drawGluSlantCylinder( height, radius, radius, slices, stacks );
}
void drawGluSlantCylinder( double height, double radiusBase, double radiusTop, int slices, int stacks )
{
if ( ! myReusableQuadric ) {
myReusableQuadric = gluNewQuadric();
// Should (but don't) check if pointer is still null --- to catch memory allocation errors.
gluQuadricNormals( myReusableQuadric, GL_TRUE );
}
// Draw the cylinder.
gluCylinder( myReusableQuadric, radiusBase, radiusTop, height, slices, stacks );
}
void drawGluCylinderWithCaps( double height, double radius, int slices, int stacks ) {
drawGluSlantCylinderWithCaps( height, radius, radius, slices, stacks );
}
// animate shall calculate the new position for the next
// render iteration. Don't do delays, busy loops and drawing
// stuff here.
void animate(float t, float &x3, float &y3, float &z3)
{
// I don't see it in this mess, but I
// assume this is some kind of spline
// interpolation, right?
x3 = 0.5*((-Geometry[j-1][0] + 3*Geometry[j][0] -3*Geometry[j+1][0] + Geometry[j+2][0])*t*t*t + (2*Geometry[j-1][0] -5*Geometry[j][0] +4*Geometry[j+1][0] -Geometry[j+2][0])*t*t + (-Geometry[j-1][0] + Geometry[j+1][0])*t + 2*Geometry[j][0]);
y3 = 0.5*((-Geometry[j-1][1] + 3*Geometry[j][1] -3*Geometry[j+1][1] + Geometry[j+2][1])*t*t*t+ (2*Geometry[j-1][1] -5*Geometry[j][1] +4*Geometry[j+1][1] -Geometry[j+2][1])*t*t +(-Geometry[j-1][1] + Geometry[j+1][1])*t + 2*Geometry[j][1]);
z3 = 0.5*((-Geometry[j-1][2] + 3*Geometry[j][2] -3*Geometry[j+1][2] + Geometry[j+2][2])*t*t*t + (2*Geometry[j-1][2] -5*Geometry[j][2] +4*Geometry[j+1][2] -Geometry[j+2][2])*t*t +(-Geometry[j-1][2] + Geometry[j+1][2])*t + 2*Geometry[j][2]);
}
void renderCylinder(float x1, float y1, float z1, float x2,float y2, float z2, float radius,int subdivisions,GLUquadricObj *quadric)
{
float v,rx,ry,ax,vx = x2-x1;
float vy = y2-y1;
float vz = z2-z1; //handle the degenerate case of z1 == z2 with an approximation
if(vz == 0)
vz =.00000001;
v = sqrt( vx*vx + vy*vy + vz*vz );
ax = 57.2957795*acos( vz/v );
if ( vz < 0.0 )
ax = -ax;
rx = -vy*vz;
ry = vx*vz;
glPushMatrix(); //draw the cylinder body
glTranslatef( x1,y1,z1 );
glRotatef(ax, rx, ry, 0.0);
gluQuadricOrientation(quadric,GLU_OUTSIDE);
gluCylinder(quadric, radius, radius, v, subdivisions, 1); //draw the first cap
gluQuadricOrientation(quadric,GLU_INSIDE);
gluDisk( quadric, 0.0, radius, subdivisions, 1);
glTranslatef( 0,0,v ); //draw the second cap
gluQuadricOrientation(quadric,GLU_OUTSIDE);
gluDisk( quadric, 0.0, radius, subdivisions, 1);
glPopMatrix();
}
void renderCylinder_convenient(
float x1, float y1, float z1,
float x2,float y2, float z2,
float radius,int subdivisions)
{
//the same quadric can be re-used for drawing many cylinders
// Instead of quadrics and coding your geometry you should
// just import a 3D model and render that. It's easier and
// allows for more artistic freedom. Yes, Yes, I know, your
// teachers assigment; seriously, I'd tell a teacher demanding
// this to f*** himself.
GLUquadricObj *quadric=gluNewQuadric();
gluQuadricNormals(quadric, GLU_SMOOTH);
renderCylinder(x1,y1,z1,x2,y2,z2,radius,subdivisions,quadric);
gluDeleteQuadric(quadric);}
void drawGluSlantCylinderWithCaps(
double height, double radiusBase, double radiusTop,
int slices, int stacks )
{
// First draw the cylinder
drawGluSlantCylinder( height, radiusBase, radiusTop, slices, stacks );
// Draw the top disk cap
glPushMatrix();
glTranslated(0.0, 0.0, height);
gluDisk( myReusableQuadric, 0.0, radiusTop, slices, stacks );
glPopMatrix();
// Draw the bottom disk cap
glPushMatrix();
glRotated(180.0, 1.0, 0.0, 0.0);
gluDisk( myReusableQuadric, 0.0, radiusBase, slices, stacks );
glPopMatrix();
}