Chris Pollett > Old Classes >
CS116b

( Print View )

Student Corner:
  [Grades Sec1]

  [Submit Sec1]

  [Email List Sec1]

  [
Lecture Notes]

Course Info:
  [Texts & Links]
  [Topics]
  [Grading]
  [HW Info]
  [Exam Info]
  [Regrades]
  [Honesty]
  [Announcements]

HW Assignments:
  [Hw1]  [Hw2]  [Hw3]
  [Hw4]  [Hw5]

Practice Exams:
  [Mid1]  [Mid2]  [Final]

                           












HW2 Solutions Page

Return to homework page.

/******************************************************
* Project:         CS116B Homework #2
* File:              SplineDrawer.cpp          
* Purpose:         Draw 3D extrusions of B-spline in
*                  a GUI environment where user can click
*                  points and then extrude the B-spline.
*                 The user can also change his orientation
*
* Start date:      Apr 8, 2005
* Programmer:      Chris Pollett
*
* Remarks: Longer than I expected
*
*******************************************************/

#ifdef WIN32
   #include<windows.h> //for windows
   #include <GL/glut.h>
   #include <GL/glu.h>
#endif

#ifdef __APPLE__ //for MAC
/*
        I created my project under xcode. I chose new C++ tool as the kind of project.
        Then under External frameworks and libraries I added the two frameworks:
        OpenGL.framework and GLUT.framework. (Frameworks are in /Library/Frameworks)

*/
   #include <OpenGL/gl.h> 
   #include <OpenGL/glu.h>
   #include <GLUT/glut.h>
#endif

#ifdef linux // for linux
 /*My compile line was:
        g++ -I /usr/X11R6/include -L /usr/X11R6/lib -lglut -lGL \
         -lGLU -lX11 -lXmu -lXi -lm name.cpp -o name
 */
      #include <GL/glut.h>
      #include <GL/glu.h>
#endif

#include <cmath>
#include <ctime>
#include <iostream>
#include <sstream>
#include <vector>

using namespace std;

/*
   CONSTANTS
*/

//Font stuff
void** FONT = GLUT_BITMAP_9_BY_15; 
const int FONT_WIDTH = 10; 
const int FONT_HEIGHT = 16;

// Screen location of the label used to draw the position
GLfloat cameraPositionLabelX = 20.0;
GLfloat cameraPositionLabelY = 20.0;

//4x4 homogeneous matrix stuff
const int MATRIX_DIM = 4; 
const int MATRIX_SIZE = MATRIX_DIM*MATRIX_DIM; 

//Light  constants
const GLfloat AMBIENT_LIGHT[] = {.3, .3, .3, 1 };
const GLfloat SUN_VECTOR[] = {1000, 2500., 1000.0 }; //sun's position
const GLfloat SUN_AMBIENT_SPECULAR[] = {1, 1, .3, 1 };
const GLfloat SUN_DIFFUSE[] = {.5, 1, 1, 1 };


//Draw MODES
const int NUM_DRAW_MODES = 2;
enum {USE_GLU, USE_HOMEMADE};

//Extrusion and Bezier constants
const GLfloat EXTRUDE_DELTA = 10.0; 
const int SUBDIVISION_DEPTH = 3; // number of times to do subdivision when drawing curve
const int NUM_FORWARD_DIFF_INTERVALS = 10; 

/*
   Prototypes
*/
void drawOneExtrusion(GLfloat direction[], vector<GLfloat> pts, GLfloat extent);


/*
   CLASS DEFINITIONS
*/

