893 lines
23 KiB
C++
893 lines
23 KiB
C++
|
|
/* cs4451_a2.cpp */
|
|
/*
|
|
* Jose Caban
|
|
* gtg184g
|
|
* proj2
|
|
*/
|
|
|
|
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <iostream>
|
|
#include <assert.h>
|
|
|
|
#ifdef _OS_LINUX_
|
|
#include <GL/gl.h>
|
|
#include <GL/glu.h>
|
|
#endif
|
|
|
|
//Windows only needs glut.h care of SGI ;)
|
|
#include <GL/glut.h>
|
|
|
|
|
|
#define VPD_MIN 200
|
|
#define VPD_DEFAULT 800
|
|
#define VPD_MAX 1024
|
|
|
|
enum MENU { MENU_SWITCH_SHADING=0,
|
|
MENU_ZOOM_IN,
|
|
MENU_ZOOM_OUT,
|
|
MENU_POINTS,
|
|
MENU_LINES,
|
|
MENU_TRIANGLES,
|
|
MENU_SWITCH_LIGHT,
|
|
MENU_SWITCH_CULLING,
|
|
MENU_TURN_OFF_CULLING,
|
|
MENU_TURN_ON_CULLING,
|
|
MENU_RESET_MODELVIEW
|
|
};
|
|
|
|
|
|
|
|
#define TWOPI (2.0 * M_PI)
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
//Define the Normal type
|
|
typedef struct SNormal {
|
|
GLfloat i;
|
|
GLfloat j;
|
|
GLfloat k;
|
|
} SNormal;
|
|
|
|
typedef struct SPoint {
|
|
GLfloat x;
|
|
GLfloat y;
|
|
GLfloat z;
|
|
} SPoint;
|
|
|
|
//Define the Vertex type for use in keeping track of Vertices
|
|
typedef struct SVertex {
|
|
SNormal normal;
|
|
GLfloat x;
|
|
GLfloat y;
|
|
GLfloat z;
|
|
} SVertex;
|
|
|
|
//Define the Data structure that will hold all the vertices
|
|
typedef struct SVertexList {
|
|
SVertex* vertices;
|
|
int length;
|
|
} SVertexList;
|
|
|
|
//Define a Triangle (a1,a2,a3 are indices to the SVertexList
|
|
typedef struct STriangle {
|
|
SNormal normal;
|
|
GLint a1,a2,a3;
|
|
} STriangle;
|
|
|
|
typedef struct STriangleList {
|
|
STriangle* triangles;
|
|
GLint length;
|
|
} STriangleList;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////
|
|
// Globals
|
|
|
|
SVertexList vertexList;
|
|
STriangleList triList;
|
|
GLfloat currModelTransform[16];
|
|
|
|
GLint wid; /* GLUT window id */
|
|
GLint vpd = VPD_DEFAULT; /* (square) viewport dimensions */
|
|
|
|
GLuint triangleScene; /* display list ID */
|
|
GLuint gouraudID; /* gouraud display list ID */
|
|
GLuint flatID; /* flat display list ID */
|
|
|
|
GLfloat angle1 = 0; /* angles used in animation */
|
|
GLfloat angle2 = 0;
|
|
GLfloat dangle1 = 0.57;
|
|
GLfloat dangle2 = 0.71;
|
|
|
|
GLdouble viewDist = 8.0; /* Changes the view distance view */
|
|
|
|
GLuint cullMode = GL_BACK;
|
|
GLboolean worldLight = GL_TRUE;
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
|
|
///////////////////////////////////////////////////////
|
|
//Functions
|
|
|
|
/*
|
|
* Input scanner
|
|
*/
|
|
void scanInput(GLvoid);
|
|
|
|
/*
|
|
* Initialize the Light Source
|
|
*/
|
|
GLvoid init_lightsource ( GLvoid )
|
|
{
|
|
GLfloat light_ambient[] = { .1, .1, .1, 1.0 };
|
|
GLfloat light_diffuse[] = { .9, .9, .9, 1.0 };
|
|
GLfloat light_specular[] = { 0, 0, 0, 1.0 };
|
|
GLfloat light_position[] = { 2.0, 2.0, 2.0, 0.0 };
|
|
|
|
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
|
|
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
|
|
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
|
|
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
|
|
glLightf(GL_LIGHT0,GL_CONSTANT_ATTENUATION,1.0);
|
|
glLightf(GL_LIGHT0,GL_LINEAR_ATTENUATION,0.0);
|
|
glLightf(GL_LIGHT0,GL_QUADRATIC_ATTENUATION,0.0);
|
|
|
|
glEnable(GL_LIGHTING);
|
|
glEnable(GL_LIGHT0);
|
|
}
|
|
|
|
GLvoid set_material_properties ( GLfloat r, GLfloat g, GLfloat b )
|
|
{
|
|
GLfloat mat_specular[4] = { 0.0, 0.0, 0.0, 1.0 };
|
|
GLfloat mat_ambient_and_diffuse[4] = { 0.5, 0.5, 0.5, 1.0 };
|
|
GLfloat mat_shininess[1] = { 0.0 };
|
|
|
|
mat_specular[0] = mat_ambient_and_diffuse[0] = r;
|
|
mat_specular[1] = mat_ambient_and_diffuse[1] = g;
|
|
mat_specular[2] = mat_ambient_and_diffuse[2] = b;
|
|
|
|
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
|
|
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
|
|
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat_ambient_and_diffuse);
|
|
|
|
}
|
|
|
|
|
|
inline void cross(SNormal& dest, SVertex& a, SVertex& b) {
|
|
dest.i = ( (a.y*b.z) - (a.z*b.y) ); //i
|
|
dest.j = ( (a.z*b.x) - (a.x*b.z) ); //j
|
|
dest.k = ( (a.x*b.y) - (a.y*b.x) ); //k
|
|
}
|
|
|
|
|
|
/*
|
|
* Initialize the scene
|
|
*
|
|
*/
|
|
GLuint init_flat_scene ( )
|
|
{
|
|
GLuint sceneList = glGenLists(1);
|
|
|
|
SNormal tempNormal;
|
|
SVertex a1, a2, a3;
|
|
|
|
glNewList(sceneList,GL_COMPILE);
|
|
glBegin(GL_TRIANGLES);
|
|
|
|
for (int i = 0; i < triList.length; i++) {
|
|
|
|
a1 = vertexList.vertices[triList.triangles[i].a1];
|
|
a2 = vertexList.vertices[triList.triangles[i].a2];
|
|
a3 = vertexList.vertices[triList.triangles[i].a3];
|
|
|
|
tempNormal = triList.triangles[i].normal;
|
|
|
|
glNormal3f(tempNormal.i, tempNormal.j, tempNormal.k);
|
|
|
|
glVertex3f(a1.x, a1.y, a1.z);
|
|
glVertex3f(a2.x, a2.y, a2.z);
|
|
glVertex3f(a3.x, a3.y, a3.z);
|
|
}
|
|
|
|
glEnd();
|
|
|
|
glEndList();
|
|
|
|
return sceneList;
|
|
}
|
|
|
|
|
|
/*
|
|
* Initialize the gouraud scene
|
|
*/
|
|
GLuint init_gouraud_scene ( )
|
|
{
|
|
GLuint sceneList = glGenLists(1);
|
|
|
|
SNormal tempNormal;
|
|
SVertex a1, a2, a3;
|
|
|
|
glNewList(sceneList,GL_COMPILE);
|
|
glBegin(GL_TRIANGLES);
|
|
|
|
for (int i = 0; i < triList.length; i++) {
|
|
|
|
a1 = vertexList.vertices[triList.triangles[i].a1];
|
|
a2 = vertexList.vertices[triList.triangles[i].a2];
|
|
a3 = vertexList.vertices[triList.triangles[i].a3];
|
|
|
|
tempNormal = a1.normal;
|
|
glNormal3f(tempNormal.i, tempNormal.j, tempNormal.k);
|
|
glVertex3f(a1.x, a1.y, a1.z);
|
|
|
|
tempNormal = a2.normal;
|
|
glNormal3f(tempNormal.i, tempNormal.j, tempNormal.k);
|
|
glVertex3f(a2.x, a2.y, a2.z);
|
|
|
|
tempNormal = a3.normal;
|
|
glNormal3f(tempNormal.i, tempNormal.j, tempNormal.k);
|
|
glVertex3f(a3.x, a3.y, a3.z);
|
|
}
|
|
|
|
glEnd();
|
|
|
|
glEndList();
|
|
|
|
return sceneList;
|
|
}
|
|
|
|
|
|
GLuint create_scene(GLuint triangleList) {
|
|
GLuint sceneList = glGenLists(1);
|
|
|
|
glNewList(sceneList,GL_COMPILE);
|
|
|
|
set_material_properties(1.0,1.0,1.0);
|
|
|
|
/* Correctly size the object */
|
|
assert(vertexList.length > 0);
|
|
|
|
SVertex Max;
|
|
SVertex Min;
|
|
SVertex Center;
|
|
|
|
Max.x = Min.x = vertexList.vertices[0].x;
|
|
Max.y = Min.y = vertexList.vertices[0].y;
|
|
Max.z = Min.z = vertexList.vertices[0].z;
|
|
|
|
for (int i = 1; i < vertexList.length; i++) {
|
|
if (vertexList.vertices[i].x > Max.x) {
|
|
Max.x = vertexList.vertices[i].x;
|
|
} else if (vertexList.vertices[i].x < Min.x) {
|
|
Min.x = vertexList.vertices[i].x;
|
|
}
|
|
|
|
if (vertexList.vertices[i].y > Max.y) {
|
|
Max.y = vertexList.vertices[i].y;
|
|
} else if (vertexList.vertices[i].y < Min.y) {
|
|
Min.y = vertexList.vertices[i].y;
|
|
}
|
|
|
|
if (vertexList.vertices[i].z > Max.z) {
|
|
Max.z = vertexList.vertices[i].z;
|
|
} else if (vertexList.vertices[i].z < Min.z) {
|
|
Min.z = vertexList.vertices[i].z;
|
|
}
|
|
}
|
|
|
|
Center.x = (Max.x + Min.x) / 2.;
|
|
Center.y = (Max.y + Min.y) / 2.;
|
|
Center.z = (Max.z + Min.z) / 2.;
|
|
|
|
float scaleX, scaleY, scaleZ;
|
|
scaleX = (Max.x - Min.x) / 2.;
|
|
scaleY = (Max.y - Min.y) / 2.;
|
|
scaleZ = (Max.z - Min.z) / 2.;
|
|
|
|
float scaleFactor;
|
|
|
|
scaleFactor = scaleX > scaleY ? scaleX : scaleY;
|
|
scaleFactor = scaleZ > scaleFactor ? scaleZ : scaleFactor;
|
|
scaleFactor = 1. / scaleFactor;
|
|
|
|
//printf("ScaleFactor: %f\n",scaleFactor);
|
|
|
|
glPushMatrix();
|
|
glTranslatef(0.-(Center.x*scaleFactor),0.-(Center.y*scaleFactor),0.-(Center.z*scaleFactor));
|
|
glScalef(scaleFactor,scaleFactor,scaleFactor);
|
|
glCallList(triangleList);
|
|
glPopMatrix();
|
|
|
|
glEndList();
|
|
|
|
return sceneList;
|
|
}
|
|
|
|
GLuint create_flat_scene ( )
|
|
{
|
|
return create_scene( init_flat_scene() );
|
|
}
|
|
|
|
GLuint create_gouraud_scene ( )
|
|
{
|
|
return create_scene( init_gouraud_scene() );
|
|
}
|
|
|
|
/* --------------------------------------------- */
|
|
|
|
/* redraw the scene */
|
|
|
|
GLvoid draw(GLvoid)
|
|
{
|
|
/* set the projection matrix */
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
gluPerspective(viewDist,1.0,15.0,25.0);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
|
|
/* initialize light */
|
|
if (worldLight) {
|
|
//World Lighting
|
|
init_lightsource();
|
|
glTranslatef(0,0,-20);
|
|
glMultMatrixf(currModelTransform);
|
|
} else {
|
|
//Model Lighting
|
|
glTranslatef(0,0,-20);
|
|
glMultMatrixf(currModelTransform);
|
|
init_lightsource();
|
|
}
|
|
|
|
/* ensure we're drawing to the correct GLUT window */
|
|
glutSetWindow(wid);
|
|
|
|
/* clear the color buffers */
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
/* DRAW WHAT IS IN THE DISPLAY LIST */
|
|
glCallList(triangleScene);
|
|
|
|
/* flush the pipeline */
|
|
glFlush();
|
|
|
|
/* look at our handiwork */
|
|
glutSwapBuffers();
|
|
|
|
}
|
|
|
|
/* --------------------------------------------- */
|
|
|
|
/* handle mouse events */
|
|
SPoint oldPoint; //stores the previous point used in the virtual trackball
|
|
|
|
GLvoid mouse_button(GLint btn, GLint state, GLint mx, GLint my)
|
|
{
|
|
switch( btn ) {
|
|
case GLUT_LEFT_BUTTON:
|
|
switch( state ) {
|
|
case GLUT_DOWN:
|
|
oldPoint.x = mx;
|
|
oldPoint.y = my;
|
|
oldPoint.z = -1;
|
|
break;
|
|
case GLUT_UP:
|
|
break;
|
|
}
|
|
break;
|
|
case GLUT_MIDDLE_BUTTON:
|
|
switch( state ) {
|
|
case GLUT_DOWN:
|
|
break;
|
|
case GLUT_UP:
|
|
break;
|
|
}
|
|
break;
|
|
case GLUT_RIGHT_BUTTON:
|
|
switch( state ) {
|
|
case GLUT_DOWN:
|
|
break;
|
|
case GLUT_UP:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
inline void scalePoint(SPoint& p, GLint mx, GLint my) {
|
|
//scale to -1 and 1
|
|
float scale = ceil(vpd/2.);
|
|
p.x = (mx / scale) -1.;
|
|
p.y = (my / scale) -1.;
|
|
p.y*=-1.; //handle reversed y
|
|
|
|
p.z = 1.-pow(p.x,2)-pow(p.y,2);
|
|
|
|
if (p.z < 0) {
|
|
float under = sqrt((p.x*p.x)+(p.y*p.y));
|
|
p.x /= under;
|
|
p.y /= under;
|
|
p.z = 0;
|
|
} else {
|
|
p.z = sqrt(p.z);
|
|
}
|
|
|
|
}
|
|
|
|
inline GLfloat vecLength(SPoint& p) {
|
|
return sqrt(pow(p.x,2)+pow(p.y,2)+pow(p.z,2));
|
|
}
|
|
|
|
inline GLfloat dot(SPoint &a, SPoint &b) {
|
|
return (a.x*b.x)+(a.y*b.y)+(a.z*b.z);
|
|
}
|
|
|
|
inline void cross(SPoint &dest, SPoint &a, SPoint &b) {
|
|
|
|
dest.x = ( (a.y*b.z) - (a.z*b.y) ); //i
|
|
dest.y = ( (a.z*b.x) - (a.x*b.z) ); //j
|
|
dest.z = ( (a.x*b.y) - (a.y*b.x) ); //k
|
|
}
|
|
|
|
inline void calcAngle(GLfloat *newMatrix, GLfloat angle, SPoint& a) {
|
|
newMatrix[0] = 1.+(1.-cos(angle))*(pow(a.x,2)-1.);
|
|
newMatrix[1] = a.z*sin(angle) + (1.-cos(angle)) * a.x * a.y;
|
|
newMatrix[2] = -1. * a.y * sin(angle) + (1.-cos(angle))*a.x*a.z;
|
|
newMatrix[3] = 0;
|
|
newMatrix[4] = -1. * a.z * sin(angle) + (1.-cos(angle)) * a.x * a.y;
|
|
newMatrix[5] = 1. + (1. - cos(angle))*(pow(a.y,2)-1.);
|
|
newMatrix[6] = a.x * sin(angle) + (1.-cos(angle))*a.y*a.z;
|
|
newMatrix[7] = 0;
|
|
newMatrix[8] = a.y * sin(angle) + (1.-cos(angle))*a.x * a.z;
|
|
newMatrix[9] = -1. * a.x * sin(angle) + (1.-cos(angle))*a.y*a.z;
|
|
newMatrix[10] = 1. + (1.-cos(angle))*(pow(a.z,2)-1.);
|
|
newMatrix[11] = newMatrix[12] = newMatrix[13] = newMatrix[14] = 0;
|
|
newMatrix[15] = 1.;
|
|
}
|
|
|
|
GLvoid button_motion(GLint mx, GLint my)
|
|
{
|
|
/* First calculate P */
|
|
static SPoint v;
|
|
SPoint p, w, a;
|
|
|
|
//Give us the scaled p on the sphere
|
|
scalePoint(p,mx,my);
|
|
|
|
//get the unit vector of p
|
|
GLfloat length = vecLength(p);
|
|
if (length==0) {
|
|
return;
|
|
} else {
|
|
w.x = p.x / length;
|
|
w.y = p.y / length;
|
|
w.z = p.z / length;
|
|
}
|
|
|
|
//This is the first time the movement has been made
|
|
if (oldPoint.z == -1) {
|
|
scalePoint(oldPoint,(int)oldPoint.x,(int)oldPoint.y);
|
|
|
|
length = vecLength(oldPoint);
|
|
if (length==0) {
|
|
return;
|
|
} else {
|
|
v.x = oldPoint.x / length;
|
|
v.y = oldPoint.y / length;
|
|
v.z = oldPoint.z / length;
|
|
}
|
|
}
|
|
|
|
cross(a,oldPoint,p);
|
|
length = vecLength(a);
|
|
if (length==0) {
|
|
return;
|
|
} else {
|
|
a.x /= length;
|
|
a.y /= length;
|
|
a.z /= length;
|
|
}
|
|
|
|
GLfloat angle = dot(v,w);
|
|
if (angle > 1) {
|
|
angle = 1;
|
|
} else if (angle < -1) {
|
|
angle = -1;
|
|
}
|
|
|
|
angle = acos(angle);
|
|
|
|
/* Perform the rotation calculation */
|
|
GLfloat newMatrix[16];
|
|
|
|
calcAngle(newMatrix,angle,a);
|
|
|
|
/* Make OpenGL do our work */
|
|
glPushMatrix();
|
|
glLoadMatrixf(newMatrix);
|
|
glMultMatrixf(currModelTransform);
|
|
glGetFloatv(GL_MODELVIEW_MATRIX,currModelTransform);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPopMatrix();
|
|
|
|
oldPoint = p;
|
|
v = w;
|
|
|
|
glutPostRedisplay();
|
|
|
|
return;
|
|
}
|
|
|
|
GLvoid passive_motion(GLint mx, GLint my)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* --------------------------------------------- */
|
|
|
|
/* handle keyboard events; here, just exit if ESC is hit */
|
|
|
|
GLvoid keyboard(GLubyte key, GLint x, GLint y)
|
|
{
|
|
switch(key) {
|
|
case 27: /* ESC */
|
|
exit(0);
|
|
case 'w':
|
|
viewDist -= .1;
|
|
glutPostRedisplay();
|
|
break;
|
|
case 's':
|
|
viewDist += .1;
|
|
glutPostRedisplay();
|
|
break;
|
|
case 'a':
|
|
currModelTransform[12] -= .01;
|
|
glutPostRedisplay();
|
|
break;
|
|
case 'd':
|
|
currModelTransform[12] += .01;
|
|
glutPostRedisplay();
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
/* --------------------------------------------- */
|
|
|
|
GLvoid menu ( int value )
|
|
{
|
|
switch(value)
|
|
{
|
|
case MENU_SWITCH_SHADING:
|
|
if (triangleScene == gouraudID) {
|
|
glShadeModel(GL_FLAT);
|
|
triangleScene = flatID;
|
|
} else {
|
|
glShadeModel(GL_SMOOTH);
|
|
triangleScene = gouraudID;
|
|
}
|
|
glutPostRedisplay();
|
|
break;
|
|
case MENU_ZOOM_IN:
|
|
viewDist -= 1.;
|
|
glutPostRedisplay();
|
|
break;
|
|
case MENU_ZOOM_OUT:
|
|
viewDist += 1.;
|
|
glutPostRedisplay();
|
|
break;
|
|
case MENU_POINTS:
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
|
|
glutPostRedisplay();
|
|
break;
|
|
case MENU_LINES:
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
|
glutPostRedisplay();
|
|
break;
|
|
case MENU_TRIANGLES:
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
|
glutPostRedisplay();
|
|
break;
|
|
case MENU_SWITCH_CULLING:
|
|
if (cullMode == GL_FRONT) {
|
|
glCullFace(GL_BACK);
|
|
cullMode = GL_BACK;
|
|
} else {
|
|
glCullFace(GL_FRONT);
|
|
cullMode = GL_FRONT;
|
|
}
|
|
glutPostRedisplay();
|
|
break;
|
|
case MENU_TURN_ON_CULLING:
|
|
glEnable(GL_CULL_FACE);
|
|
glutPostRedisplay();
|
|
break;
|
|
case MENU_TURN_OFF_CULLING:
|
|
glDisable(GL_CULL_FACE);
|
|
glutPostRedisplay();
|
|
break;
|
|
case MENU_SWITCH_LIGHT:
|
|
worldLight = !worldLight;
|
|
glutPostRedisplay();
|
|
break;
|
|
case MENU_RESET_MODELVIEW:
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glGetFloatv(GL_MODELVIEW_MATRIX,currModelTransform);
|
|
glPopMatrix();
|
|
glutPostRedisplay();
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
/* --------------------------------------------- */
|
|
|
|
/* handle resizing the glut window */
|
|
|
|
GLvoid reshape(GLint vpw, GLint vph)
|
|
{
|
|
glutSetWindow(wid);
|
|
|
|
/* maintain a square viewport, not too small, not too big */
|
|
if( vpw < vph ) vpd = vph;
|
|
else vpd = vpw;
|
|
|
|
if( vpd < VPD_MIN ) vpd = VPD_MIN;
|
|
if( vpd > VPD_MAX ) vpd = VPD_MAX;
|
|
|
|
glViewport(0, 0, vpd, vpd);
|
|
glutReshapeWindow(vpd, vpd);
|
|
|
|
glutPostRedisplay();
|
|
}
|
|
|
|
/* --------------------------------------------- */
|
|
|
|
GLint init_glut(GLint *argc, char **argv)
|
|
{
|
|
GLint id;
|
|
|
|
glutInit(argc,argv);
|
|
|
|
/* size and placement hints to the window system */
|
|
glutInitWindowSize(vpd, vpd);
|
|
glutInitWindowPosition(10,10);
|
|
|
|
/* double buffered, RGB color mode */
|
|
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
|
|
|
|
/* create a GLUT window (not drawn until glutMainLoop() is entered) */
|
|
id = glutCreateWindow("cs4451 assignment 2");
|
|
|
|
/* register callbacks */
|
|
|
|
/* window size changes */
|
|
glutReshapeFunc(reshape);
|
|
|
|
/* keypress handling when the current window has input focus */
|
|
glutKeyboardFunc(keyboard);
|
|
|
|
/* mouse event handling */
|
|
glutMouseFunc(mouse_button); /* button press/release */
|
|
glutMotionFunc(button_motion); /* mouse motion w/ button down */
|
|
glutPassiveMotionFunc(passive_motion); /* mouse motion with button up */
|
|
|
|
/* window obscured/revealed event handler */
|
|
glutVisibilityFunc(NULL);
|
|
|
|
/* handling of keyboard SHIFT, ALT, CTRL keys */
|
|
glutSpecialFunc(NULL);
|
|
|
|
/* what to do when mouse cursor enters/exits the current window */
|
|
glutEntryFunc(NULL);
|
|
|
|
/* what to do on each display loop iteration */
|
|
glutDisplayFunc(draw);
|
|
|
|
/* Create the menu */
|
|
|
|
//Create the Zoom Menu
|
|
GLint zoomMenu = glutCreateMenu(menu);
|
|
glutAddMenuEntry("Zoom In (w)",MENU_ZOOM_IN);
|
|
glutAddMenuEntry("Zoom Out (s)",MENU_ZOOM_OUT);
|
|
|
|
//Create the Render Mode Menu
|
|
GLint renderMenu = glutCreateMenu(menu);
|
|
glutAddMenuEntry("Points Only",MENU_POINTS);
|
|
glutAddMenuEntry("Lines Only",MENU_LINES);
|
|
glutAddMenuEntry("Full Model",MENU_TRIANGLES);
|
|
|
|
//Create the Culling Menu
|
|
GLint cullingMenu = glutCreateMenu(menu);
|
|
glutAddMenuEntry("Switch Culling Mode",MENU_SWITCH_CULLING);
|
|
glutAddMenuEntry("Turn on Culling",MENU_TURN_ON_CULLING);
|
|
glutAddMenuEntry("Turn off Culling",MENU_TURN_OFF_CULLING);
|
|
|
|
GLint menuID = glutCreateMenu(menu);
|
|
glutAddMenuEntry("Switch Shading Mode",MENU_SWITCH_SHADING);
|
|
glutAddMenuEntry("Toggle World/Model Relative Light",MENU_SWITCH_LIGHT);
|
|
|
|
glutAddSubMenu("Zoom",zoomMenu);
|
|
glutAddSubMenu("Render", renderMenu);
|
|
glutAddSubMenu("Culling", cullingMenu);
|
|
|
|
glutAddMenuEntry("Reset View Model",MENU_RESET_MODELVIEW);
|
|
|
|
glutSetMenu(menuID);
|
|
|
|
glutAttachMenu(GLUT_RIGHT_BUTTON);
|
|
|
|
return id;
|
|
}
|
|
|
|
/* --------------------------------------------- */
|
|
|
|
GLvoid init_opengl(GLvoid)
|
|
{
|
|
/* back-face culling on */
|
|
glEnable(GL_CULL_FACE);
|
|
glCullFace(GL_BACK); /* We want to cull the back */
|
|
glFrontFace(GL_CW); /* The vertices we get are clockwise */
|
|
|
|
/* automatically scale normals to unit length after transformation */
|
|
glEnable(GL_NORMALIZE);
|
|
|
|
/* clear to BLACK */
|
|
glClearColor(0.0, 0.0, 0.0, 1.0);
|
|
|
|
/* Enable depth test */
|
|
glEnable(GL_DEPTH_TEST);
|
|
}
|
|
|
|
/* --------------------------------------------- */
|
|
|
|
void generateNormals() {
|
|
|
|
/* Generate normals for triangles and Vertices */
|
|
SNormal tempNormal;
|
|
|
|
SVertex a1a2, a1a3;
|
|
SVertex a1, a2, a3;
|
|
|
|
for (int i = 0; i < triList.length; i++) {
|
|
|
|
a1 = vertexList.vertices[triList.triangles[i].a1];
|
|
a2 = vertexList.vertices[triList.triangles[i].a2];
|
|
a3 = vertexList.vertices[triList.triangles[i].a3];
|
|
|
|
a1a2.x = a2.x - a1.x;
|
|
a1a2.y = a2.y - a1.y;
|
|
a1a2.z = a2.z - a1.z;
|
|
|
|
a1a3.x = a3.x - a1.x;
|
|
a1a3.y = a3.y - a1.y;
|
|
a1a3.z = a3.z - a1.z;
|
|
|
|
cross(tempNormal,a1a2,a1a3);
|
|
|
|
tempNormal.i *= -1;
|
|
tempNormal.j *= -1;
|
|
tempNormal.k *= -1;
|
|
|
|
/* Store the normal for the triangle */
|
|
triList.triangles[i].normal = tempNormal;
|
|
|
|
/* Add this normal to the normal of all the vertices */
|
|
vertexList.vertices[triList.triangles[i].a1].normal.i += tempNormal.i;
|
|
vertexList.vertices[triList.triangles[i].a1].normal.j += tempNormal.j;
|
|
vertexList.vertices[triList.triangles[i].a1].normal.k += tempNormal.k;
|
|
|
|
vertexList.vertices[triList.triangles[i].a2].normal.i += tempNormal.i;
|
|
vertexList.vertices[triList.triangles[i].a2].normal.j += tempNormal.j;
|
|
vertexList.vertices[triList.triangles[i].a2].normal.k += tempNormal.k;
|
|
|
|
vertexList.vertices[triList.triangles[i].a3].normal.i += tempNormal.i;
|
|
vertexList.vertices[triList.triangles[i].a3].normal.j += tempNormal.j;
|
|
vertexList.vertices[triList.triangles[i].a3].normal.k += tempNormal.k;
|
|
}
|
|
}
|
|
|
|
|
|
/* --------------------------------------------- */
|
|
|
|
|
|
GLint main(GLint argc, char **argv)
|
|
{
|
|
|
|
/* Scan Input */
|
|
scanInput();
|
|
generateNormals();
|
|
|
|
/* initialize light */
|
|
init_lightsource();
|
|
|
|
/* Initialize the currentTransformation */
|
|
currModelTransform[0] = 1;
|
|
currModelTransform[5] = 1;
|
|
currModelTransform[10] = 1;
|
|
currModelTransform[15] = 1;
|
|
|
|
/* initialize GLUT: register callbacks, etc */
|
|
wid = init_glut(&argc, argv);
|
|
|
|
/* any OpenGL state initialization we need to do */
|
|
init_opengl();
|
|
|
|
/* CREATE THE DISPLAY LIST FOR THE SCENE */
|
|
|
|
flatID = create_flat_scene();
|
|
gouraudID = create_gouraud_scene();
|
|
|
|
triangleScene = gouraudID;
|
|
|
|
glutMainLoop();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void scanInput(GLvoid) {
|
|
char input[81];
|
|
char *inputPtr;
|
|
int i;
|
|
|
|
//Get the # of vertices and # of triangles
|
|
std::cin.getline(input,81);
|
|
|
|
triList.length = strtol(input,&inputPtr,0);
|
|
triList.triangles = (STriangle*)malloc(sizeof(STriangle)*triList.length);
|
|
|
|
vertexList.length = strtol(inputPtr,NULL,0);
|
|
vertexList.vertices = (SVertex*)malloc(sizeof(SVertex)*vertexList.length);
|
|
|
|
//Skip over the first newline
|
|
std::cin.getline(input,81);
|
|
|
|
for (i=0; i < triList.length; i++) {
|
|
std::cin.getline(input,81);
|
|
|
|
//get points
|
|
triList.triangles[i].a1 = strtol(input,&inputPtr,0);
|
|
triList.triangles[i].a2 = strtol(inputPtr,&inputPtr,0);
|
|
triList.triangles[i].a3 = strtol(inputPtr,NULL,0);
|
|
triList.triangles[i].normal.i = 0;
|
|
triList.triangles[i].normal.j = 0;
|
|
triList.triangles[i].normal.k = 0;
|
|
}
|
|
|
|
//skip over separation newline
|
|
std::cin.getline(input,81);
|
|
|
|
for (i=0; i < vertexList.length; i++) {
|
|
std::cin.getline(input,81);
|
|
|
|
//get coordinates
|
|
vertexList.vertices[i].x = strtod(input,&inputPtr);
|
|
vertexList.vertices[i].y = strtod(inputPtr,&inputPtr);
|
|
vertexList.vertices[i].z = strtod(inputPtr,NULL);
|
|
|
|
vertexList.vertices[i].normal.i = 0;
|
|
vertexList.vertices[i].normal.j = 0;
|
|
vertexList.vertices[i].normal.k = 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|