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.
|