/*-----------------------------------------------*/
class Extrusion
/*
PURPOSE: Encapsulates the notion of one B-spline curve extrusion
         Contains a sequence of control points for the B-spline,
		 a direction in which the extrusion is going away from (a unit vector),
		 and a distance the curve is extruded
REMARK: It probably would be one elegant to have direction
        be the vector toward which we are extruding rather than away from
        which we are extruding.		 
*/
{
	private:
		vector<GLfloat> pts; // B-spline control points
		GLfloat direction[3]; // direction away from extrusion
		GLfloat extent; // how far

	public:
		/*-----------------------------------------------*/
		Extrusion()
		/*
		PURPOSE: Constructor - sets up defaults for extrusion
		 These are that the direction is away from the z axis
		RECEIVES: Nothing
		RETURNS: a default extrusion
		REMARKS:    
		*/
		{
			direction[0] = 0.0; //initially 1. on z -axis
			direction[1] = 0.0;
			direction[2] = 1.0;
			pts.clear();
			
			extent = 0.0; // intially no extrusion
		}

		/*-----------------------------------------------*/		
		void addPoint(GLfloat x, GLfloat y, GLfloat z)
		/*
		PURPOSE: Adds a control point to this extrusion
		RECEIVES: x,y,z coordinates of the point to add
		RETURNS: Nothing 
		REMARKS:    
		*/
		{
			pts.push_back(x);
			pts.push_back(y);
			pts.push_back(z);						
		}
	
		/*-----------------------------------------------*/
		void setDirection(GLfloat x, GLfloat y, GLfloat z)
		/*
		PURPOSE: Sets the current direction that the extrusion
				should be directed away from
		RECEIVES:  x,y,z coordinates of the direction
		RETURNS: Nothing 
		REMARKS:    
		*/
		{
			direction[0] = x;
			direction[1] = y;
			direction[2] = z;		
		}

		/*-----------------------------------------------*/		
		void addExtent(GLfloat value)
		/*
		PURPOSE: To add to the distance this extrusion extrudes
		 an amount value
		RECEIVES: value - the amount more this extrusion should extrude
		RETURNS: Nothing 
		REMARKS:    
		*/
		{
			extent += value;
		}
		
		/*-----------------------------------------------*/
		void draw(GLfloat drawSize)
		/*
		PURPOSE: Draws this extrusion
		RECEIVES: drawSize -- if the extrusion has a zero extent
			then we draw the control points for the extrusion
			as cubes of size drawSize
		RETURNS: Nothing 
		REMARKS:    
		*/		
		{
			if(extent)
			{
				drawOneExtrusion(direction, pts, extent);
			}
			else
			{
				for(unsigned int i = 0; i < pts.size(); i += 3)
				{
					glPushMatrix();
					glTranslatef(pts[i], pts[i+1], pts[i+2]);				
					glutSolidCube(drawSize);
					glPopMatrix();					
				}	
			}
		}
	
};


/*
   GLOBALS
*/

GLsizei winWidth = 300, winHeight = 300; // used for size of window
GLsizei initX = 50, initY = 50; // used for initial position of window

//Camera Variables
GLfloat cameraX = 0.0; //camera's direction (looks at origin)
GLfloat cameraY = 0.0;
GLfloat cameraZ = 1.0;
GLfloat cameraDistance = 1500.0; //camera's initial distance from the origin
GLfloat cameraDistanceDelta = 50.0; //amount distance can change when tap a key once
GLfloat cameraNear = 1.1*winHeight; // nearest to the origin camera can get;
GLfloat cameraFar  = 20*winHeight; // farthest from the origin camera can get

GLfloat upX = 0.0; //camera's up vector
GLfloat upY = 1.0;
GLfloat upZ = 0.0;

GLfloat rightX = 1.0; //camera's right vector
GLfloat rightY = 0.0;
GLfloat rightZ = 0.0;

//Draw Mode
int drawMode = USE_GLU;

//Display Lists
GLuint axisList;

//Vector holding all the extrusions so far
vector<Extrusion> extrusions;


/*-----------------------------------------------*/
void drawString(GLfloat x, GLfloat y, string outString)
/*
PURPOSE: Draws a string at the specified coordinates on the viewing plane
RECEIVES: x - the x coordinate to draw the string at
          y - the y coordinate to draw the string at
		  outString - the string to output
RETURNS: Nothing 
REMARKS:    
*/
{	
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	gluOrtho2D(0, winWidth, 0, winHeight);
	
	for(unsigned int i = 0; i< outString.size(); i++)
	{	
		glRasterPos2f( x + FONT_WIDTH*i, y);
		glutBitmapCharacter(FONT, outString[i]);
	}
	
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);	
}

