Last active
August 29, 2015 14:00
-
-
Save aleks-mariusz/34ac97891fcf53db1e62 to your computer and use it in GitHub Desktop.
May 2 2001 - Another sample of coursework i did for a class on OpenGL using C++ (circa 2001). Neither of these i can say i know like the back of my hand, but at least one can say i'm familiar with the fundamental concepts :-) I definitely had a new found appreciation after this piece for experts on either!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
** Alex Koralewski | |
** 0019480 | |
** Assignment 4 | |
** | |
** Written with a 2-button mouse in mind when dealing with menu requirement. | |
** | |
** Please note, due to linked list usage, the vertex/edge/triangle linked lists | |
** store the information backwards from what was read; therefore, the normal | |
** vectors are negated to compensate. | |
*/ | |
#include <stdlib.h> // for various C goodies | |
#include <iostream.h> // for c++ i/o | |
#include <fstream.h> // for file manipulation | |
#include <math.h> // for mathematical functions (sqrt comes to mind) | |
#include <assert.h> // for assert() | |
#include <gl/glut.h> // for all gl_ glu_ and glut_ functions | |
#define XOFFSET 50 // window offset from left of screen | |
#define YOFFSET 50 // window offset from top of screen | |
#define WINDOW_WIDTH 500 // window width | |
#define WINDOW_HEIGHT 500 // window height | |
#define IMAGE_WIDTH 64 | |
#define IMAGE_HEIGHT 64 | |
#define LEG1_X -1 // first leg of cycle | |
#define LEG1_Z -4 | |
#define LEG2_X 3 // second leg of cycle | |
#define LEG2_Z -3 | |
#define LEG3_X 1 // starting leg of cycle | |
#define LEG3_Z 4 | |
// menu identifiers | |
#define MENU_DEFAULT_VIEW 1 | |
#define MENU_NO_HSR 4 | |
#define MENU_HSR 5 | |
#define MENU_SHADE_FLAT 8 | |
#define MENU_SHADE_TVN 9 | |
#define MENU_SHADE_AVN 10 | |
#define MENU_LIGHT_SPOT 16 | |
#define MENU_LIGHT_POINT 17 | |
#define MENU_NO_FOG 32 | |
#define MENU_FOG_LINEAR 33 | |
#define MENU_FOG_EXP 34 | |
#define MENU_FOG_EXP2 35 | |
#define MENU_QUIT 64 | |
#define SHADE_FLAT 128 | |
#define SHADE_AVG_VERTEX 129 | |
#define SHADE_TRUE_VERTEX 130 | |
#define NUM_VERTEX 3 // number of vertexes a triangle SHOULD have! | |
#define ROLL_SPEED 0.0030 // this is a weird number found through experimentation, | |
// that controls the speed of rolling, higher == faster | |
// 0.002 rolls fairly fast on my AMD 1.333 GHZ cpu, | |
// adjust for your CPU accordingly.. | |
struct triangleNode; // forward declaration of triangleNode to be used in triangleNodeList | |
struct triangleNodeList { // will contains a list of triangles that belong to a vertex or edge | |
triangleNode *triangle; | |
triangleNodeList *nxt; | |
}; | |
struct vertexNode { // vertex data will be loaded into this linked list of vertexes | |
GLfloat x; | |
GLfloat y; | |
GLfloat z; | |
// the average-normal vector subcomponents for this vertex | |
GLfloat normalX; | |
GLfloat normalY; | |
GLfloat normalZ; | |
triangleNodeList *myTriangles; | |
vertexNode *nxt; | |
}; | |
struct edgeNode { // edge data will be calculated based on vertex data loaded | |
vertexNode *vertex0; | |
vertexNode *vertex1; | |
triangleNodeList *myTriangles; | |
edgeNode *nxt; | |
}; | |
struct triangleNode { // triangle information will be interpolated based on vertex/edge data | |
vertexNode *vertex0; | |
vertexNode *vertex1; | |
vertexNode *vertex2; | |
// the normal vector subcomponents for this triangle | |
GLfloat normalX; | |
GLfloat normalY; | |
GLfloat normalZ; | |
triangleNode *nxt; | |
}; | |
vertexNode *enteredVertexes = NULL; //linked list containing vertexes loaded (initially empty) | |
edgeNode *enteredEdges = NULL; //linked list containing edges calculated | |
triangleNode *enteredTriangles = NULL; //linked list containing triangles interpolated | |
//from vertex data | |
static GLfloat myMatrix[16]; //viewing matrix that will be used to HSR algorithm | |
GLubyte Image[IMAGE_HEIGHT][IMAGE_WIDTH][4]; | |
GLuint Texture; | |
GLfloat noMaterialMatrix[] = {0, 0, 0, 1}; | |
GLfloat floorMaterialMatrix[] = {0, 1, 0}; | |
GLfloat sphereMaterialMatrix[] = {1, 0.84, 0}; | |
GLfloat fogColor[] = {0.7, 0.7, 0.7, 0.5}; | |
static GLfloat transX, transY, transZ, //amount to translate sphere | |
startX, startZ, //starting position of leg component | |
theta, rotateX, rotateZ, //amount to rotate sphere & on what axis | |
vRefPtX, vRefPtY, vRefPtZ, //reference point viewing coordinates | |
viewingX, viewingY, viewingZ; //transformable viewing coordinates | |
//state variables | |
static GLint hasStarted, // if prog has been started | |
isStopped, // if sphere is not rolling | |
useHSR, // whether to use hidden surface removal | |
useShading, // whether to use shading at all | |
vertexMode, // which vertex normals to use, actual or averaged | |
useSpotLight,// whether to use a spot light or not | |
fogMode, // type of fog | |
legOfCycle; // which leg of the trip the sphere is on | |
void varInit() { | |
// initialize variables at beginning of program | |
glClearColor(0.529, 0.807, 0.92, 0.0); | |
transX = LEG3_X, transY = 1.0, transZ = LEG3_Z, | |
startX = LEG3_X, startZ = LEG3_Z, | |
vRefPtX = 7, vRefPtY = 3,vRefPtZ = -10, | |
theta = 0, rotateX = 0,rotateZ = 0; | |
hasStarted = 0, isStopped = 1,useHSR = 0, | |
vertexMode = SHADE_FLAT, | |
useShading = 1, useSpotLight = 0, legOfCycle = 1; | |
glEnable(GL_DEPTH_TEST); | |
} | |
void setLightCutOff() { | |
if (useSpotLight) | |
glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 20); | |
else | |
glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 180); | |
} | |
void lightsInit() { | |
GLfloat globalAmbience[] = {1.0, 1.0, 1.0, 1}; | |
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, globalAmbience); | |
glEnable(GL_LIGHT0); | |
GLfloat light1Ambience[] = {0.0, 0.0, 0.0, 1}; | |
GLfloat light1Diffuse[] = {1.0, 1.0, 1.0, 1}; | |
GLfloat light1Specular[] = {1.0, 1.0, 1.0, 1}; | |
GLfloat light1Position[] = {-14.0, 12.0, -3.0, 1}; | |
GLfloat light1Direction[] = {8, -12, -1}; | |
glLightfv(GL_LIGHT1, GL_AMBIENT, light1Ambience); | |
glLightfv(GL_LIGHT1, GL_DIFFUSE, light1Diffuse); | |
glLightfv(GL_LIGHT1, GL_SPECULAR, light1Specular); | |
glLightfv(GL_LIGHT1, GL_POSITION, light1Position); | |
glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, light1Direction); | |
glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 2.0); | |
glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.01); | |
glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.001); | |
glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 5); | |
setLightCutOff(); | |
glEnable(GL_LIGHT1); | |
} | |
void imageInit(void) { | |
int i, j, c; | |
/* --- generate checkerboard image to the image array ---*/ | |
for (i = 0; i < IMAGE_HEIGHT; i++) | |
for (j = 0; j < IMAGE_HEIGHT; j++) | |
{ | |
c = (((i & 0x8) == 0) ^ ((j & 0x8) == 0)); | |
if (c == 1) /* white */ | |
{ | |
c = 255; | |
Image[i][j][0] = (GLubyte) c; | |
Image[i][j][1] = (GLubyte) c; | |
Image[i][j][2] = (GLubyte) c; | |
} | |
else /* green */ | |
{ | |
Image[i][j][0] = (GLubyte) 0; | |
Image[i][j][1] = (GLubyte) 150; | |
Image[i][j][2] = (GLubyte) 0; | |
} | |
Image[i][j][3] = (GLubyte) 255; | |
} | |
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |
glGenTextures(1, &Texture); | |
glBindTexture(GL_TEXTURE_2D, Texture); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, IMAGE_WIDTH, IMAGE_HEIGHT, | |
0, GL_RGBA, GL_UNSIGNED_BYTE, Image); | |
} /* end function */ | |
// calculate the dot product of two vectors, given by their components | |
inline GLdouble calcDotProduct(GLdouble x1, GLdouble y1, GLdouble z1, | |
GLdouble x2, GLdouble y2, GLdouble z2) { | |
return ((x1 * x2) + (y1 * y2) + (z1 * z2)); | |
} | |
void resetFog() { | |
glFogi(GL_FOG_MODE, fogMode); | |
glFogf(GL_FOG_START, 0.1); | |
glFogf(GL_FOG_END, 18.0); | |
glFogf(GL_FOG_DENSITY, 0.09); | |
glFogfv(GL_FOG_COLOR, fogColor); | |
} | |
// draw the sphere onto the screen | |
void drawSphere() { | |
glColor3f(1.0, 0.84, 0.0); // specify color of line/triangles to draw | |
if (useShading) { | |
glEnable(GL_LIGHTING); // enable lighting on this object | |
glEnable(GL_CULL_FACE); // enable culling of faces (to not draw uncessary ones) | |
glFrontFace(GL_CW); // set the face ordering to be clockwise (read top comments) | |
glCullFace(GL_BACK); // set to cull back facing triangles | |
glMaterialf(GL_FRONT, GL_SHININESS, 125); | |
glMaterialfv(GL_FRONT, GL_AMBIENT, noMaterialMatrix); | |
glMaterialfv(GL_FRONT, GL_DIFFUSE, sphereMaterialMatrix); | |
glMaterialfv(GL_FRONT, GL_SPECULAR, sphereMaterialMatrix); | |
glMaterialfv(GL_FRONT, GL_EMISSION, noMaterialMatrix); | |
glMaterialf(GL_FRONT, GL_SHININESS, 125); | |
triangleNode *currTriangle = enteredTriangles; | |
glBegin(GL_TRIANGLES); | |
if (vertexMode == SHADE_FLAT) { | |
while (currTriangle != NULL) { | |
// here we specify one normal for the entire triangle | |
glNormal3f(currTriangle->normalX, | |
currTriangle->normalY, | |
currTriangle->normalZ); | |
glVertex3f(currTriangle->vertex0->x, | |
currTriangle->vertex0->y, | |
currTriangle->vertex0->z); | |
glVertex3f(currTriangle->vertex1->x, | |
currTriangle->vertex1->y, | |
currTriangle->vertex1->z); | |
glVertex3f(currTriangle->vertex2->x, | |
currTriangle->vertex2->y, | |
currTriangle->vertex2->z); | |
currTriangle = currTriangle->nxt; | |
} | |
} else if (vertexMode == SHADE_AVG_VERTEX) { | |
while (currTriangle != NULL) { | |
// here we specify an averaged vertex normal for each vertex | |
glNormal3f(currTriangle->vertex0->normalX, | |
currTriangle->vertex0->normalY, | |
currTriangle->vertex0->normalZ); | |
glVertex3f(currTriangle->vertex0->x, | |
currTriangle->vertex0->y, | |
currTriangle->vertex0->z); | |
glNormal3f(currTriangle->vertex1->normalX, | |
currTriangle->vertex1->normalY, | |
currTriangle->vertex1->normalZ); | |
glVertex3f(currTriangle->vertex1->x, | |
currTriangle->vertex1->y, | |
currTriangle->vertex1->z); | |
glNormal3f(currTriangle->vertex2->normalX, | |
currTriangle->vertex2->normalY, | |
currTriangle->vertex2->normalZ); | |
glVertex3f(currTriangle->vertex2->x, | |
currTriangle->vertex2->y, | |
currTriangle->vertex2->z); | |
currTriangle = currTriangle->nxt; | |
} | |
} else if (vertexMode == SHADE_TRUE_VERTEX) { | |
while (currTriangle != NULL) { | |
// here we specify the true triangle normal for each vertex | |
glNormal3f(currTriangle->normalX, | |
currTriangle->normalY, | |
currTriangle->normalZ); | |
glVertex3f(currTriangle->vertex0->x, | |
currTriangle->vertex0->y, | |
currTriangle->vertex0->z); | |
glNormal3f(currTriangle->normalX, | |
currTriangle->normalY, | |
currTriangle->normalZ); | |
glVertex3f(currTriangle->vertex1->x, | |
currTriangle->vertex1->y, | |
currTriangle->vertex1->z); | |
glNormal3f(currTriangle->normalX, | |
currTriangle->normalY, | |
currTriangle->normalZ); | |
glVertex3f(currTriangle->vertex2->x, | |
currTriangle->vertex2->y, | |
currTriangle->vertex2->z); | |
currTriangle = currTriangle->nxt; | |
} | |
} | |
glEnd (); | |
glDisable(GL_CULL_FACE); | |
glDisable(GL_LIGHTING); | |
} else { // we're drawing wireframe | |
edgeNode *currEdge = enteredEdges; // use the entered edge list | |
glBegin(GL_LINES); | |
while (currEdge != NULL) { // loop through all edges | |
// if using Hidden Surface Removal, and neither of the edge's triangles are visible.. | |
// note the negated normals, read top comments for more information | |
if (useHSR && calcDotProduct(-currEdge->myTriangles->triangle->normalX, | |
-currEdge->myTriangles->triangle->normalY, | |
-currEdge->myTriangles->triangle->normalZ, | |
viewingX, viewingY, viewingZ) >= 0 && | |
calcDotProduct(-currEdge->myTriangles->nxt->triangle->normalX, | |
-currEdge->myTriangles->nxt->triangle->normalY, | |
-currEdge->myTriangles->nxt->triangle->normalZ, | |
viewingX, viewingY, viewingZ) >= 0) { | |
currEdge = currEdge->nxt; // traverse to the next edge.. | |
continue; // and skip the drawing draw | |
} else { // draw all wireframes | |
// draw the line for the current edge based on its two vertexes | |
glVertex3f(currEdge->vertex0->x, currEdge->vertex0->y, currEdge->vertex0->z); | |
glVertex3f(currEdge->vertex1->x, currEdge->vertex1->y, currEdge->vertex1->z); | |
currEdge = currEdge->nxt; // linked list traversal | |
} | |
} // done drawing all edges | |
glEnd(); | |
} | |
} | |
void setupRotationParams(GLfloat x1, GLfloat z1, GLfloat x2, GLfloat z2, GLint legOfCycle) { | |
// modify the state variables that determine the amount to rotate, translate and on which vector | |
GLfloat moveX = (x2 - x1) * ROLL_SPEED, // sphere moved this amount on this iteration | |
moveZ = (z2 - z1) * ROLL_SPEED; | |
transX += moveX, transZ += moveZ;// add the moved amount to the current amount | |
GLfloat distance = sqrt (moveX * moveX + moveZ * moveZ); // determine distance | |
if (legOfCycle == 3) distance = -distance; // negate distance if back at starting point | |
theta += distance * 180 / 3.14; // determine angle of rotation based on distance moved | |
if (theta >= 360) theta -= 360; // if theta overflow, correct | |
rotateX = 1.0 / (x2 - x1); // determine rotational axis vector | |
rotateZ = -1.0 / (z2 - z1); | |
glutPostRedisplay(); // re-draw | |
} | |
void animateRotatingSphere() { | |
// sphere has rolled passed limits of the first leg | |
if (transX < LEG1_X && transZ < LEG1_Z && legOfCycle == 1) { | |
legOfCycle = 2; | |
startX = transX; | |
startZ = transZ; | |
} | |
// sphere has rolled passed limits of second leg | |
else if (transX > LEG2_X && transZ > LEG2_Z && legOfCycle == 2) { | |
legOfCycle = 3; | |
startX = transX; | |
startZ = transZ; | |
} | |
// sphere has rolled passed limits of last leg | |
else if (transX < LEG3_X && transZ > LEG3_Z && legOfCycle == 3) { | |
legOfCycle = 1; | |
startX = transX; | |
startZ = transZ; | |
} | |
// modify rolling parameters depending on which leg we're in | |
switch (legOfCycle) { | |
case 1: | |
setupRotationParams(startX, startZ, LEG1_X, LEG1_Z, legOfCycle); break; | |
case 2: | |
setupRotationParams(startX, startZ, LEG2_X, LEG2_Z, legOfCycle); break; | |
case 3: | |
setupRotationParams(startX, startZ, LEG3_X, LEG3_Z, legOfCycle); break; | |
} | |
} | |
void startRolling() { | |
// start the rolling of the sphere | |
isStopped = 0; | |
if (hasStarted) | |
glutIdleFunc(animateRotatingSphere); | |
} | |
void menuMainHandler(int id) { | |
// handles main menu items | |
if (id == MENU_DEFAULT_VIEW) { | |
vRefPtX = 7.0; | |
vRefPtY = 3.0; | |
vRefPtZ = -10.0; | |
} else if (id == MENU_QUIT) | |
exit (0); | |
glutPostRedisplay(); // explicitly re-draw! | |
if (isStopped) startRolling(); | |
} | |
void menuWireFrameHandler(int id) { | |
useShading = 0; | |
if (id == MENU_NO_HSR) useHSR = 0; | |
else if (id == MENU_HSR) useHSR = 1; | |
glutPostRedisplay(); // explicitly re-draw! | |
if (isStopped) startRolling(); | |
} | |
void menuShadingSmoothHandler(int id) { | |
useShading = 1; | |
glShadeModel(GL_SMOOTH); | |
if (id == MENU_SHADE_TVN) | |
vertexMode = SHADE_TRUE_VERTEX; | |
else if (id == MENU_SHADE_AVN) | |
vertexMode = SHADE_AVG_VERTEX; | |
glutPostRedisplay(); // explicitly re-draw! | |
if (isStopped) startRolling(); | |
} | |
void menuShadingHandler(int id) { | |
useShading = 1; | |
glShadeModel(GL_FLAT); | |
if (id == MENU_SHADE_FLAT) | |
vertexMode = SHADE_FLAT; | |
glutPostRedisplay(); // explicitly re-draw! | |
if (isStopped) startRolling(); | |
} | |
void menuLightingHandler(int id) { | |
if (id == MENU_LIGHT_SPOT) { | |
useSpotLight = 1; | |
} else if (id == MENU_LIGHT_POINT) | |
useSpotLight = 0; | |
setLightCutOff(); | |
glutPostRedisplay(); // explicitly re-draw! | |
if (isStopped) startRolling(); | |
} | |
void menuFogHandler(int id) { | |
if (id == MENU_NO_FOG) glDisable (GL_FOG); | |
else if (id == MENU_FOG_LINEAR) fogMode = GL_LINEAR; | |
else if (id == MENU_FOG_EXP) fogMode = GL_EXP; | |
else if (id == MENU_FOG_EXP2) fogMode = GL_EXP2; | |
if (id == MENU_FOG_LINEAR || id == MENU_FOG_EXP || id == MENU_FOG_EXP2) { | |
glEnable(GL_FOG); | |
resetFog(); | |
} | |
glutPostRedisplay(); // explicitly re-draw! | |
if (isStopped) startRolling(); | |
} | |
void menuInit() { | |
// sets up menu definitions | |
int menuWireFrame = glutCreateMenu(menuWireFrameHandler); | |
glutAddMenuEntry("without hidden edge removal",MENU_NO_HSR); | |
glutAddMenuEntry("with hidden edge removal", MENU_HSR); | |
int menuShadingSmooth = glutCreateMenu(menuShadingSmoothHandler); | |
glutAddMenuEntry("True Vertex Normals", MENU_SHADE_TVN); | |
glutAddMenuEntry("Averaged Vertex Normals", MENU_SHADE_AVN); | |
int menuShading = glutCreateMenu(menuShadingHandler); | |
glutAddMenuEntry("Flat Shading", MENU_SHADE_FLAT); | |
glutAddSubMenu("Smooth Shading", menuShadingSmooth); | |
int menuLighting = glutCreateMenu(menuLightingHandler); | |
glutAddMenuEntry("Spot Light", MENU_LIGHT_SPOT); | |
glutAddMenuEntry("Point Source Light", MENU_LIGHT_POINT); | |
int menuFog = glutCreateMenu (menuFogHandler); | |
glutAddMenuEntry("No Fog", MENU_NO_FOG); | |
glutAddMenuEntry("Linear Fog", MENU_FOG_LINEAR); | |
glutAddMenuEntry("Exponential Fog", MENU_FOG_EXP); | |
glutAddMenuEntry("Exponential Squared Fog", MENU_FOG_EXP2); | |
glutCreateMenu(menuMainHandler); | |
glutAddMenuEntry("Default View Point", MENU_DEFAULT_VIEW); | |
glutAddSubMenu("Wire Frame", menuWireFrame); | |
glutAddSubMenu("Fog Options", menuFog); | |
glutAddSubMenu("Shading", menuShading); | |
glutAddSubMenu("Lighting", menuLighting); | |
glutAddMenuEntry("Quit", MENU_QUIT); | |
glutAttachMenu(GLUT_LEFT_BUTTON); | |
} | |
void display() { | |
// draws the sphere | |
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); | |
if (useHSR) { // only perform these calculations if we're using HSR. | |
glLoadIdentity(); | |
glRotatef(theta, rotateX, 0, rotateZ); | |
glGetFloatv(GL_MODELVIEW_MATRIX, myMatrix); | |
GLfloat tempX, tempY, tempZ; | |
viewingX = vRefPtX; viewingY = vRefPtY; viewingZ = vRefPtZ; | |
// manually multiply this matrix | |
tempX = viewingX * myMatrix[0] + viewingY * myMatrix[1] + viewingZ * myMatrix[2]; | |
tempY = viewingX * myMatrix[4] + viewingY * myMatrix[5] + viewingZ * myMatrix[6]; | |
tempZ = viewingX * myMatrix[8] + viewingY * myMatrix[9] + viewingZ * myMatrix[10]; | |
viewingX = tempX; viewingY = tempY; viewingZ = tempZ; | |
} | |
glLoadIdentity(); // load identity matrix | |
gluLookAt(vRefPtX,vRefPtY,vRefPtZ,0,0,0,0,1,0); // setup viewing | |
// draw green plane | |
setLightCutOff(); | |
glEnable(GL_LIGHTING); | |
glEnable(GL_TEXTURE_2D); | |
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); | |
glBindTexture(GL_TEXTURE_2D, Texture); | |
glMaterialfv(GL_FRONT, GL_AMBIENT, noMaterialMatrix); | |
glMaterialfv(GL_FRONT, GL_SPECULAR, noMaterialMatrix); | |
glMaterialfv(GL_FRONT, GL_DIFFUSE, floorMaterialMatrix); | |
glMaterialfv(GL_FRONT, GL_EMISSION, noMaterialMatrix); | |
glMaterialf(GL_FRONT, GL_SHININESS, 0); | |
glNormal3f(0.0, 1.0, 0.0); // set normal of ground | |
glBegin(GL_QUADS); | |
glColor3f (0, 1, 0); | |
glTexCoord2f(0, 0); glVertex4i(5,0,8,1); | |
glTexCoord2f(0, 3); glVertex4i(5,0,-4,1); | |
glTexCoord2f(2.5, 3.0); glVertex4i(-5,0,-4,1); | |
glTexCoord2f(2.5, 0); glVertex4i(-5,0,8,1); | |
glEnd(); | |
glDisable(GL_TEXTURE_2D); | |
glDisable(GL_LIGHTING); | |
glBegin(GL_LINES); | |
glColor3f(1, 0, 0); glVertex4f(0, 0.01, 0, 1); glVertex4f(10, 0.01, 0, 1); // red x-axis | |
glColor3f(1, 0, 1); glVertex4f(0, 10, 0, 1); glVertex4f(0, 0, 0, 1); // magenta y-axis | |
glColor3f(0, 0, 1); glVertex4f(0, 0.01, 0, 1); glVertex4f(0, 0.01, 10, 1); // blue z-axis | |
glEnd(); | |
glTranslatef(transX, transY, transZ); // modify matrix for translation | |
glRotatef(theta, rotateX, 0, rotateZ); // modify matrix for rotation | |
drawSphere(); // draw our wonderful sphere | |
glFlush(); // flush system so everything gets drawn | |
glutSwapBuffers(); // switch to other buffer (we're using double buffering) | |
} | |
void myKeyHandler(unsigned char key, int mouseX, int mouseY) { | |
// start the rolling | |
if (key == 'S' || key == 's') { | |
hasStarted = 1; startRolling(); | |
} | |
// handle navigation keys | |
else if (key == 'X') vRefPtX += 1; else if (key == 'x') vRefPtX -= 1; | |
else if (key == 'Y') vRefPtY += 1; else if (key == 'y') vRefPtY -= 1; | |
else if (key == 'Z') vRefPtZ += 1; else if (key == 'z') vRefPtZ -= 1; | |
// exit program | |
else if (key == 'Q' || key == 'q') exit(0); | |
glutPostRedisplay(); // re-draw | |
} | |
void myMouseHandler(int button, int state, int x, int y) { | |
// pause the rolling of the sphere (if rolling has been started) | |
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN && hasStarted) { | |
if (isStopped) { | |
startRolling(); | |
} else { | |
isStopped = 1; | |
glutIdleFunc(NULL); | |
} | |
} | |
} | |
void myReshape(int w, int h) { | |
// called when first drawn and when window is resized, moved, etc. | |
glViewport(0,0,(GLsizei) w, (GLsizei) h); | |
glMatrixMode(GL_PROJECTION); | |
glLoadIdentity(); | |
gluPerspective (50.0, (GLfloat) w/(GLfloat) h, 0.1, 25.0); | |
glMatrixMode(GL_MODELVIEW); | |
} | |
void loadSphere(const char* filename) { | |
ifstream infile; infile.open(filename); | |
if (infile.fail()) { | |
cout << "Error, cannot open file " << filename << endl; | |
exit(0); | |
} | |
int numVertexes; // will be entered from file | |
int numTriangles; // will be entered from file | |
GLfloat length; // will be entered from file | |
/* part of hash code, see below | |
#define HASHSIZE 24000 | |
int hashtable[HASHSIZE]; | |
int hashkey; | |
for (hashkey=0; hashkey < HASHSIZE; hashkey++) { | |
hashtable[hashkey] = 0; | |
} | |
*/ | |
vertexNode *currVertex, *newVertex, tempVertex[NUM_VERTEX]; | |
edgeNode *currEdge, *newEdge, *tempEdge; | |
triangleNode *currTriangle; | |
triangleNodeList *currTriangleList; | |
// read in number of triangles and loop through each triangle. | |
for (infile >> numTriangles; numTriangles > 0; numTriangles--) { | |
// create a new triangle | |
currTriangle = new triangleNode; | |
infile >> numVertexes; // how many vertexes does this triangle have? | |
assert(numVertexes == NUM_VERTEX); // it should be 3!! | |
for (;numVertexes > 0; numVertexes--) { | |
infile >> tempVertex[numVertexes-1].x // read each coordinate.. | |
>> tempVertex[numVertexes-1].y // into the array.. | |
>> tempVertex[numVertexes-1].z; // for the current vertex.. | |
tempVertex[numVertexes-1].nxt = NULL; // being processed. | |
// linear search through the already-entered-vertex-list | |
currVertex = enteredVertexes; | |
while (currVertex != NULL) | |
// check to see if the current vertex was already entered | |
if ((currVertex->x == tempVertex[numVertexes-1].x) && | |
(currVertex->y == tempVertex[numVertexes-1].y) && | |
(currVertex->z == tempVertex[numVertexes-1].z)) { | |
// if it was found, save it's location in the temporary vertex array | |
tempVertex[numVertexes-1].nxt = currVertex; | |
currVertex = NULL; // and exit the loops. | |
} else | |
currVertex = currVertex->nxt; // otherwise try next entered vertex | |
/* the following is the hash code that just DIDN'T want to work properly!! | |
// reset hash key to 0 | |
hashkey = 0; | |
// add positive integer x contribution | |
if (tempVertex[numVertexes-1].x < 0) | |
hashkey += int(-(tempVertex[numVertexes-1].x*10000)); | |
else | |
hashkey += int(tempVertex[numVertexes-1].x*10000); | |
// add positive integer y contribution | |
if (tempVertex[numVertexes-1].y < 0) | |
hashkey += int(-(tempVertex[numVertexes-1].y*100000)); | |
else | |
hashkey += int(tempVertex[numVertexes-1].y*100000); | |
// add positive integer z contribution | |
if (tempVertex[numVertexes-1].z < 0) | |
hashkey += int(-(tempVertex[numVertexes-1].z*1000000)); | |
else | |
hashkey += int(tempVertex[numVertexes-1].z*1000000); | |
hashkey = hashkey % 23997; | |
// if we ended up NOT finding the current vertex in the hashtable... | |
if (hashtable[hashkey] == 0) { | |
hashtable[hashkey] = 1; | |
// the stuff below would be here. | |
} | |
*/ | |
if (tempVertex[numVertexes-1].nxt == NULL) { | |
// create a new vertex node and set its values to the current vertex | |
newVertex = new vertexNode; | |
newVertex->x = tempVertex[numVertexes-1].x; | |
newVertex->y = tempVertex[numVertexes-1].y; | |
newVertex->z = tempVertex[numVertexes-1].z; | |
newVertex->myTriangles = NULL; | |
// add this vertex to [the beginning of] the list of entered vertexes | |
newVertex->nxt = enteredVertexes; | |
enteredVertexes = newVertex; | |
// remember this new vertex's location in the temporary vertex array | |
tempVertex[numVertexes-1].nxt = newVertex; | |
} | |
} // done processing all vertexes of the current triangle | |
// process the first two vertex's edge.. | |
// set up traversal through the already-entered-edge-list | |
tempEdge = NULL; currEdge = enteredEdges; | |
while (currEdge != NULL) | |
// check to see if this vertex pair already has been entered | |
if (((currEdge->vertex0->x == tempVertex[0].nxt->x) && (currEdge->vertex0->y == | |
tempVertex[0].nxt->y) && (currEdge->vertex0->z == tempVertex[0].nxt->z) && | |
(currEdge->vertex1->x == tempVertex[1].nxt->x) && (currEdge->vertex1->y == | |
tempVertex[1].nxt->y) && (currEdge->vertex1->z == tempVertex[1].nxt->z)) || | |
((currEdge->vertex0->x == tempVertex[1].nxt->x) && (currEdge->vertex0->y == | |
tempVertex[1].nxt->y) && (currEdge->vertex0->z == tempVertex[1].nxt->z) && | |
(currEdge->vertex1->x == tempVertex[0].nxt->x) && (currEdge->vertex1->y == | |
tempVertex[0].nxt->y) && (currEdge->vertex1->z == tempVertex[0].nxt->z))) { | |
// it has? then save it and end traversal | |
tempEdge = currEdge; currEdge = NULL; | |
} else | |
currEdge = currEdge->nxt; // otherwise proceed to next edge in list | |
// edge has not been found, creating new one, setting values, adding to list | |
if (tempEdge == NULL) { | |
newEdge = new edgeNode; newEdge->myTriangles = NULL; | |
newEdge->vertex0 = tempVertex[0].nxt; newEdge->vertex1 = tempVertex[1].nxt; | |
newEdge->nxt = enteredEdges; enteredEdges = newEdge; | |
tempEdge = newEdge; | |
} | |
// updating the edge's triangle-children list | |
currTriangleList = new triangleNodeList; currTriangleList->nxt = tempEdge->myTriangles; | |
currTriangleList->triangle = currTriangle; tempEdge->myTriangles = currTriangleList; | |
// process the second two vertex's edge.. | |
// set up traversal through the already-entered-edge-list | |
tempEdge = NULL; currEdge = enteredEdges; | |
while (currEdge != NULL) | |
// check to see if this vertex pair already has been entered | |
if (((currEdge->vertex1->x == tempVertex[1].nxt->x) && (currEdge->vertex1->y == | |
tempVertex[1].nxt->y) && (currEdge->vertex1->z == tempVertex[1].nxt->z) && | |
(currEdge->vertex0->x == tempVertex[2].nxt->x) && (currEdge->vertex0->y == | |
tempVertex[2].nxt->y) && (currEdge->vertex0->z == tempVertex[2].nxt->z)) || | |
((currEdge->vertex1->x == tempVertex[2].nxt->x) && (currEdge->vertex1->y == | |
tempVertex[2].nxt->y) && (currEdge->vertex1->z == tempVertex[2].nxt->z) && | |
(currEdge->vertex0->x == tempVertex[1].nxt->x) && (currEdge->vertex0->y == | |
tempVertex[1].nxt->y) && (currEdge->vertex0->z == tempVertex[1].nxt->z))) { | |
// it has? then save it and end traversal | |
tempEdge = currEdge; currEdge = NULL; | |
} else | |
currEdge = currEdge->nxt; // otherwise proceed to next edge in list | |
// edge has not been found, creating new one, setting values, adding to list | |
if (tempEdge == NULL) { | |
newEdge = new edgeNode; newEdge->myTriangles = NULL; | |
newEdge->vertex1 = tempVertex[1].nxt; newEdge->vertex0 = tempVertex[2].nxt; | |
newEdge->nxt = enteredEdges; enteredEdges = newEdge; | |
tempEdge = newEdge; | |
} | |
// updating the edge's triangle-children list | |
currTriangleList = new triangleNodeList; currTriangleList->nxt = tempEdge->myTriangles; | |
currTriangleList->triangle = currTriangle; tempEdge->myTriangles = currTriangleList; | |
// process the last two vertex's edge.. | |
// set up traversal through the already-entered-edge-list | |
tempEdge = NULL; currEdge = enteredEdges; | |
while (currEdge != NULL) | |
// check to see if this vertex pair already has been entered | |
if (((currEdge->vertex0->x == tempVertex[0].nxt->x) && (currEdge->vertex0->y == | |
tempVertex[0].nxt->y) && (currEdge->vertex0->z == tempVertex[0].nxt->z) && | |
(currEdge->vertex1->x == tempVertex[2].nxt->x) && (currEdge->vertex1->y == | |
tempVertex[2].nxt->y) && (currEdge->vertex1->z == tempVertex[2].nxt->z)) || | |
((currEdge->vertex0->x == tempVertex[2].nxt->x) && (currEdge->vertex0->y == | |
tempVertex[2].nxt->y) && (currEdge->vertex0->z == tempVertex[2].nxt->z) && | |
(currEdge->vertex1->x == tempVertex[0].nxt->x) && (currEdge->vertex1->y == | |
tempVertex[0].nxt->y) && (currEdge->vertex1->z == tempVertex[0].nxt->z))) { | |
// it has? then save it and end traversal | |
tempEdge = currEdge; currEdge = NULL; | |
} else | |
currEdge = currEdge->nxt; // otherwise proceed to next edge in list | |
// edge has not been found, creating new one, setting values, adding to list | |
if (tempEdge == NULL) { | |
newEdge = new edgeNode; newEdge->myTriangles = NULL; | |
newEdge->vertex0 = tempVertex[0].nxt; newEdge->vertex1 = tempVertex[2].nxt; | |
newEdge->nxt = enteredEdges; enteredEdges = newEdge; | |
tempEdge = newEdge; | |
} | |
// updating the edge's triangle-children list | |
currTriangleList = new triangleNodeList; currTriangleList->nxt = tempEdge->myTriangles; | |
currTriangleList->triangle = currTriangle; tempEdge->myTriangles = currTriangleList; | |
// back to triangles: | |
// set triangle's vertexes, and update each vertex's triangle children list | |
currTriangle->vertex0 = tempVertex[0].nxt; | |
currTriangleList = new triangleNodeList; | |
currTriangleList->nxt = currTriangle->vertex0->myTriangles; | |
currTriangleList->triangle = currTriangle; | |
currTriangle->vertex0->myTriangles = currTriangleList; | |
currTriangle->vertex1 = tempVertex[1].nxt; | |
currTriangleList = new triangleNodeList; | |
currTriangleList->nxt = currTriangle->vertex1->myTriangles; | |
currTriangleList->triangle = currTriangle; | |
currTriangle->vertex1->myTriangles = currTriangleList; | |
currTriangle->vertex2 = tempVertex[2].nxt; | |
currTriangleList = new triangleNodeList; | |
currTriangleList->nxt = currTriangle->vertex2->myTriangles; | |
currTriangleList->triangle = currTriangle; | |
currTriangle->vertex2->myTriangles = currTriangleList; | |
// and add it to the entered-triangle list | |
currTriangle->nxt = enteredTriangles; | |
enteredTriangles = currTriangle; | |
// calculate normal for the triangle | |
currTriangle->normalX = (currTriangle->vertex1->y - currTriangle->vertex0->y) * | |
(currTriangle->vertex2->z - currTriangle->vertex0->z) - | |
(currTriangle->vertex1->z - currTriangle->vertex0->z) * | |
(currTriangle->vertex2->y - currTriangle->vertex0->y); | |
currTriangle->normalY = (currTriangle->vertex1->z - currTriangle->vertex0->z) * | |
(currTriangle->vertex2->x - currTriangle->vertex0->x) - | |
(currTriangle->vertex1->x - currTriangle->vertex0->x) * | |
(currTriangle->vertex2->z - currTriangle->vertex0->z); | |
currTriangle->normalZ = (currTriangle->vertex1->x - currTriangle->vertex0->x) * | |
(currTriangle->vertex2->y - currTriangle->vertex0->y) - | |
(currTriangle->vertex1->y - currTriangle->vertex0->y) * | |
(currTriangle->vertex2->x - currTriangle->vertex0->x); | |
length = -(sqrt(currTriangle->normalX * currTriangle->normalX + | |
currTriangle->normalY * currTriangle->normalY + | |
currTriangle->normalZ * currTriangle->normalZ)); | |
// store normal | |
currTriangle->normalX /= length; | |
currTriangle->normalY /= length; | |
currTriangle->normalZ /= length; | |
} // done processing all triangles | |
// calculating average vertex normals | |
GLfloat tempX, tempY, tempZ, vectorLength; | |
currVertex = enteredVertexes; | |
while (currVertex != NULL) { | |
tempX = 0, tempY = 0, tempZ = 0; | |
currTriangleList = currVertex->myTriangles; | |
while (currTriangleList != NULL) { | |
tempX += currTriangleList->triangle->normalX; | |
tempY += currTriangleList->triangle->normalY; | |
tempZ += currTriangleList->triangle->normalZ; | |
currTriangleList = currTriangleList->nxt; | |
} | |
vectorLength = sqrt(tempX*tempX+tempY*tempY+tempZ*tempZ); | |
currVertex->normalX = tempX/vectorLength; | |
currVertex->normalY = tempY/vectorLength; | |
currVertex->normalZ = tempZ/vectorLength; | |
currVertex = currVertex->nxt; | |
} | |
} | |
void main(int argc, char **argv) { | |
glutInit(&argc,argv); | |
if (argc < 2) { | |
cout << "Requires one argument, which file to open" << endl; | |
exit(0); | |
} | |
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB); | |
// position & draw the right window size w/ title | |
glutInitWindowPosition(XOFFSET, YOFFSET); | |
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT); | |
glutCreateWindow("CS653 Assignment 4"); | |
glutReshapeFunc(myReshape); // set up reshape method | |
glutDisplayFunc(display); // set our display method | |
glutIdleFunc(NULL); // initially the program does not roll | |
glutKeyboardFunc(myKeyHandler); // set keyboard handler | |
glutMouseFunc(myMouseHandler); // set mouse handler | |
loadSphere(argv[1]); // load the sphere and perform sphere calculations | |
varInit(); // initiate our variables | |
menuInit(); // setup our menus | |
imageInit(); // setup texture mapping for floor | |
lightsInit(); // setup lights position, intensity, type, etc.. | |
glutMainLoop(); // let her loose! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment