/* * Student Name: Stellios Keskinidis * Student Number: 02412012 * * 3 windows demonstrating shading models * * Load tricyele and wagon from .asc files */ /* glut library, includes all of gl */ #include /* requires file I/O */ #include /* window size coordinates */ #define windowHeight 450 #define windowWidth 450 /* Object 1 input file */ #define WAGON_INFILE "wagon.asc" /* Object 2 input file */ #define TRICYCLE_INFILE "tricycle.asc" /* single vertex */ typedef struct VERTEX { GLfloat x; GLfloat y; GLfloat z; } VERTEX; /* single face normal */ typedef struct NORMAL { GLint x; GLint y; GLint z; } NORMAL; /* a face based on triangles with rgb values*/ typedef struct FACE { GLint a; GLint b; GLint c; /* red green blue values of face*/ GLint red; GLint green; GLint blue; } FACE; /* list of vertices */ typedef struct VERTEX_LIST { /* material properties (MaterialObjectProperties) */ int materialProperties; /* number of vertices */ int vertices; /* list of vertices */ VERTEX *vertexlist; } VERTEX_LIST; /* vertices with same edges */ typedef struct FACE_LIST { /* number of faces */ int faces; /* list of faces */ FACE *facelist; } FACE_LIST; typedef struct NORMAL_LIST { /* number of normals */ int normals; /* list of normals */ NORMAL *normalslist; } NORMAL_LIST; /* boolean type */ typedef enum { false, true } BOOLEAN; /* different types of surface material */ typedef enum { SHINY_SURFACE, VERY_SHINY_SURFACE, DULL_SURFACE, NORMAL_SURFACE } SURFACE_MATERIAL; /* Object is composed of vertex lists * which have differnt material properties */ typedef struct OBJECT { int numberOfObjects; VERTEX_LIST *objectVertices; FACE_LIST *objectFaces; NORMAL_LIST *objectNormals; BOOLEAN averageNormals; BOOLEAN gouraudShade; } OBJECT; /* references to windows */ GLint window1; GLint window2; GLint window3; /* current rotating objects window number */ BOOLEAN RotateWindow1, RotateWindow2, RotateWindow3; /* rotation angle of objects */ const GLfloat object1Rotation=1.5; const GLfloat object2Rotation=3.3; /* rotation angle of object in respective window */ GLfloat object1Window1Rotate=0,object2Window1Rotate=0; GLfloat object1Window2Rotate=0,object2Window2Rotate=0; GLfloat object1Window3Rotate=0,object2Window3Rotate=0; /* objects in windows, 2 for each window */ OBJECT *object1Window1,*object2Window1; OBJECT *object1Window2,*object2Window2; OBJECT *object1Window3,*object2Window3; void calculateVertexNormals(OBJECT *obj); /* vertex list of loaded models */ /* light position, 1.0 indicates position */ GLfloat lightPosition1[]={-400.0f,300.0f,-20.0f,0.0f}; GLfloat lightPosition2[]={400.0f,-300.0f,20.0f,0.0f}; /* load object from file * object - load object into structure * filename - .ASC file */ void loadObject(OBJECT *object, char *filename) { FILE *file = fopen(filename,"r"); char line[BUFSIZ]; int currentObjectProperty=0; /* file does not exist */ if(file==NULL) { fprintf(stderr,"Could not open file : %s!\n\n",filename); exit(-1); } fgets(line,BUFSIZ,file); sscanf(line,"%d", &object->numberOfObjects); /* read color information but do nothing with it */ fgets(line,BUFSIZ,file); object->objectVertices=(VERTEX_LIST*) malloc( (sizeof(struct VERTEX_LIST))*object->numberOfObjects); object->objectFaces=(FACE_LIST*) malloc( (sizeof(struct FACE_LIST))*object->numberOfObjects); object->objectNormals=(NORMAL_LIST*) malloc( (sizeof(struct NORMAL_LIST))*object->numberOfObjects); for(currentObjectProperty=0; currentObjectPropertynumberOfObjects; currentObjectProperty++) { int currentVertex=0; int currentFace=0; /* read blank line */ fgets(line,BUFSIZ,file); /* read comment */ fgets(line,BUFSIZ,file); /* read number of vertices and faces */ fgets(line,BUFSIZ,file); sscanf(line,"Tri-mesh, Vertices: %d Faces: %d", &object->objectVertices[currentObjectProperty].vertices, &object->objectFaces[currentObjectProperty].faces); /* read Material property */ fgets(line,BUFSIZ,file); sscanf(line,"Surface Material: %d", &object->objectVertices[currentObjectProperty].materialProperties); /* read Vertex list: line */ fgets(line,BUFSIZ,file); /* set material property for vertex list */ /* allocate memory for vertex list */ object->objectVertices[currentObjectProperty].vertexlist = (VERTEX*) malloc((sizeof(struct VERTEX))*object->objectVertices[currentObjectProperty].vertices); /* allocate memory for normals having the same number of vertices */ object->objectNormals[currentObjectProperty].normalslist = (NORMAL*) malloc((sizeof(struct NORMAL))*object->objectVertices[currentObjectProperty].vertices); /* load vertices for current object */ for(currentVertex=0; currentVertexobjectVertices[currentObjectProperty].vertices; currentVertex++) { int curr; fgets(line, BUFSIZ,file); sscanf(line,"Vertex %d: X:%f Y:%f Z:%f", &curr, &object->objectVertices[currentObjectProperty].vertexlist[currentVertex].x, &object->objectVertices[currentObjectProperty].vertexlist[currentVertex].y, &object->objectVertices[currentObjectProperty].vertexlist[currentVertex].z); } /* read Face list: line */ fgets(line,BUFSIZ,file); /* allocate memory for faces list */ object->objectFaces[currentObjectProperty].facelist = (FACE*) malloc((sizeof(struct FACE))*object->objectFaces[currentObjectProperty].faces); for(currentFace=0; currentFace< object->objectFaces[currentObjectProperty].faces; currentFace++) { int curr; fgets(line, BUFSIZ,file); sscanf(line,"Face %d: A:%d B:%d C:%d", &curr, &object->objectFaces[currentObjectProperty].facelist[currentFace].a, &object->objectFaces[currentObjectProperty].facelist[currentFace].b, &object->objectFaces[currentObjectProperty].facelist[currentFace].c); /* read Material: line */ fgets(line, BUFSIZ,file); sscanf(line,"Material:\"r%dg%db%da0\"", &object->objectFaces[currentObjectProperty].facelist[currentFace].red, &object->objectFaces[currentObjectProperty].facelist[currentFace].green, &object->objectFaces[currentObjectProperty].facelist[currentFace].blue); /* read Smoothing: line */ fgets(line, BUFSIZ,file); } /* load faces for current object */ } fclose(file); calculateVertexNormals(object); } /* calculate vertex normals for object */ void calculateVertexNormals(OBJECT *object) { int vertexNumber=0; int currentObjectProperty=0; int currentWindow= glutGetWindow(); /* loop through all object properties for this object */ for(currentObjectProperty=0; currentObjectPropertynumberOfObjects; currentObjectProperty++) { /** loop through all vertices for this property */ for(vertexNumber=0; vertexNumberobjectVertices[currentObjectProperty].vertices; vertexNumber++) { int numberOfFacesShared=0; int faceNumber=0; NORMAL normal1, normal2; float x=0,y=0,z=0; float length=0; float vertexX=0,vertexY=0,vertexZ=0; /* find connecting vertices to this face */ for(faceNumber=0; faceNumberobjectFaces[currentObjectProperty].faces; faceNumber++) { int verticeA = object->objectFaces[currentObjectProperty].facelist[faceNumber].a; int verticeB = object->objectFaces[currentObjectProperty].facelist[faceNumber].b; int verticeC = object->objectFaces[currentObjectProperty].facelist[faceNumber].c; if(verticeA == vertexNumber || verticeB == vertexNumber || verticeC == vertexNumber) { normal1.x = object->objectVertices[currentObjectProperty].vertexlist[verticeC].x - object->objectVertices[currentObjectProperty].vertexlist[verticeA].x; normal1.y = object->objectVertices[currentObjectProperty].vertexlist[verticeC].y - object->objectVertices[currentObjectProperty].vertexlist[verticeA].y; normal1.z = object->objectVertices[currentObjectProperty].vertexlist[verticeC].z - object->objectVertices[currentObjectProperty].vertexlist[verticeA].z; normal2.x = object->objectVertices[currentObjectProperty].vertexlist[verticeB].x - object->objectVertices[currentObjectProperty].vertexlist[verticeA].x; normal2.y = object->objectVertices[currentObjectProperty].vertexlist[verticeB].y - object->objectVertices[currentObjectProperty].vertexlist[verticeA].y; normal2.z = object->objectVertices[currentObjectProperty].vertexlist[verticeB].z - object->objectVertices[currentObjectProperty].vertexlist[verticeA].z; x = x + ((normal2.y * normal1.z) - (normal2.z * normal1.y)); y = y + ((normal2.z * normal1.x) - (normal2.x * normal1.z)); z = z + ((normal2.x * normal1.y) - (normal2.y * normal1.x)); numberOfFacesShared++; } } /* Calculate Normals */ if(numberOfFacesShared!=0) { object->objectNormals[currentObjectProperty].normalslist[vertexNumber].x = x / numberOfFacesShared; object->objectNormals[currentObjectProperty].normalslist[vertexNumber].y = y / numberOfFacesShared; object->objectNormals[currentObjectProperty].normalslist[vertexNumber].z = z / numberOfFacesShared; } /* Average Normals */ if(object->averageNormals) { vertexX = object->objectNormals[currentObjectProperty].normalslist[vertexNumber].x; vertexY = object->objectNormals[currentObjectProperty].normalslist[vertexNumber].y; vertexZ = object->objectNormals[currentObjectProperty].normalslist[vertexNumber].z; length = sqrt ((vertexX*vertexX)+(vertexY*vertexY)+(vertexZ+vertexZ)); object->objectNormals[currentObjectProperty].normalslist[vertexNumber].x = vertexX / length; object->objectNormals[currentObjectProperty].normalslist[vertexNumber].y = vertexY / length; object->objectNormals[currentObjectProperty].normalslist[vertexNumber].z = vertexZ / length; } } } } /* set the surface material for the current object */ void setObjectProperty(SURFACE_MATERIAL property) { GLfloat dull_ambient[] = { 0.2, 0.2, 0.2, 0.2 }; GLfloat dull_specular[] = { 0.0, 0.0, 0.0, 0.0 }; GLfloat dull_diffuse[] = { 0.2, 0.2, 0.2, 0.2 }; GLfloat dull_shininess[] = { 128.0 }; GLfloat shine_ambient[] = { 0.1, 0.1, 0.1, 0.1 }; GLfloat shine_specular[] = { 0.4, 0.4, 0.4, 0.4 }; GLfloat shine_diffuse[] = { 0.1, 0.1, 0.1, 0.1 }; GLfloat shine_shininess[] = { 30.0 }; GLfloat vshine_ambient[] = { 0.1, 0.1, 0.1, 0.1 }; GLfloat vshine_specular[] = { 0.5, 0.5, 0.5, 0.5 }; GLfloat vshine_diffuse[] = { 0.1, 0.1, 0.1, 0.1 }; GLfloat vshine_shininess[] = { 20.0 }; GLfloat normal_ambient[] = { 0.5, 0.5, 0.5, 0.5 }; GLfloat normal_specular[] = { 0.5, 0.5, 0.5, 0.5 }; GLfloat normal_diffuse[] = { 0.5, 0.5, 0.5, 0.5 }; GLfloat normal_shininess[] = { 70.0 }; glLoadIdentity(); switch(property) { /* simulate a dull surface */ case DULL_SURFACE: glMaterialfv(GL_FRONT, GL_AMBIENT, dull_ambient); glMaterialfv(GL_FRONT, GL_SPECULAR, dull_specular); glMaterialfv(GL_FRONT, GL_DIFFUSE, dull_diffuse); glMaterialfv(GL_FRONT, GL_SHININESS, dull_shininess); break; /* simulate a shiny surface */ case SHINY_SURFACE: glMaterialfv(GL_FRONT, GL_AMBIENT, shine_ambient); glMaterialfv(GL_FRONT, GL_SPECULAR, shine_specular); glMaterialfv(GL_FRONT, GL_DIFFUSE, shine_diffuse); glMaterialfv(GL_FRONT, GL_SHININESS, shine_shininess); break; /* simulate an very shiny surface */ case VERY_SHINY_SURFACE: glMaterialfv(GL_FRONT, GL_AMBIENT, vshine_ambient); glMaterialfv(GL_FRONT, GL_SPECULAR, vshine_specular); glMaterialfv(GL_FRONT, GL_DIFFUSE, vshine_diffuse); glMaterialfv(GL_FRONT, GL_SHININESS, vshine_shininess); break; /* otherwise simulate a "normal" surface */ default: glMaterialfv(GL_FRONT, GL_AMBIENT, normal_ambient); glMaterialfv(GL_FRONT, GL_SPECULAR, normal_specular); glMaterialfv(GL_FRONT, GL_DIFFUSE, normal_diffuse); glMaterialfv(GL_FRONT, GL_SHININESS, normal_shininess); break; } } /* draw a single object to window */ void drawObject(OBJECT *object) { int currentObjectProperty=0; int currentVertex=0; int currentFaceNumber=0; glBegin(GL_TRIANGLES); for(currentObjectProperty=0; currentObjectPropertynumberOfObjects; currentObjectProperty++) { /* set material properties of surface */ setObjectProperty(object->objectVertices[currentObjectProperty].materialProperties); /* draw vertices and normals in order using the face list */ for(currentFaceNumber=0; currentFaceNumberobjectFaces[currentObjectProperty].faces; currentFaceNumber++) { /* draw vertices based on face numbers */ int vertices[]= { object->objectFaces[currentObjectProperty].facelist[currentFaceNumber].a, object->objectFaces[currentObjectProperty].facelist[currentFaceNumber].b, object->objectFaces[currentObjectProperty].facelist[currentFaceNumber].c }; int currentVertice=0; /* draw color of face */ glColor3ub(object->objectFaces[currentObjectProperty].facelist[currentFaceNumber].red, object->objectFaces[currentObjectProperty].facelist[currentFaceNumber].green, object->objectFaces[currentObjectProperty].facelist[currentFaceNumber].blue); /* draw vertices and normals for face */ for(currentVertice=0;currentVertice<3;currentVertice++) { glNormal3f(object->objectNormals[currentObjectProperty].normalslist[vertices[currentVertice]].x, object->objectNormals[currentObjectProperty].normalslist[vertices[currentVertice]].y, object->objectNormals[currentObjectProperty].normalslist[vertices[currentVertice]].z); glVertex3f(object->objectVertices[currentObjectProperty].vertexlist[vertices[currentVertice]].x, object->objectVertices[currentObjectProperty].vertexlist[vertices[currentVertice]].y, object->objectVertices[currentObjectProperty].vertexlist[vertices[currentVertice]].z); } } } glEnd(); } void loadObjects(void) { /* Load vertex lists from file */ object1Window1 = (OBJECT*)malloc(sizeof(struct OBJECT)); object2Window1 = (OBJECT*)malloc(sizeof(struct OBJECT)); object1Window1->averageNormals=false; object2Window1->averageNormals=false; object1Window2 = (OBJECT*)malloc(sizeof(struct OBJECT)); object2Window2 = (OBJECT*)malloc(sizeof(struct OBJECT)); object1Window2->averageNormals=false; object2Window2->averageNormals=false; object1Window3 = (OBJECT*)malloc(sizeof(struct OBJECT)); object2Window3 = (OBJECT*)malloc(sizeof(struct OBJECT)); object1Window3->averageNormals=true; object2Window3->averageNormals=true; /* load wagon object from file */ loadObject(object1Window1,WAGON_INFILE); loadObject(object1Window2,WAGON_INFILE); loadObject(object1Window3,WAGON_INFILE); /* load tricycle object from file */ loadObject(object2Window1,TRICYCLE_INFILE); loadObject(object2Window2,TRICYCLE_INFILE); loadObject(object2Window3,TRICYCLE_INFILE); } /* initialize shading and for first window */ void initWindow1(void) { /* setup window 1 lighting and settings */ glClearColor(0.5,0.5,0.5,0.5); glEnable(GL_COLOR_MATERIAL); glEnable(GL_DEPTH_TEST); glEnable(GL_NORMALIZE); /* Flat shading */ glShadeModel(GL_FLAT); } void initWindow2(void) { glClearColor(0.5,0.5,0.5,0.5); glEnable(GL_COLOR_MATERIAL); glEnable(GL_DEPTH_TEST); glShadeModel(GL_SMOOTH); glEnable(GL_NORMALIZE); } void initWindow3(void) { glClearColor(0.5,0.5,0.5,0.5); glEnable(GL_COLOR_MATERIAL); glEnable(GL_DEPTH_TEST); glShadeModel(GL_SMOOTH); glEnable(GL_NORMALIZE); } /* display everything for current window */ void display(void) { int currentWindow; /* setup lighting sources */ /* first light source settings */ GLfloat light1_ambient[] = { 0.1, 0.1, 0.1, 0.1 }; GLfloat light1_specular[] = { 0.1, 0.1, 0.1, 0.1 }; GLfloat light1_diffuse[] = { 0.1, 0.1, 0.1, 0.1 }; /* second light source settings */ GLfloat light2_ambient[] = { 0.2, 0.2, 0.2, 0.2 }; GLfloat light2_specular[] = { 0.2, 0.2, 0.2, 0.2 }; GLfloat light2_diffuse[] = { 0.2, 0.2, 0.2, 0.2 }; glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glMaterialfv(GL_FRONT, GL_AMBIENT, light1_ambient); glMaterialfv(GL_FRONT, GL_SPECULAR, light1_specular); glMaterialfv(GL_FRONT, GL_DIFFUSE, light1_diffuse); glLightfv(GL_LIGHT0,GL_POSITION,lightPosition1); glMaterialfv(GL_FRONT, GL_AMBIENT, light2_ambient); glMaterialfv(GL_FRONT, GL_SPECULAR, light2_specular); glMaterialfv(GL_FRONT, GL_DIFFUSE, light2_diffuse); glLightfv(GL_LIGHT1,GL_POSITION,lightPosition2); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); currentWindow = glutGetWindow(); /* draw window 1 and shading models */ if(currentWindow==1) { glLoadIdentity(); glShadeModel(GL_FLAT); glTranslatef(-300,-300,350); glRotatef(object1Window1Rotate,-1.0f,-1.0f,0.0f); drawObject(object1Window1); glLoadIdentity(); glRotatef(object2Window1Rotate,1.0f,1.0f,0.0f); drawObject(object2Window1); } /* draw window 2 and shading models */ else if(currentWindow==2) { glLoadIdentity(); glShadeModel(GL_SMOOTH); glTranslatef(-300,-300,350); glRotatef(object1Window2Rotate,-1.0f,-1.0f,0.0f); drawObject(object1Window2); glLoadIdentity(); glRotatef(object2Window2Rotate,1.0f,1.0f,0.0f); drawObject(object2Window2); } /* draw window 3 and shading models */ else if(currentWindow==3) { glLoadIdentity(); glTranslatef(-300,-300,350); glRotatef(object1Window3Rotate,-1.0f,-1.0f,0.0f); drawObject(object1Window3); glLoadIdentity(); glRotatef(object2Window3Rotate,1.0f,1.0f,0.0f); drawObject(object2Window3); } /* double buffering, swap buffers for update */ glutSwapBuffers(); } /* resize window, new width and height */ void resize(int width, int height) { glViewport(0,0,width,height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); /* scale window */ if(width<=height) glOrtho(-500,500,-500*height/width, 500*height/width, -550.0,550.0); else glOrtho(-500*width/height, 500*width/height, -500, 500, -550.0, 550.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } /* perform angle adjustments and then post redisplay * to show 'animated' */ void animate() { /* animate window 1 */ if(RotateWindow1) { glutSetWindow(window1); object1Window1Rotate+=object1Rotation; object2Window1Rotate+=object2Rotation; if(object1Window1Rotate>=360) { object1Window1Rotate=0; } if(object2Window1Rotate>=360) { object2Window1Rotate=0; } } /* animate window 2 */ if(RotateWindow2) { glutSetWindow(window2); object1Window2Rotate+=object1Rotation; object2Window2Rotate+=object2Rotation; if(object1Window2Rotate>=360) { object1Window2Rotate=0; } if(object2Window2Rotate>=360) { object2Window2Rotate=0; } } /* animate window 3 */ if(RotateWindow3) { glutSetWindow(window3); object1Window3Rotate+=object1Rotation; object2Window3Rotate+=object2Rotation; if(object1Window3Rotate>=360) { object1Window3Rotate=0; } if(object2Window3Rotate>=360) { object2Window3Rotate=0; } } /* call timer for 100 milliseconds to reduce cpu overload */ glutTimerFunc(100,NULL,1); /* update display 'show' animation */ glutPostRedisplay(); } /* mouse handler */ void mouse(int button, int x, int y) { /* get current window and set parameters * that determine which window to animate */ int currentWindow = glutGetWindow(); switch(button) { case GLUT_LEFT_BUTTON: case GLUT_RIGHT_BUTTON: if(currentWindow== 1) { RotateWindow1=true; RotateWindow2=false; RotateWindow3=false; } else if(currentWindow==2) { RotateWindow1=false; RotateWindow2=true; RotateWindow3=false; } else if (currentWindow==3) { RotateWindow1=false; RotateWindow2=false; RotateWindow3=true; } break; } } int main(int argc, char *argv[]) { /* initialise glut library */ glutInit(&argc, argv); /* set the initial display mode */ glutInitDisplayMode (GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH); /* initial window size */ glutInitWindowSize(windowHeight,windowWidth); /* load objects from file */ loadObjects(); /* create window with logo on title bar */ window1 = glutCreateWindow("Window 1 Flat Shade"); glutSetWindow(window1); /* other initialisation that needs to be done */ initWindow1(); /* set the resize window function */ glutReshapeFunc(resize); /* drawing and display function */ glutDisplayFunc(display); /* idle function, rotations and angle calculations */ glutIdleFunc(animate); /* mouse events handler window 1 */ glutMouseFunc(mouse); window2 = glutCreateWindow("Window 2 Gouraud Shading"); glutSetWindow(window2); /* other initialisation that needs to be done */ initWindow2(); /* set the resize window function */ glutReshapeFunc(resize); /* drawing and display function */ glutDisplayFunc(display); /* idle function, rotations and angle calculations */ glutIdleFunc(animate); /* mouse events handler window 2 */ glutMouseFunc(mouse); /* enter event processing loop */ window3 = glutCreateWindow("Window 3 Gouraud Shade Averaging Normals"); glutSetWindow(window3); /* other initialisation that needs to be done */ initWindow3(); /* set the resize window function */ glutReshapeFunc(resize); /* drawing and display function */ glutDisplayFunc(display); /* idle function, rotations and angle calculations */ glutIdleFunc(animate); /* mouse events handler window 3 */ glutMouseFunc(mouse); glutMainLoop(); return 0; } /* a3.c */