/*-----------------------------------------------*/
void normalize(GLfloat& x, GLfloat& y, GLfloat& z)
/*
PURPOSE: normalizes the supplied x, y, z values
RECEIVES: x,y,z values to compute a unit vector from
RETURNS: Nothing
REMARKS:    
*/
{
	GLfloat length = sqrt(x*x + y*y+ z*z);
	x /= length;
	y /= length;
	z /= length;
}


/*-----------------------------------------------*/
void rotateVectorAboutVector(GLfloat angle, 
	GLfloat rx, GLfloat ry, GLfloat rz, GLfloat& x, GLfloat& y, GLfloat& z)
/*
PURPOSE: rotate the second supplied vector by angle about first supplied vector
RECEIVES: rx - x coordinate of axis of rotation
          ry - y coordinate of axis of rotation
          rz - z coordinate of axis of rotation
		  x - x coordinate of vector to rotate
		  y - y coordinate of vector to rotate
		  z - z coordinate of vector to rotate
		  
RETURNS: nothing
REMARKS: changes x, y, z by reference   
*/
{
	GLdouble curPts[MATRIX_SIZE]; //matrix for vector to rotate

	int i;
	
	for(i = 0; i < MATRIX_DIM; i++)
	{
			curPts[i + 2*MATRIX_DIM] = 0;
			curPts[i + 3*MATRIX_DIM] = 0;                                                   
	}
	
	curPts[0] = x;
	curPts[1] = y;
	curPts[2] = z;
	curPts[3] = 1; //homogeneous coordinates
	
	glPushMatrix();
	glLoadIdentity();
	glRotatef(angle, rx, ry, rz);
	glMultMatrixd(curPts);	
	glGetDoublev(GL_MODELVIEW_MATRIX, curPts); 
	glPopMatrix();
 
	x = (GLfloat) (curPts[0]/curPts[3]);
	y = (GLfloat) (curPts[1]/curPts[3]);
	z = (GLfloat) (curPts[2]/curPts[3]); 
				//dividing since using homogeneous coordinates

}

/*-----------------------------------------------*/
void convertCubicBSplineBezier(GLfloat bArray[], GLfloat bezArray[])
/*
PURPOSE: Converts an array of data for a cubic B-spline into
		an array of data for a cubic Bezier curve
RECEIVES: 
	bArray - the control point data for the B-spline (Notice 1-d array
	         so values congruent to 0%3 are x's; 1%3 are y's
			 and 2%3 are z's
	bezArray - array to store control points of Bezier curve			 
RETURNS: Nothing 
REMARKS: bArray must have size offset+4*3
		 bezArray must have size 4*3
*/
{   
    // zeroth control point
	bezArray[0] = (bArray[0] + 4*bArray[3] + bArray[6])/6;
	bezArray[1] = (bArray[1] + 4*bArray[4] + bArray[7])/6;
	bezArray[2] = (bArray[2] + 4*bArray[5] + bArray[8])/6;

    // 3rd control point
	bezArray[9] = (bArray[3] + 4*bArray[6] + bArray[9])/6;
	bezArray[10] = (bArray[4] + 4*bArray[7] + bArray[10])/6;
	bezArray[11] = (bArray[5] + 4*bArray[8] + bArray[11])/6;
	
	// Now get 1st control point
	bezArray[3] =  (bArray[6] - bArray[0])/6 + bezArray[0];
	bezArray[4] =  (bArray[7] - bArray[1])/6 + bezArray[1];
	bezArray[5] =  (bArray[8] - bArray[2])/6 + bezArray[2];
	
	//Now get second control point

	bezArray[6] =  bezArray[9 ] - (bArray[9 ] - bArray[3])/6;
	bezArray[7] =  bezArray[10] - (bArray[10] - bArray[4])/6;
	bezArray[8] =  bezArray[11] - (bArray[11] - bArray[5])/6;
	
}

