(no commit message)
[atyndall/cits2231.git] / scene.c
1 /**\r
2  * CITS2231 Graphics Scene Editor\r
3  * @author Ashley Tyndall (20915779)\r
4  */\r
5 \r
6 #include <stdlib.h>\r
7 #include <stdio.h>\r
8 #include <dirent.h>\r
9 #include <string.h>\r
10 #include <math.h>\r
11 #include <GL/gl.h>\r
12 #include <GL/glut.h>\r
13 #include <time.h>\r
14 \r
15 #include "bitmap.h"\r
16 \r
17 // Type definitions for vertex-coordinates, normals, texture-coordinates, \r
18 // and triangles (via the indices of 3 vertices).\r
19 typedef GLfloat vertex[3];\r
20 typedef GLfloat normal[3];\r
21 typedef GLfloat texCoord[2];\r
22 typedef GLint vertexIndex;\r
23 typedef vertexIndex triangle[3];\r
24 \r
25 // A type for a mesh\r
26 typedef struct {         \r
27     int nVertices;           //  The number of vertices in the mesh\r
28     vertex* vertices;        //  Array with coordinates of vertices\r
29     normal* normals;         //  Array with normals of vertices\r
30     texCoord* texCoords;     //  Array with texture-coordinates of vertices\r
31     int nTriangles;          //  The number of triangles in the mesh\r
32     triangle* triangles;     //  Array of trangles via 3 indices into "vertices"\r
33 } mesh;\r
34 \r
35 #define NMESH 54       // The number of meshes (in the models-textures dir)\r
36 mesh* meshes[NMESH];   // An array of pointers to the meshes - see getMesh\r
37 \r
38 // A type for a 2D texture, with height and width in pixels\r
39 typedef struct {\r
40     int height;\r
41     int width;\r
42     GLubyte *rgbData;   // Array of bytes with the colour data for the texture\r
43 } texture;\r
44 \r
45 #define NTEXTURE 30     // The number of textures (in the models-textures dir)\r
46 texture* textures[NTEXTURE];   // An array of texture pointers - see getTexture\r
47 \r
48 typedef struct {  \r
49     // You'll need to add scale, rotation, material, mesh number, etc.,\r
50     // to this structure\r
51     float x,y,z;\r
52 } SceneObject;\r
53 \r
54 // Menu enum\r
55 enum menu {\r
56   // Main menu\r
57   ROTATE_MOVE_CAMERA,\r
58   POSITION_SCALE,\r
59   ROTATION_TEXTURE_SCALE,\r
60   EXIT,\r
61 \r
62   // Material submenu\r
63   MATERIAL_ALL_RGB,\r
64   MATERIAL_AMBIENT_RGB,\r
65   MATERIAL_DIFFUSE_RGB,\r
66   MATERIAL_SPECULAR_RGB,\r
67   MATERIAL_ALL_ADSS,\r
68   MATERIAL_RED_ADSS,\r
69   MATERIAL_GREEN_ADSS,\r
70   MATERIAL_BLUE_ADSS,\r
71 \r
72   // Light submenu\r
73   LIGHT_MOVE_LIGHT_1,\r
74   LIGHT_RGBALL_LIGHT_1,\r
75   LIGHT_MOVE_LIGHT_2,\r
76   LIGHT_RGBALL_LIGHT_2\r
77 };\r
78 \r
79 // Menu arrays\r
80 const char *textureMenuEntries[NTEXTURE] = {\r
81   "1 Plain", "2 Rust", "3 Concrete", "4 Carpet", "5 Beach Sand",\r
82   "6 Rocky", "7 Brick", "8 Water", "9 Paper", "10 Marble",\r
83   "11 Wood", "12 Scales", "13 Fur", "14 Denim", "15 Hessian",\r
84   "16 Orange Peel", "17 Ice Crystals", "18 Grass", "19 Corrugated Iron", "20 Styrofoam",\r
85   "21 Bubble Wrap", "22 Leather", "23 Camouflage", "24 Asphalt", "25 Scratched Ice",\r
86   "26 Rattan", "27 Snow", "28 Dry Mud", "29 Old Concrete", "30 Leopard Skin"\r
87 };\r
88 \r
89 const char *objectMenuEntries[NMESH] = {\r
90   "1 Thin Dinosaur","2 Big Dog","3 Saddle Dinosaur", "4 Dragon", "5 Cleopatra",\r
91   "6 Bone I", "7 Bone II", "8 Rabbit", "9 Long Dragon", "10 Buddha",\r
92   "11 Sitting Rabbit", "12 Frog", "13 Cow", "14 Monster", "15 Sea Horse",\r
93   "16 Head", "17 Pelican", "18 Horse", "19 Kneeling Angel", "20 Porsche I",\r
94   "21 Truck", "22 Statue of Liberty", "23 Sitting Angel", "24 Metal Part", "25 Car",\r
95   "26 Apatosaurus", "27 Airliner", "28 Motorbike", "29 Dolphin", "30 Spaceman",\r
96   "31 Winnie the Pooh", "32 Shark", "33 Crocodile", "34 Toddler", "35 Fat Dinosaur",\r
97   "36 Chihuahua", "37 Sabre-toothed Tiger", "38 Lioness", "39 Fish", "40 Horse (head down)",\r
98   "41 Horse (head up)", "42 Skull", "43 Fighter Jet I", "44 Toad", "45 Convertible",\r
99   "46 Porsche II", "47 Hare", "48 Vintage Car", "49 Fighter Jet II", "50 Winged Monkey",\r
100   "51 Chef", "52 Parasaurolophus", "53 Rooster", "54 T-rex"\r
101 };\r
102 \r
103 #define MAXOBJECTS 256\r
104 SceneObject sceneObjs[MAXOBJECTS];  // An array with details of the objects in a scene\r
105 int nObjects=0;                     // How many objects there are in the scene currently.\r
106 \r
107 // Directories containing models\r
108 char *dirDefault1 = "models-textures";\r
109 char *dirDefault2 = "/cslinux/examples/CITS2231/project-files/models-textures";\r
110 \r
111 char dataDir[200];  // Stores the directory name for the meshes and textures.\r
112 \r
113 static GLfloat lightColor[] = {1.0, 1.0, 1.0, 1.0}; // White light\r
114 static GLfloat lightPosition[4];\r
115 \r
116 int moving, startx, starty;\r
117 int lightMoving = 0, lightStartX, lightStartY;\r
118 \r
119 /* Time varying or user-controled variables. */\r
120 static float jump = 0.0;\r
121 static float lightAngle = 0.0, lightHeight = 5;\r
122 GLfloat angle = -150;   /* in degrees */\r
123 GLfloat angle2 = 30;   /* in degrees */\r
124 \r
125 /* Near and far parameters */\r
126 GLfloat near = -10;\r
127 GLfloat far = 10;\r
128 \r
129 /* Zoom factor for mouse movements */\r
130 GLfloat zoomFactor = 1.0;\r
131 \r
132 /* Recursion level for floor drawing */\r
133 int drawFloorRecurse = 5;\r
134 \r
135 /* Size of floor, from -n to n */\r
136 int floorSize = 100;\r
137 \r
138 /* Light 0 parameters */\r
139 GLfloat diffuse0[] = {1.0, 1.0, 1.0, 1.0};\r
140 GLfloat ambient0[] = {1.0, 1.0, 1.0, 1.0};\r
141 GLfloat specular0[] = {1.0, 1.0, 1.0, 1.0};\r
142 GLfloat light0_pos[] ={ 1.0, 2.0, 3,0, 1.0};\r
143 GLfloat emission0[] = {0.0, 0.0, 0.0, 0.0};\r
144 \r
145 \r
146 /**\r
147  * Prints out error message when file cannot be read\r
148  * @param fileName Name of file that could not be read\r
149  */\r
150 void fileErr(char* fileName) {\r
151     printf("Error reading file: %s\n", fileName);\r
152     printf("If not in the CSSE labs, you will need to include the directory containing\n");\r
153     printf("the models on the command line, or put it in the same folder as the exectutable.");\r
154     exit(EXIT_FAILURE);\r
155 }  \r
156 \r
157 /**\r
158  * Reads .bmp texture files and converts them to a texture object\r
159  * @param fileName .bmp texture file\r
160  * @return texture object\r
161  */\r
162 texture* loadTexture(char *fileName) {\r
163     texture* t = malloc(sizeof (texture));\r
164     BITMAPINFO *info;\r
165 \r
166     t->rgbData = LoadDIBitmap(fileName, &info);\r
167     t->height=info->bmiHeader.biHeight;\r
168     t->width=info->bmiHeader.biWidth;\r
169 \r
170     return t;\r
171 }\r
172 \r
173 /**\r
174  * Reads .x files and converts them to a mesh object\r
175  * @param fileName .x mesh file\r
176  * @return mesh object\r
177  */\r
178 mesh* loadMesh(char* fileName) {\r
179     mesh* m = malloc(sizeof (mesh));\r
180     FILE* fp = fopen(fileName, "r");\r
181     char line[256] = "";\r
182     int lineBuffSize = 256;\r
183 \r
184     if(fp == NULL) fileErr(fileName);\r
185 \r
186     while(strcmp(line,"Mesh {\r\n") != 0 && strcmp(line,"Mesh {\n") != 0 )\r
187         fgets(line, lineBuffSize, fp);\r
188 \r
189     fscanf(fp, "%d;\n", &(m->nVertices));\r
190     m->vertices = malloc(m->nVertices * sizeof(vertex));\r
191     for(int i=0; i < m->nVertices; i++)\r
192         fscanf(fp, "%f; %f; %f;%*[,;]\n", &(m->vertices[i][0]), &(m->vertices[i][1]), &(m->vertices[i][2]) );\r
193 \r
194     fscanf(fp, "%d;\n", &(m->nTriangles));\r
195     m->triangles = malloc(m->nTriangles * sizeof(triangle));\r
196     for(int i=0; i < m->nTriangles; i++)\r
197         fscanf(fp, "%*d; %d, %d, %d;%*[;,]", m->triangles[i], m->triangles[i]+1, m->triangles[i]+2);\r
198 \r
199     while(strcmp(line,"  MeshNormals {\r\n") != 0 && strcmp(line,"  MeshNormals {\n") != 0)\r
200         fgets(line, lineBuffSize, fp);\r
201 \r
202     fgets(line, lineBuffSize, fp);\r
203     m->normals = malloc(m->nVertices * sizeof(normal));\r
204     for(int i=0; i < m->nVertices; i++)\r
205         fscanf(fp, "%f; %f; %f;%*[;,]\n",\r
206                &(m->normals[i][0]), &(m->normals[i][1]), &(m->normals[i][2]));\r
207 \r
208     while(strcmp(line,"MeshTextureCoords {\r\n") != 0 && strcmp(line,"MeshTextureCoords {\n") != 0)\r
209         fgets(line, lineBuffSize, fp);\r
210 \r
211     fgets(line, lineBuffSize, fp);\r
212     m->texCoords = malloc(m->nVertices * sizeof(texCoord));\r
213     for(int i=0; i < m->nVertices; i++)\r
214         fscanf(fp, "%f;%f;%*[,;]\n", &(m->texCoords[i][0]), &(m->texCoords[i][1]) );\r
215     fclose(fp);\r
216     \r
217     return m;\r
218 }\r
219 \r
220 // [You may want to add to this function.]\r
221 /**\r
222  * Loads mesh[i] if it isn't already loaded.\r
223  * You must call getMesh(i) at least once before using mesh[i].\r
224  *\r
225  * @param i Mesh ID\r
226  */\r
227 void getMesh(int i) { // getMesh(i) loads mesh[i] if it isn't already loaded.  \r
228     char fileName[220];\r
229     if(i>=NMESH || i<0) {\r
230         printf("Error in getMesh - wrong model number");\r
231         exit(1);\r
232     }\r
233     if(meshes[i] != NULL)\r
234         return;\r
235     sprintf(fileName, "%s/model%d.x", dataDir, i+1);\r
236     meshes[i] = loadMesh(fileName);\r
237 }\r
238 \r
239 /**\r
240  * Loads texture i if it isn't already loaded\r
241  *\r
242  * After calling getTexture(i), you can make texture i the current texture using\r
243  *      glBindTexture(GL_TEXTURE_2D, i);\r
244  * Use i=0 to return to the default plain texture.\r
245  *\r
246  * You can then scale the texture via:\r
247  *      glMatrixMode(GL_TEXTURE);\r
248  * See the textbook, section 8.8.3.\r
249  *\r
250  * You must call getTexture(i) at least once before using texture i.\r
251  * @param i Texture ID\r
252  */\r
253 void getTexture(int i) {\r
254     char fileName[220];\r
255     if(i<1 || i>NTEXTURE) {\r
256         printf("Error in getTexture - wrong texture number");\r
257         exit(1);\r
258     }\r
259     if(textures[i-1] != NULL)\r
260         return;\r
261     sprintf(fileName, "%s/texture%d.bmp", dataDir, i);\r
262 \r
263     textures[i-1] = loadTexture(fileName);\r
264 \r
265     glBindTexture(GL_TEXTURE_2D, i);\r
266 \r
267     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textures[i-1]->width, textures[i-1]->height,\r
268                  0, GL_RGB, GL_UNSIGNED_BYTE, textures[i-1]->rgbData);\r
269     gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, textures[i-1]->width, textures[i-1]->height, GL_RGB, \r
270                       GL_UNSIGNED_BYTE, textures[i-1]->rgbData);\r
271     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);\r
272     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);\r
273     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\r
274     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);\r
275 \r
276     glBindTexture(GL_TEXTURE_2D, 0);  // Back to default texture\r
277 }\r
278 \r
279 /**\r
280  * Event hander for main menu events\r
281  * @param id ID of menu item selected\r
282  */\r
283 void processMainEvents(int id) {\r
284   switch (id) {\r
285     case ROTATE_MOVE_CAMERA:\r
286       // Do stuff\r
287       break;\r
288 \r
289     case POSITION_SCALE:\r
290       // Do stuff\r
291       break;\r
292 \r
293     case ROTATION_TEXTURE_SCALE:\r
294       // Do stuff\r
295       break;\r
296 \r
297     case EXIT:\r
298       exit(EXIT_SUCCESS);\r
299 \r
300   }\r
301 }\r
302 \r
303 /**\r
304  * Event hander for materials menu events\r
305  * @param id ID of menu item selected\r
306  */\r
307 void processMaterialEvents(int id) {\r
308   switch (id) {\r
309     case MATERIAL_ALL_RGB:\r
310       // Do stuff\r
311       break;\r
312 \r
313     case MATERIAL_AMBIENT_RGB:\r
314       // Do stuff\r
315       break;\r
316 \r
317     case MATERIAL_DIFFUSE_RGB:\r
318       // Do stuff\r
319       break;\r
320 \r
321     case MATERIAL_SPECULAR_RGB:\r
322       // Do stuff\r
323       break;\r
324 \r
325     case MATERIAL_ALL_ADSS:\r
326       // Do stuff\r
327       break;\r
328 \r
329     case MATERIAL_RED_ADSS:\r
330       // Do stuff\r
331       break;\r
332 \r
333     case MATERIAL_GREEN_ADSS:\r
334       // Do stuff\r
335       break;\r
336 \r
337     case MATERIAL_BLUE_ADSS:\r
338       // Do stuff\r
339       break;\r
340 \r
341   }\r
342 }\r
343 \r
344 /**\r
345  * Event hander for light menu events\r
346  * @param id ID of menu item selected\r
347  */\r
348 void processLightEvents(int id) {\r
349   switch (id) {\r
350     case LIGHT_MOVE_LIGHT_1:\r
351       // Do stuff\r
352       break;\r
353 \r
354     case LIGHT_RGBALL_LIGHT_1:\r
355       // Do stuff\r
356       break;\r
357 \r
358     case LIGHT_MOVE_LIGHT_2:\r
359       // Do stuff\r
360       break;\r
361 \r
362     case LIGHT_RGBALL_LIGHT_2:\r
363       // Do stuff\r
364       break;\r
365 \r
366   }\r
367 }\r
368 \r
369 /**\r
370  * Event hander for object menu events\r
371  * @param id ID of object selected\r
372  */\r
373 void processObjectEvents(int id) {\r
374 \r
375 }\r
376 \r
377 /**\r
378  * Event hander for texture menu events\r
379  * @param id ID of texutre selected\r
380  */\r
381 void processTextureEvents(int id) {\r
382 \r
383 }\r
384 \r
385 /**\r
386  * Event hander for ground texture menu events\r
387  * @param id ID of ground texture selected\r
388  */\r
389 void processGTextureEvents(int id) {\r
390 \r
391 }\r
392 \r
393 /**\r
394  * Rounds up numbers, from http://stackoverflow.com/questions/3407012/c-rounding-up-to-the-nearest-multiple-of-a-number\r
395  * @param numToRound Number to round\r
396  * @param multiple Multiple to round up to\r
397  * @return Rounded number\r
398  */\r
399 int roundUp(int numToRound, int multiple) {\r
400   if(multiple == 0) {\r
401     return numToRound;\r
402   }\r
403 \r
404   int remainder = numToRound % multiple;\r
405   if (remainder == 0)\r
406     return numToRound;\r
407   return numToRound + multiple - remainder;\r
408 }\r
409 \r
410 /**\r
411  * Makes a submenu from an array of items, splitting the list into subsubmenus\r
412  * of only 10 items.\r
413  * @param menuEntries Array of menu items\r
414  * @param menuEntriesSize Size of menuEntries\r
415  * @param callback Callback function for this array of menu items\r
416  * @return Reference to menu created\r
417  */\r
418 int makeSubmenuFromArray( const char *menuEntries[], unsigned int menuEntriesSize, void *callback ) {\r
419   if ( menuEntriesSize == 0 ) return -1;\r
420 \r
421   int menuNumber = roundUp(menuEntriesSize, 10) / 10;\r
422   int submenuObjects[menuNumber-1];\r
423 \r
424   for( int i = 0; i < menuNumber; i++ ) {\r
425     submenuObjects[i] = glutCreateMenu(callback);\r
426     int startNum = i*11 - (i-1);\r
427     for ( int j = startNum - 1; j < (startNum+9); j++ ) {\r
428       if ( j == menuEntriesSize ) break; // Detect if we've reached the end of the array\r
429       glutAddMenuEntry( menuEntries[j], j + 1 );\r
430     }\r
431   } \r
432 \r
433   int mainMenu = glutCreateMenu(callback);\r
434   for ( int i = 0; i < menuNumber; i++ ) {\r
435     char name[10]; // buffer to hold name\r
436     int startNum = i*11 - (i-1);\r
437     int endNum = startNum + 9;\r
438     if ( i == menuNumber - 1 ) { // We're on the last one\r
439       endNum = startNum + (menuEntriesSize - startNum); // Work out final number\r
440     }\r
441     sprintf(name, "%d-%d", startNum, endNum);\r
442     glutAddSubMenu( name, submenuObjects[i] );\r
443   }\r
444 \r
445   return mainMenu;\r
446 }\r
447 \r
448 /**\r
449  * Creates menu for program\r
450  */\r
451 void makeMenu() {\r
452   // Construct material menu\r
453   int materialMenu = glutCreateMenu(processMaterialEvents);\r
454   glutAddMenuEntry("All R/G/B", MATERIAL_ALL_RGB);\r
455   glutAddMenuEntry("Ambient R/G/B", MATERIAL_AMBIENT_RGB);\r
456   glutAddMenuEntry("Diffuse R/G/B", MATERIAL_DIFFUSE_RGB);\r
457   glutAddMenuEntry("Specular R/G/B", MATERIAL_SPECULAR_RGB);\r
458   glutAddMenuEntry("All Amb/Diff/Spec/Shine", MATERIAL_ALL_ADSS);\r
459   glutAddMenuEntry("Red Amb/Diff/Spec/Shine", MATERIAL_RED_ADSS);\r
460   glutAddMenuEntry("Green Amb/Diff/Spec/Shine", MATERIAL_GREEN_ADSS);\r
461   glutAddMenuEntry("Blue Amb/Diff/Spec/Shine", MATERIAL_BLUE_ADSS);\r
462 \r
463   // Construct light menu\r
464   int lightMenu = glutCreateMenu(processLightEvents);\r
465   glutAddMenuEntry("Move Light 1", LIGHT_MOVE_LIGHT_1);\r
466   glutAddMenuEntry("R/G/B/All Light 1", LIGHT_RGBALL_LIGHT_1);\r
467   glutAddMenuEntry("Move Light 2", LIGHT_MOVE_LIGHT_2);\r
468   glutAddMenuEntry("R/G/B/All Light 2", LIGHT_RGBALL_LIGHT_2);\r
469 \r
470   // Construct object menu\r
471   int objectMenuEntriesSize = sizeof(objectMenuEntries) / sizeof(objectMenuEntries[0]);\r
472   int objectMenu = makeSubmenuFromArray( objectMenuEntries, objectMenuEntriesSize, processObjectEvents );\r
473 \r
474   // Construct texture / ground texture menus\r
475   int textureMenuEntriesSize = sizeof(textureMenuEntries) / sizeof(textureMenuEntries[0]);\r
476   int textureMenu = makeSubmenuFromArray( textureMenuEntries, textureMenuEntriesSize, processTextureEvents );\r
477   int gTextureMenu = makeSubmenuFromArray( textureMenuEntries, textureMenuEntriesSize, processGTextureEvents );\r
478 \r
479   // Construct main menu\r
480   glutCreateMenu(processMainEvents);\r
481   //glutAddMenuEntry("Rotate/Move Camera", ROTATE_MOVE_CAMERA);\r
482   //glutAddSubMenu("Add object", objectMenu);\r
483   //glutAddMenuEntry("Position/Scale", POSITION_SCALE);\r
484   //glutAddMenuEntry("Rotation/Texture Scale", ROTATION_TEXTURE_SCALE);\r
485   //glutAddSubMenu("Material", materialMenu);\r
486   //glutAddSubMenu("Texture", textureMenu);\r
487   //glutAddSubMenu("Ground texture", gTextureMenu);\r
488   //glutAddSubMenu("Lights", lightMenu);\r
489   glutAddMenuEntry("Exit", EXIT);\r
490 \r
491   // Bind to right mouse button\r
492   glutAttachMenu(GLUT_RIGHT_BUTTON);\r
493 }\r
494 \r
495 /**\r
496  * Called when window is resized\r
497  * @param w New width\r
498  * @param h New height\r
499  */\r
500 void windowReshape(int w, int h) {\r
501   glViewport(0, 0, (GLsizei) w, (GLsizei) h);\r
502   glMatrixMode(GL_PROJECTION);\r
503   glLoadIdentity();\r
504   if (w <= h) \r
505     glOrtho(near, far, near*(GLfloat)h/(GLfloat)w,\r
506              far*(GLfloat)h/(GLfloat)w, near, far);\r
507   else\r
508     glOrtho(near*(GLfloat)w/(GLfloat)h,\r
509              far*(GLfloat)w/(GLfloat)h, near, far, near, far);\r
510    glMatrixMode(GL_MODELVIEW); \r
511    glLoadIdentity();\r
512 }\r
513 \r
514 /**\r
515  * Called when mouse event occurs\r
516  * @param btn Mouse button\r
517  * @param state State of mouse button\r
518  * @param x Mouse x position\r
519  * @param y Mouse y position\r
520  */\r
521 void mouse(int button, int state, int x, int y) {\r
522   if (button == GLUT_LEFT_BUTTON) {\r
523     if (state == GLUT_DOWN) {\r
524       moving = 1;\r
525       startx = x;\r
526       starty = y;\r
527     }\r
528     if (state == GLUT_UP) {\r
529       moving = 0;\r
530     }\r
531   }\r
532   if (button == GLUT_MIDDLE_BUTTON) {\r
533     if (state == GLUT_DOWN) {\r
534       lightMoving = 1;\r
535       lightStartX = x;\r
536       lightStartY = y;\r
537     }\r
538     if (state == GLUT_UP) {\r
539       lightMoving = 0;\r
540     }\r
541   }\r
542 }\r
543 \r
544 /**\r
545  * Called when motion event occurs\r
546  * @param x Mouse x position\r
547  * @param y Mouse y position\r
548  */\r
549 void motion(int x, int y) {\r
550   if (moving) {\r
551     angle = angle + (x - startx);\r
552     angle2 = angle2 + (y - starty);\r
553     startx = x;\r
554     starty = y;\r
555     glutPostRedisplay();\r
556   }\r
557   if (lightMoving) {\r
558     lightAngle += (x - lightStartX)/40.0;\r
559     lightHeight += (lightStartY - y)/20.0;\r
560     lightStartX = x;\r
561     lightStartY = y;\r
562     glutPostRedisplay();\r
563   }\r
564 }\r
565 \r
566 /**\r
567  * Recursive function to draw a square by drawing smaller and smaller\r
568  * divisions of the square, determined by drawFloorRecurse.\r
569  * @param recurseLevel Current level of recursion, only pass 0\r
570  * @param x1 top-left x\r
571  * @param z1 top-left z\r
572  * @param x2 bottom-left x\r
573  * @param z2 bottom-left z\r
574  */\r
575 void drawSquare(int recurseLevel, float x1, float z1, float x2, float z2) {\r
576 \r
577   if ( drawFloorRecurse != recurseLevel ) {\r
578     // Calculate middle points\r
579     float xm = (x1 + x2) / 2.0;\r
580     float zm = (z1 + z2) / 2.0;\r
581 \r
582     // Increment recursion level\r
583     int rnew = recurseLevel + 1;\r
584 \r
585     // Split into four sub-quads\r
586     drawSquare(rnew, x1, z1, xm, zm);\r
587     drawSquare(rnew, x1, zm, xm, z2);\r
588     drawSquare(rnew, xm, zm, x2, z2);\r
589     drawSquare(rnew, xm, z1, x2, zm);\r
590 \r
591   } else {\r
592     // Draw square.\r
593     // **NOTE: Is the polygon facing in the right direction?\r
594     glBegin(GL_QUADS);\r
595       glVertex3f(x1, 0.0, z1);\r
596       glVertex3f(x1, 0.0, z2);\r
597       glVertex3f(x2, 0.0, z2);\r
598       glVertex3f(x2, 0.0, z1);\r
599     glEnd();\r
600   }\r
601 \r
602 }\r
603 \r
604 /**\r
605  * Draw a floor by calling the drawSquare recursion\r
606  */\r
607 void drawFloor() {\r
608   drawSquare(0, -floorSize, -floorSize, floorSize, floorSize);\r
609 }\r
610 \r
611 /**\r
612  * Draw x, z axis on floor\r
613  */\r
614 void drawLine() {\r
615     // **NOTE: fix function\r
616     glDisable(GL_TEXTURE_2D);\r
617     glEnable(GL_BLEND);\r
618     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\r
619     glColor4ub( 0.0, 0.0, 0.0, 0.5 );\r
620 \r
621     glBegin(GL_LINES);\r
622     glVertex3i( 10.0, 0.1, 10.0);\r
623     glVertex3i( -10.0, 0.1, -10.0);\r
624     glEnd();\r
625 \r
626     glDisable(GL_BLEND);\r
627     glEnable(GL_TEXTURE_2D);\r
628 }\r
629 \r
630 /**\r
631  * Display function\r
632  */\r
633 void display() {\r
634   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\r
635   glLoadIdentity();\r
636   gluLookAt(\r
637     0.0, 0.0, 10.0,  /* eye is at (x,y,z) */\r
638     0.0, 0.0,  0.0,  /* center is at (x,y,z) */\r
639     0.0, 1.0,  0.0   /* up is in postivie Y direction */\r
640     );\r
641 \r
642 \r
643   // **NOTE: Currently this rotation function is all that moves the camera off\r
644   //         the flat surface. Need to integrate function into gluLookAt\r
645   glRotatef(30.0, 1.0, 0.0, 0.0);\r
646 \r
647   /* Reposition the light source. */\r
648   lightPosition[0] = 12*cos(lightAngle);\r
649   lightPosition[1] = lightHeight;\r
650   lightPosition[2] = 12*sin(lightAngle);\r
651   lightPosition[3] = 0.0;\r
652 \r
653   glPushMatrix();\r
654 \r
655     /* Perform scene rotations based on user mouse input. */\r
656     glRotatef(angle, 0.0, 1.0, 0.0);\r
657     //glRotatef(angle2, 1.0, 0.0, 0.0); **NOTE: Only one degree of freedom\r
658 \r
659     glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);\r
660 \r
661     drawFloor();\r
662 \r
663     drawLine();\r
664     \r
665     // Draw teapot for a test object\r
666     glPushMatrix();\r
667       glTranslatef(0.0, 1.0, 0.0); // **NOTE: Teapot does not rest on surface\r
668       glutWireTeapot(1);\r
669     glPopMatrix();\r
670 \r
671     // Draw a white ball over the light source\r
672     glPushMatrix();\r
673       glDisable(GL_LIGHTING);\r
674       glColor3f(1.0, 1.0, 1.0);\r
675       glTranslatef(lightPosition[0], lightPosition[1], lightPosition[2]);\r
676       glutSolidSphere(1.0, 50, 50);\r
677       glEnable(GL_LIGHTING);\r
678     glPopMatrix();\r
679 \r
680   glPopMatrix();\r
681 \r
682   glutSwapBuffers();\r
683 }\r
684 \r
685 /**\r
686  * init function; sets initial OpenGL state\r
687  */\r
688 void init() {\r
689   glMatrixMode(GL_PROJECTION);\r
690   glLoadIdentity();\r
691 \r
692   gluPerspective(\r
693     60.0,  /* field of view in degree */\r
694      1.0,  /* aspect ratio */\r
695     near,  /* Z near */\r
696      far   /* Z far */\r
697     );    \r
698 \r
699   glEnable(GL_LIGHT0);\r
700   glLightfv(GL_LIGHT0, GL_POSITION, light0_pos);\r
701   glLightfv(GL_LIGHT0, GL_AMBIENT, ambient0);\r
702   glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0);\r
703   glLightfv(GL_LIGHT0, GL_SPECULAR, specular0);\r
704   glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );\r
705   glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, specular0);\r
706   glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, emission0);\r
707   glEnable(GL_COLOR_MATERIAL);\r
708 \r
709   glEnable(GL_LIGHTING);\r
710 \r
711   glMatrixMode(GL_MODELVIEW);\r
712   glLoadIdentity();\r
713 }\r
714 \r
715 /**\r
716  * Main function\r
717  * @param argc Number of arguments\r
718  * @param argv Array of arguments\r
719  * @return Program exit code\r
720  */\r
721 int main(int argc, char **argv) {\r
722   if(argc>1)\r
723     strcpy(dataDir, argv[1]);\r
724   else if(opendir(dirDefault1))\r
725     strcpy(dataDir, dirDefault1);\r
726   else if(opendir(dirDefault2))\r
727     strcpy(dataDir, dirDefault2);\r
728   else fileErr(dirDefault1);\r
729 \r
730   for(int i=0; i<NMESH; i++) meshes[i]=NULL;\r
731   for(int i=0; i<NTEXTURE; i++) textures[i]=NULL;\r
732 \r
733   glutInit(&argc, argv);\r
734 \r
735   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);\r
736 \r
737   glutInitWindowSize(500, 500);\r
738   glutCreateWindow("Scene Editor");\r
739 \r
740   glShadeModel(GL_SMOOTH); // Enables Smooth Shading\r
741   glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Black Background\r
742   glClearDepth(1.0f); // Depth Buffer Setup\r
743   glEnable(GL_DEPTH_TEST); // Enables Depth Testing\r
744   glDepthFunc(GL_LEQUAL);  // the type\r
745   glEnable(GL_CULL_FACE);\r
746   glEnable(GL_TEXTURE_2D);\r
747   glLineWidth(1.0);\r
748 \r
749   glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);\r
750 \r
751   glutReshapeFunc(windowReshape);\r
752   glutDisplayFunc(display);\r
753   glutMouseFunc(mouse);\r
754   glutMotionFunc(motion);\r
755 \r
756   makeMenu();\r
757 \r
758   init();\r
759 \r
760   glutMainLoop();\r
761 }\r

UCC git Repository :: git.ucc.asn.au