/*-----------------------------------------------*/
void init(void)
/*
PURPOSE: sets the background color to black,
         sets up display list for coordinate axes,
		 initializes extrusions vector
RECEIVES: Nothing
RETURNS: Nothing
REMARKS:    
*/
{
   glClearColor(0.0, 0.0, 0.0, 0.0);

	axisList = glGenLists(1);
	
	GLUquadricObj* axis = gluNewQuadric();
	gluQuadricDrawStyle(axis, GLU_FILL);
	
	glNewList(axisList, GL_COMPILE);
		glPushMatrix();
		gluCylinder(axis, .1*winWidth, .1*winWidth, winHeight, 10, 10);
		glRotatef(90.0, 1, 0.0, 0.0);
		glTranslatef(0.0, 0.0, -1.0);		
		gluCylinder(axis, .1*winWidth, .1*winWidth, winHeight, 10, 10);		
		glRotatef(90.0, 0.0, 1.0, 0.0);
		glTranslatef(-1.0, 0.0, 0.0);		
		gluCylinder(axis, .1*winWidth, .1*winWidth, winHeight, 10, 10);
		glPopMatrix();								
    glEndList();
	
	Extrusion startExtrusion;
	extrusions.push_back(startExtrusion);
}



/*-----------------------------------------------*/
void drawLabels()
/*
PURPOSE: Draws the labels for what the current draw mode is 
	and where the camera position is
RECEIVES: Nothing
RETURNS: Nothing 
REMARKS:    
*/
{	
	stringstream labelStream;
	labelStream.precision(1);
	labelStream.setf(ios::fixed);
	
	labelStream  << "x=" << cameraDistance*cameraX << "; y=" 
		<< cameraDistance*cameraY << "; z=" << cameraDistance*cameraZ;

	drawString(cameraPositionLabelX, cameraPositionLabelY, labelStream.str());
	
	if(drawMode == USE_GLU)
	{
		drawString(cameraPositionLabelX, 
			winHeight - cameraPositionLabelY - FONT_HEIGHT,
			"Spline Draw Mode: GLU");
	}
	else
	{
		drawString(cameraPositionLabelX, 
			winHeight - cameraPositionLabelY - FONT_HEIGHT, 
			"Spline Draw Mode: HomeMade");
	}	
}


/*-----------------------------------------------*/
void drawOneGLUExtrusion(GLfloat direction[], vector<GLfloat> pts, GLfloat extent)
/*
PURPOSE: Draws a spline surface, using OpenGL spline functions, 
 which is the extrusion of the
 supplied points of the passed extent in the given direction
RECEIVES: 
	pts - points to use in curve (assumed to be divisble by 3)
	direction - 3-array direction to extrude towards
	extent - distance to extrude
	numPts - number of points in curve	
RETURNS: Nothing 
REMARKS:    
*/
{
		int numPts  = pts.size();
		GLfloat vertices[48];
		
		GLfloat vKnots[8] = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0};
			// for starting curve we use a uniform B-spline
			
		GLfloat uKnots[8] = {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0}; 
			// for extruded direction we use a Bezier curve
				
		GLUnurbsObj *surface = gluNewNurbsRenderer();

		for(int i = 0; i < numPts - 9; i += 3 ) 
		{
		    /*  For each point that has been clicked
			we take it, and the three points after it to make 
			surface which in one direction is a uniform cubic B-spline curve
			on those points and in the other direction is a cubic Bezier curve
			of conisting of control points all on a line in the direction of the extrusion 
		    */
			for(int k = 0; k < 12; k += 3) // 12 is from 4 points each of which has x,y,z
			{
			
				for(int j=0; j < 4; j++) 
				{
				    /*
					   Give Bezier control points all on a line. Rather than equally
					   space them, which means I have to divide by 3, I probably
					   should have done something with powers of 2.
					*/
					vertices[k + j*12] = pts[i + k] - j*extent*direction[0]/3;
					vertices[k + j*12 + 1] = pts[i + k + 1] - j*extent*direction[1]/3;
					vertices[k + j*12 + 2] = pts[i + k + 2] - j*extent*direction[2]/3;
				}									
			}		 
			gluBeginSurface(surface);
				gluNurbsSurface(surface, 8, uKnots,
					8, vKnots, 12, 3, vertices,
					4, 4, GL_MAP2_VERTEX_3);
			gluEndSurface(surface);
		}
		
		gluDeleteNurbsRenderer(surface);
}

/*-----------------------------------------------*/
void drawExtrusionUsingForwardDifferencing(GLfloat offsetVector[], GLfloat bezCurve[], int numIntervals)
/*
PURPOSE: draws an extruded version of the supplied bezier curve 
RECEIVES: offsetVector - vector giving direction to extrude
		  bezCurve - single array with four control points of the Bezier Curve
		  depth - how many subdivisions to do before drawing using forward differencing
	
RETURNS: Nothing 
REMARKS:    
*/
{
	/* To begin let's work out the coefficient \vec{a}, \vec{b}, \vec{c}, \vec{d} in 
	   \vec{a}u^3 + \vec{b}u^2 +\vec{c}u +\vec{d}
    */
	int i,j;
	GLfloat a[3], b[3], c[3] ,d[3];
	
	for(j = 0; j < 3; j++)
	{
		a[j] = -bezCurve[j] + 3*bezCurve[j + 3] - 3*bezCurve[j + 6] + bezCurve[j + 9];
		b[j] = 3*bezCurve[j] - 6*bezCurve[j + 3] + 3*bezCurve[j + 6];
		c[j] = -3*bezCurve[j] + 3*bezCurve[j + 3];
		d[j] = bezCurve[j];

	}
	
	/*
		Now we initialze our various forward differences
	*/
	GLfloat delta = 1.0/( (GLfloat)numIntervals);
	GLfloat zeroDiff[3], firstDiff[3], secondDiff[3], thirdDiff[3];
	GLfloat nextZeroDiff[3], nextFirstDiff[3], nextSecondDiff[3];

	for(int j = 0; j < 3; j++)
	{
		zeroDiff[j] = d[j];
		firstDiff[j] = ((a[j]*delta + b[j])*delta +c[j])*delta; //Look it's Horner's rule!!
		secondDiff[j] = (6*a[j]*delta + 2*b[j])*delta*delta;
		thirdDiff[j] = 6*a[j]*delta*delta*delta;
	}
	
	//Now let's draw the Bezier curve
	for(i = 0; i < numIntervals; i++)
	{
		// compute next step along curve
		for(j = 0; j < 3; j++)
		{
			nextZeroDiff[j] = zeroDiff[j] + firstDiff[j];
			nextFirstDiff[j] = firstDiff[j] + secondDiff[j];
			nextSecondDiff[j] = secondDiff[j] + thirdDiff[j];
		}
		
		//Draw a Quad for this part of the extrusion
		glBegin(GL_QUADS);
			glVertex3f(zeroDiff[0], zeroDiff[1], zeroDiff[2]);
			glVertex3f(zeroDiff[0] + offsetVector[0], zeroDiff[1] + offsetVector[1], 
				zeroDiff[2] + offsetVector[2]);
			glVertex3f(nextZeroDiff[0] + offsetVector[0], nextZeroDiff[1] + offsetVector[1], 
				nextZeroDiff[2] + offsetVector[2]);					
			glVertex3f(nextZeroDiff[0], nextZeroDiff[1], nextZeroDiff[2]);					
		glEnd();		
		
		//set up for next iteration
		for(j = 0; j < 3; j++)
		{
			zeroDiff[j] = nextZeroDiff[j];
			firstDiff[j] = nextFirstDiff[j];
			secondDiff[j] = nextSecondDiff[j];
		}		
	}		
}

/*-----------------------------------------------*/
void drawExtrusionUsingSubdivisions(GLfloat offsetVector[], GLfloat bezCurve[], int depth)
/*
PURPOSE: draws an extruded version of the supplied bezier curve 
RECEIVES: offsetVector - vector giving direction to extrude
		  bezCurve - single array with four control points of the Bezier Curve
		  depth - how many subdivisions to do before drawing using forward differencing
	
RETURNS: Nothing 
REMARKS:    
*/
{
	if(depth <= 1)
	{
		drawExtrusionUsingForwardDifferencing(offsetVector, bezCurve, NUM_FORWARD_DIFF_INTERVALS);
	}
	else
	{
		depth--;
		GLfloat frontHalf[12], backHalf[12], tmp[3];
		
		for(int i = 0; i < 3; i++)
		{
			frontHalf[i] = bezCurve[i];  // zeroth control front
			backHalf[i+9] = bezCurve[i+9]; // third control back
			
			frontHalf[i+3] = (bezCurve[i] + bezCurve[i+3])/2; //first control front
			backHalf[i+6] = (bezCurve[i+6] + bezCurve[i+9])/2; // second control back

			tmp[i] = (bezCurve[i+3] + bezCurve[i+6])/2; //tmp point use for remaining controls
			
			frontHalf[i+6] = (frontHalf[i+3] + tmp[i])/2; // second control front
			backHalf[i+3] = (backHalf[i+6] + tmp[i])/2; // first control back
			
			backHalf[i] = (frontHalf[i+6] + backHalf[i+3])/2; // zeroth control back
			frontHalf[i+9] = backHalf[i]; // third control front
		}
		
		drawExtrusionUsingSubdivisions(offsetVector, frontHalf, depth);
		drawExtrusionUsingSubdivisions(offsetVector, backHalf, depth);			
	}
	
}

/*-----------------------------------------------*/
void drawOneHomeExtrusion(GLfloat direction[], vector<GLfloat> pts, GLfloat extent)
/*
PURPOSE: Draws a spline surface, using spline drawing functions
 created for this assignment,
 which is the extrusion of the
 supplied points of the passed extent in the given direction
RECEIVES: 
	pts - points to use in curve (assumed to be divisble by 3)
	direction - 3-array direction to extrude towards
	extent - distance to extrude
	numPts - number of points in curve	
RETURNS: Nothing 
REMARKS:    
*/
{
		int numPts  = pts.size();
		
		GLfloat bPoints[12], bezPoints[12];
		GLfloat dirVector[3];
		
		for(int k = 0;  k < 3; k++)
		{
			dirVector[k] = - direction[k]*extent;
		}
		
		for(int i = 0; i < numPts - 9; i += 3 )
		{
			for(int j = 0; j < 12; j++)
			{
				bPoints[j] = pts[j + i];
			}
			
			convertCubicBSplineBezier(bPoints, bezPoints);
			drawExtrusionUsingSubdivisions(dirVector, bezPoints, SUBDIVISION_DEPTH);
		}		
}

/*-----------------------------------------------*/
void drawOneExtrusion(GLfloat direction[], vector<GLfloat> pts, GLfloat extent)
/*
PURPOSE: Draws a spline surface which is the extrusion of the
 supplied points of the passed extent in the given direction
RECEIVES: 
	pts - points to use in curve
	direction - 3-array direction to extrude towards
	extent - distance to extrude
	numPts - number of points in curve
RETURNS: Nothing 
REMARKS:    
*/
{
	switch(drawMode)
	{
		case USE_GLU:
			drawOneGLUExtrusion(direction, pts, extent);
		break;
		
		case USE_HOMEMADE:
			drawOneHomeExtrusion(direction, pts, extent);
		break;
	}
}

/*-----------------------------------------------*/
void drawExtrusions()
/*
PURPOSE: Draws all of the extrusions in the scene
RECEIVES: Nothing
RETURNS: Nothing 
REMARKS:    
*/
{
	// Set up how we draw the points.
	GLfloat drawSize;
	GLfloat sizes[2];  // Store supported point size range
	GLfloat step;     // Store supported point size increments


	// Get supported point size range and step size
	glGetFloatv(GL_POINT_SIZE_RANGE,sizes);
	glGetFloatv(GL_POINT_SIZE_GRANULARITY,&step);

	// Specify the point size 

	drawSize = (winWidth < winHeight) ? winWidth/50 : winHeight/50;
	if(drawSize > sizes[1]) drawSize = sizes[1];
	drawSize = winWidth/100;			
	for(unsigned int i = 0; i < extrusions.size(); i++)
	{
		extrusions[i].draw(drawSize);
	}	
}

/*-----------------------------------------------*/
void drawFn()
/*
PURPOSE: Used to craw the complete scene saturn + probe
		and to swap scene buffers
RECEIVES: Nothing
RETURNS:  Nothing
REMARKS:    
*/
{

	glEnable(GL_LIGHTING);

	glLightfv(GL_LIGHT0, GL_POSITION, SUN_VECTOR);
	glLightfv(GL_LIGHT0, GL_AMBIENT, SUN_AMBIENT_SPECULAR);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, SUN_DIFFUSE);
	glLightfv(GL_LIGHT0, GL_SPECULAR, SUN_AMBIENT_SPECULAR);                
	glEnable(GL_LIGHT0);    
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, AMBIENT_LIGHT); 
	
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	glFrustum(-winWidth/2, winWidth/2, -winHeight/2, winHeight/2, winWidth/2, 20*winWidth);
	gluLookAt(cameraX*cameraDistance, 
			  cameraY*cameraDistance, 
			  cameraZ*cameraDistance, 
			  0.0, 0.0, 0.0, upX, upY, upZ);
	
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	
	//Compute Depths
	glEnable(GL_DEPTH_TEST); 

	glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);


	glCallList(axisList); // draw the coordinate axes

		
	drawLabels();
	drawExtrusions();
	
	glutSwapBuffers();
}

/*-----------------------------------------------*/
void mouseFn(int button, int state, int xPos, int yPos)
/*
PURPOSE: Handle nonspecial key events (mainly space key and 1 key)
RECEIVES: button - which button was pressed
		  state - whether button is up or down
          xPos - x position of mouse
		  yPos - y position of mouse  
RETURNS: Nothing 
REMARKS:    
*/
{
	GLfloat adjustedRightPos = xPos - winWidth/2; 
		// position in right direction relative to camera
		 
	GLfloat adjustedUpPos = yPos - winHeight/2;
		// position in Up direction relative to camera
		
	GLfloat adjustedDistance = cameraDistance - .51*winWidth; 
		//put point so not immediately clipped (winWidth/2 is distance to clipping plane)
	
	GLfloat x = adjustedDistance*cameraX + adjustedRightPos*rightX
		- adjustedUpPos*upX;

	GLfloat y = adjustedDistance*cameraY + adjustedRightPos*rightY
		- adjustedUpPos*upY;

	GLfloat z = adjustedDistance*cameraZ + adjustedRightPos*rightZ
		- adjustedUpPos*upZ;
		
	
	if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
	{
		extrusions[extrusions.size()-1].addPoint(x, y, z);
		
		glutPostRedisplay(); // cause scene to be redrawn		
	}
}

/*-----------------------------------------------*/
void keyFn(unsigned char key, int xPos, int yPos)
/*
PURPOSE: Handle nonspecial key events (mainly space key and 1 key)
RECEIVES: key - key being pressed
          xPos - x position of mouse
		  yPos - y position of mouse  
RETURNS: Nothing 
REMARKS:    
*/
{
	bool sceneChanged = false;
	int end = extrusions.size() - 1;

	switch(key)
	{
		case '1':
			drawMode ++;
			drawMode %= NUM_DRAW_MODES;
			
			sceneChanged = true;
		break;
		
		case ' ':
			extrusions[end].addExtent(EXTRUDE_DELTA);
			extrusions[end].setDirection(cameraX, cameraY, cameraZ);
			sceneChanged = true;
		break;
	}

	if(sceneChanged)
	{		
		glutPostRedisplay(); // cause scene to be redrawn
	}	
}

/*-----------------------------------------------*/
void keyUpFn(unsigned char key, int xPos, int yPos)
/*
PURPOSE: Handle nonspecial key release events
		This is mainly used for the space
		key to handle when the extrusion stops
RECEIVES: key - key being pressed
          xPos - x position of mouse
		  yPos - y position of mouse  
RETURNS: Nothing 
REMARKS:    
*/
{
	Extrusion nextExtrusion;
	switch(key)
	{
		
		case ' ':
			extrusions.push_back(nextExtrusion);
		break;
	}
}

/*-----------------------------------------------*/
void specialKeyFn(int key, int xPos, int yPos)
/*
PURPOSE: Handle arrow key events
RECEIVES: key - key being pressed
          xPos - x position of mouse
		  yPos - y position of mouse  
RETURNS: Nothing 
REMARKS:    
*/
{
	bool sceneChanged = false;
	int modifiers = glutGetModifiers();
	
	switch(key)
	{
		case GLUT_KEY_UP:
			if(modifiers == GLUT_ACTIVE_SHIFT)
			{
				cameraDistance -= cameraDistanceDelta;
				if(cameraDistance < cameraNear) cameraDistance = cameraNear;				
			}
			else
			{
				rotateVectorAboutVector(-1, rightX, rightY, rightZ, cameraX, cameraY, cameraZ);
				rotateVectorAboutVector(-1, rightX, rightY, rightZ, upX, upY, upZ);			
			}
			sceneChanged = true;
		break;
		
		case GLUT_KEY_DOWN:
			if(modifiers == GLUT_ACTIVE_SHIFT)
			{
				cameraDistance += cameraDistanceDelta;
				if(cameraDistance > cameraFar) cameraDistance = cameraFar;				
			}
			else
			{
				rotateVectorAboutVector(1, rightX, rightY, rightZ, cameraX, cameraY, cameraZ);
				rotateVectorAboutVector(1, rightX, rightY, rightZ, upX, upY, upZ);		
			}
			sceneChanged = true;
		break;
		
		case GLUT_KEY_LEFT:
			rotateVectorAboutVector(-1, cameraX, cameraY, cameraZ, upX, upY, upZ); 		
			rotateVectorAboutVector(-1, cameraX, cameraY, cameraZ, rightX, rightY, rightZ); 		

			sceneChanged = true;		
		break;

		case GLUT_KEY_RIGHT:
			rotateVectorAboutVector(1, cameraX, cameraY, cameraZ, upX, upY, upZ);		
			rotateVectorAboutVector(1, cameraX, cameraY, cameraZ, rightX, rightY, rightZ); 		

			sceneChanged = true;		
		break;
								
	}

	if(sceneChanged)
	{
		normalize(cameraX, cameraY, cameraZ);
		normalize(upX, upY, upZ);
		normalize(rightX, rightY, rightZ);
		
		glutPostRedisplay(); // cause scene to be redrawn
	}
}

/*-----------------------------------------------*/
void reshapeFn(int newWidth, int newHeight)
/*
PURPOSE: To redraw scene when  window gets resized.
RECEIVES: newWidth -- new window x size
          newHeight -- new window y size
RETURNS: Nothing 
REMARKS:    
*/
{
	glViewport(0, 0, newWidth, newHeight);
	
	winWidth = newWidth;
	winHeight = newHeight;
	
	glutPostRedisplay(); // cause scene to be redrawn

}

int main (int argc, char **argv) 
{
   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); 

   glutInitWindowPosition(initX, initY);
   glutInitWindowSize(winWidth, winHeight);
   glutCreateWindow("Constructive Spline Drawer");

   init();
   glutDisplayFunc(drawFn);
   glutReshapeFunc(reshapeFn);
   glutSpecialFunc(specialKeyFn);   
   glutKeyboardFunc(keyFn);
   glutKeyboardUpFunc(keyUpFn);         
   glutMouseFunc(mouseFn);   
      
   glutMainLoop();
   return 0;
}
 

Return to homework page.