(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 \r
144 \r
145 /**\r
146  * Prints out error message when file cannot be read\r
147  * @param fileName Name of file that could not be read\r
148  */\r
149 void fileErr(char* fileName) {\r
150     printf("Error reading file: %s\n", fileName);\r
151     printf("If not in the CSSE labs, you will need to include the directory containing\n");\r
152     printf("the models on the command line, or put it in the same folder as the exectutable.");\r
153     exit(EXIT_FAILURE);\r
154 }  \r
155 \r
156 /**\r
157  * Reads .bmp texture files and converts them to a texture object\r
158  * @param fileName .bmp texture file\r
159  * @return texture object\r
160  */\r
161 texture* loadTexture(char *fileName) {\r
162     texture* t = malloc(sizeof (texture));\r
163     BITMAPINFO *info;\r
164 \r
165     t->rgbData = LoadDIBitmap(fileName, &info);\r
166     t->height=info->bmiHeader.biHeight;\r
167     t->width=info->bmiHeader.biWidth;\r
168 \r
169     return t;\r
170 }\r
171 \r
172 /**\r
173  * Reads .x files and converts them to a mesh object\r
174  * @param fileName .x mesh file\r
175  * @return mesh object\r
176  */\r
177 mesh* loadMesh(char* fileName) {\r
178     mesh* m = malloc(sizeof (mesh));\r
179     FILE* fp = fopen(fileName, "r");\r
180     char line[256] = "";\r
181     int lineBuffSize = 256;\r
182 \r
183     if(fp == NULL) fileErr(fileName);\r
184 \r
185     while(strcmp(line,"Mesh {\r\n") != 0 && strcmp(line,"Mesh {\n") != 0 )\r
186         fgets(line, lineBuffSize, fp);\r
187 \r
188     fscanf(fp, "%d;\n", &(m->nVertices));\r
189     m->vertices = malloc(m->nVertices * sizeof(vertex));\r
190     for(int i=0; i < m->nVertices; i++)\r
191         fscanf(fp, "%f; %f; %f;%*[,;]\n", &(m->vertices[i][0]), &(m->vertices[i][1]), &(m->vertices[i][2]) );\r
192 \r
193     fscanf(fp, "%d;\n", &(m->nTriangles));\r
194     m->triangles = malloc(m->nTriangles * sizeof(triangle));\r
195     for(int i=0; i < m->nTriangles; i++)\r
196         fscanf(fp, "%*d; %d, %d, %d;%*[;,]", m->triangles[i], m->triangles[i]+1, m->triangles[i]+2);\r
197 \r
198     while(strcmp(line,"  MeshNormals {\r\n") != 0 && strcmp(line,"  MeshNormals {\n") != 0)\r
199         fgets(line, lineBuffSize, fp);\r
200 \r
201     fgets(line, lineBuffSize, fp);\r
202     m->normals = malloc(m->nVertices * sizeof(normal));\r
203     for(int i=0; i < m->nVertices; i++)\r
204         fscanf(fp, "%f; %f; %f;%*[;,]\n",\r
205                &(m->normals[i][0]), &(m->normals[i][1]), &(m->normals[i][2]));\r
206 \r
207     while(strcmp(line,"MeshTextureCoords {\r\n") != 0 && strcmp(line,"MeshTextureCoords {\n") != 0)\r
208         fgets(line, lineBuffSize, fp);\r
209 \r
210     fgets(line, lineBuffSize, fp);\r
211     m->texCoords = malloc(m->nVertices * sizeof(texCoord));\r
212     for(int i=0; i < m->nVertices; i++)\r
213         fscanf(fp, "%f;%f;%*[,;]\n", &(m->texCoords[i][0]), &(m->texCoords[i][1]) );\r
214     fclose(fp);\r
215     \r
216     return m;\r
217 }\r
218 \r
219 // [You may want to add to this function.]\r
220 /**\r
221  * Loads mesh[i] if it isn't already loaded.\r
222  * You must call getMesh(i) at least once before using mesh[i].\r
223  *\r
224  * @param i Mesh ID\r
225  */\r
226 void getMesh(int i) { // getMesh(i) loads mesh[i] if it isn't already loaded.  \r
227     char fileName[220];\r
228     if(i>=NMESH || i<0) {\r
229         printf("Error in getMesh - wrong model number");\r
230         exit(1);\r
231     }\r
232     if(meshes[i] != NULL)\r
233         return;\r
234     sprintf(fileName, "%s/model%d.x", dataDir, i+1);\r
235     meshes[i] = loadMesh(fileName);\r
236 }\r
237 \r
238 /**\r
239  * Loads texture i if it isn't already loaded\r
240  *\r
241  * After calling getTexture(i), you can make texture i the current texture using\r
242  *      glBindTexture(GL_TEXTURE_2D, i);\r
243  * Use i=0 to return to the default plain texture.\r
244  *\r
245  * You can then scale the texture via:\r
246  *      glMatrixMode(GL_TEXTURE);\r
247  * See the textbook, section 8.8.3.\r
248  *\r
249  * You must call getTexture(i) at least once before using texture i.\r
250  * @param i Texture ID\r
251  */\r
252 void getTexture(int i) {\r
253     char fileName[220];\r
254     if(i<1 || i>NTEXTURE) {\r
255         printf("Error in getTexture - wrong texture number");\r
256         exit(1);\r
257     }\r
258     if(textures[i-1] != NULL)\r
259         return;\r
260     sprintf(fileName, "%s/texture%d.bmp", dataDir, i);\r
261 \r
262     textures[i-1] = loadTexture(fileName);\r
263 \r
264     glBindTexture(GL_TEXTURE_2D, i);\r
265 \r
266     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textures[i-1]->width, textures[i-1]->height,\r
267                  0, GL_RGB, GL_UNSIGNED_BYTE, textures[i-1]->rgbData);\r
268     gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, textures[i-1]->width, textures[i-1]->height, GL_RGB, \r
269                       GL_UNSIGNED_BYTE, textures[i-1]->rgbData);\r
270     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);\r
271     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);\r
272     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\r
273     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);\r
274 \r
275     glBindTexture(GL_TEXTURE_2D, 0);  // Back to default texture\r
276 }\r
277 \r
278 /**\r
279  * Event hander for main menu events\r
280  * @param id ID of menu item selected\r
281  */\r
282 void processMainEvents(int id) {\r
283   switch (id) {\r
284     case ROTATE_MOVE_CAMERA:\r
285       // Do stuff\r
286       break;\r
287 \r
288     case POSITION_SCALE:\r
289       // Do stuff\r
290       break;\r
291 \r
292     case ROTATION_TEXTURE_SCALE:\r
293       // Do stuff\r
294       break;\r
295 \r
296     case EXIT:\r
297       exit(EXIT_SUCCESS);\r
298 \r
299   }\r
300 }\r
301 \r
302 /**\r
303  * Event hander for materials menu events\r
304  * @param id ID of menu item selected\r
305  */\r
306 void processMaterialEvents(int id) {\r
307   switch (id) {\r
308     case MATERIAL_ALL_RGB:\r
309       // Do stuff\r
310       break;\r
311 \r
312     case MATERIAL_AMBIENT_RGB:\r
313       // Do stuff\r
314       break;\r
315 \r
316     case MATERIAL_DIFFUSE_RGB:\r
317       // Do stuff\r
318       break;\r
319 \r
320     case MATERIAL_SPECULAR_RGB:\r
321       // Do stuff\r
322       break;\r
323 \r
324     case MATERIAL_ALL_ADSS:\r
325       // Do stuff\r
326       break;\r
327 \r
328     case MATERIAL_RED_ADSS:\r
329       // Do stuff\r
330       break;\r
331 \r
332     case MATERIAL_GREEN_ADSS:\r
333       // Do stuff\r
334       break;\r
335 \r
336     case MATERIAL_BLUE_ADSS:\r
337       // Do stuff\r
338       break;\r
339 \r
340   }\r
341 }\r
342 \r
343 /**\r
344  * Event hander for light menu events\r
345  * @param id ID of menu item selected\r
346  */\r
347 void processLightEvents(int id) {\r
348   switch (id) {\r
349     case LIGHT_MOVE_LIGHT_1:\r
350       // Do stuff\r
351       break;\r
352 \r
353     case LIGHT_RGBALL_LIGHT_1:\r
354       // Do stuff\r
355       break;\r
356 \r
357     case LIGHT_MOVE_LIGHT_2:\r
358       // Do stuff\r
359       break;\r
360 \r
361     case LIGHT_RGBALL_LIGHT_2:\r
362       // Do stuff\r
363       break;\r
364 \r
365   }\r
366 }\r
367 \r
368 /**\r
369  * Event hander for object menu events\r
370  * @param id ID of object selected\r
371  */\r
372 void processObjectEvents(int id) {\r
373 \r
374 }\r
375 \r
376 /**\r
377  * Event hander for texture menu events\r
378  * @param id ID of texutre selected\r
379  */\r
380 void processTextureEvents(int id) {\r
381 \r
382 }\r
383 \r
384 /**\r
385  * Event hander for ground texture menu events\r
386  * @param id ID of ground texture selected\r
387  */\r
388 void processGTextureEvents(int id) {\r
389 \r
390 }\r
391 \r
392 /**\r
393  * Rounds up numbers, from http://stackoverflow.com/questions/3407012/c-rounding-up-to-the-nearest-multiple-of-a-number\r
394  * @param numToRound Number to round\r
395  * @param multiple Multiple to round up to\r
396  * @return Rounded number\r
397  */\r
398 int roundUp(int numToRound, int multiple) {\r
399   if(multiple == 0) {\r
400     return numToRound;\r
401   }\r
402 \r
403   int remainder = numToRound % multiple;\r
404   if (remainder == 0)\r
405     return numToRound;\r
406   return numToRound + multiple - remainder;\r
407 }\r
408 \r
409 /**\r
410  * Makes a submenu from an array of items, splitting the list into subsubmenus\r
411  * of only 10 items.\r
412  * @param menuEntries Array of menu items\r
413  * @param menuEntriesSize Size of menuEntries\r
414  * @param callback Callback function for this array of menu items\r
415  * @return Reference to menu created\r
416  */\r
417 int makeSubmenuFromArray( const char *menuEntries[], unsigned int menuEntriesSize, void *callback ) {\r
418   if ( menuEntriesSize == 0 ) return -1;\r
419 \r
420   int menuNumber = roundUp(menuEntriesSize, 10) / 10;\r
421   int submenuObjects[menuNumber-1];\r
422 \r
423   for( int i = 0; i < menuNumber; i++ ) {\r
424     submenuObjects[i] = glutCreateMenu(callback);\r
425     int startNum = i*11 - (i-1);\r
426     for ( int j = startNum - 1; j < (startNum+9); j++ ) {\r
427       if ( j == menuEntriesSize ) break; // Detect if we've reached the end of the array\r
428       glutAddMenuEntry( menuEntries[j], j + 1 );\r
429     }\r
430   } \r
431 \r
432   int mainMenu = glutCreateMenu(callback);\r
433   for ( int i = 0; i < menuNumber; i++ ) {\r
434     char name[10]; // buffer to hold name\r
435     int startNum = i*11 - (i-1);\r
436     int endNum = startNum + 9;\r
437     if ( i == menuNumber - 1 ) { // We're on the last one\r
438       endNum = startNum + (menuEntriesSize - startNum); // Work out final number\r
439     }\r
440     sprintf(name, "%d-%d", startNum, endNum);\r
441     glutAddSubMenu( name, submenuObjects[i] );\r
442   }\r
443 \r
444   return mainMenu;\r
445 }\r
446 \r
447 /**\r
448  * Creates menu for program\r
449  */\r
450 void makeMenu() {\r
451   // Construct material menu\r
452   int materialMenu = glutCreateMenu(processMaterialEvents);\r
453   glutAddMenuEntry("All R/G/B", MATERIAL_ALL_RGB);\r
454   glutAddMenuEntry("Ambient R/G/B", MATERIAL_AMBIENT_RGB);\r
455   glutAddMenuEntry("Diffuse R/G/B", MATERIAL_DIFFUSE_RGB);\r
456   glutAddMenuEntry("Specular R/G/B", MATERIAL_SPECULAR_RGB);\r
457   glutAddMenuEntry("All Amb/Diff/Spec/Shine", MATERIAL_ALL_ADSS);\r
458   glutAddMenuEntry("Red Amb/Diff/Spec/Shine", MATERIAL_RED_ADSS);\r
459   glutAddMenuEntry("Green Amb/Diff/Spec/Shine", MATERIAL_GREEN_ADSS);\r
460   glutAddMenuEntry("Blue Amb/Diff/Spec/Shine", MATERIAL_BLUE_ADSS);\r
461 \r
462   // Construct light menu\r
463   int lightMenu = glutCreateMenu(processLightEvents);\r
464   glutAddMenuEntry("Move Light 1", LIGHT_MOVE_LIGHT_1);\r
465   glutAddMenuEntry("R/G/B/All Light 1", LIGHT_RGBALL_LIGHT_1);\r
466   glutAddMenuEntry("Move Light 2", LIGHT_MOVE_LIGHT_2);\r
467   glutAddMenuEntry("R/G/B/All Light 2", LIGHT_RGBALL_LIGHT_2);\r
468 \r
469   // Construct object menu\r
470   int objectMenuEntriesSize = sizeof(objectMenuEntries) / sizeof(objectMenuEntries[0]);\r
471   int objectMenu = makeSubmenuFromArray( objectMenuEntries, objectMenuEntriesSize, processObjectEvents );\r
472 \r
473   // Construct texture / ground texture menus\r
474   int textureMenuEntriesSize = sizeof(textureMenuEntries) / sizeof(textureMenuEntries[0]);\r
475   int textureMenu = makeSubmenuFromArray( textureMenuEntries, textureMenuEntriesSize, processTextureEvents );\r
476   int gTextureMenu = makeSubmenuFromArray( textureMenuEntries, textureMenuEntriesSize, processGTextureEvents );\r
477 \r
478   // Construct main menu\r
479   glutCreateMenu(processMainEvents);\r
480   //glutAddMenuEntry("Rotate/Move Camera", ROTATE_MOVE_CAMERA);\r
481   //glutAddSubMenu("Add object", objectMenu);\r
482   //glutAddMenuEntry("Position/Scale", POSITION_SCALE);\r
483   //glutAddMenuEntry("Rotation/Texture Scale", ROTATION_TEXTURE_SCALE);\r
484   //glutAddSubMenu("Material", materialMenu);\r
485   //glutAddSubMenu("Texture", textureMenu);\r
486   //glutAddSubMenu("Ground texture", gTextureMenu);\r
487   //glutAddSubMenu("Lights", lightMenu);\r
488   glutAddMenuEntry("Exit", EXIT);\r
489 \r
490   // Bind to right mouse button\r
491   glutAttachMenu(GLUT_RIGHT_BUTTON);\r
492 }\r
493 \r
494 /**\r
495  * Called when window is resized\r
496  * @param w New width\r
497  * @param h New height\r
498  */\r
499 void windowReshape(int w, int h) {\r
500   glViewport(0, 0, (GLsizei) w, (GLsizei) h);\r
501   glMatrixMode(GL_PROJECTION);\r
502   glLoadIdentity();\r
503   if (w <= h) \r
504     glOrtho(near, far, near*(GLfloat)h/(GLfloat)w,\r
505              far*(GLfloat)h/(GLfloat)w, near, far);\r
506   else\r
507     glOrtho(near*(GLfloat)w/(GLfloat)h,\r
508              far*(GLfloat)w/(GLfloat)h, near, far, near, far);\r
509    glMatrixMode(GL_MODELVIEW); \r
510    glLoadIdentity();\r
511 }\r
512 \r
513 /**\r
514  * Called when mouse event occurs\r
515  * @param btn Mouse button\r
516  * @param state State of mouse button\r
517  * @param x Mouse x position\r
518  * @param y Mouse y position\r
519  */\r
520 void mouse(int button, int state, int x, int y) {\r
521   if (button == GLUT_LEFT_BUTTON) {\r
522     if (state == GLUT_DOWN) {\r
523       moving = 1;\r
524       startx = x;\r
525       starty = y;\r
526     }\r
527     if (state == GLUT_UP) {\r
528       moving = 0;\r
529     }\r
530   }\r
531   if (button == GLUT_MIDDLE_BUTTON) {\r
532     if (state == GLUT_DOWN) {\r
533       lightMoving = 1;\r
534       lightStartX = x;\r
535       lightStartY = y;\r
536     }\r
537     if (state == GLUT_UP) {\r
538       lightMoving = 0;\r
539     }\r
540   }\r
541 }\r
542 \r
543 /**\r
544  * Called when motion event occurs\r
545  * @param x Mouse x position\r
546  * @param y Mouse y position\r
547  */\r
548 void motion(int x, int y) {\r
549   if (moving) {\r
550     angle = angle + (x - startx);\r
551     angle2 = angle2 + (y - starty);\r
552     startx = x;\r
553     starty = y;\r
554     glutPostRedisplay();\r
555   }\r
556   if (lightMoving) {\r
557     lightAngle += (x - lightStartX)/40.0;\r
558     lightHeight += (lightStartY - y)/20.0;\r
559     lightStartX = x;\r
560     lightStartY = y;\r
561     glutPostRedisplay();\r
562   }\r
563 }\r
564 \r
565 /**\r
566  * Recursive function to draw a square by drawing smaller and smaller\r
567  * divisions of the square, determined by drawFloorRecurse.\r
568  * @param recurseLevel Current level of recursion, only pass 0\r
569  * @param x1 top-left x\r
570  * @param z1 top-left z\r
571  * @param x2 bottom-left x\r
572  * @param z2 bottom-left z\r
573  */\r
574 void drawSquare(int recurseLevel, float x1, float z1, float x2, float z2) {\r
575 \r
576   if ( drawFloorRecurse != recurseLevel ) {\r
577     // Calculate middle points\r
578     float xm = (x1 + x2) / 2.0;\r
579     float zm = (z1 + z2) / 2.0;\r
580 \r
581     // Increment recursion level\r
582     int rnew = recurseLevel + 1;\r
583 \r
584     // Split into four sub-quads\r
585     drawSquare(rnew, x1, z1, xm, zm);\r
586     drawSquare(rnew, x1, zm, xm, z2);\r
587     drawSquare(rnew, xm, zm, x2, z2);\r
588     drawSquare(rnew, xm, z1, x2, zm);\r
589 \r
590   } else {\r
591     // Draw square.\r
592     // **NOTE: Is the polygon facing in the right direction?\r
593     glBegin(GL_QUADS);\r
594       glVertex3f(x1, 0.0, z1);\r
595       glVertex3f(x1, 0.0, z2);\r
596       glVertex3f(x2, 0.0, z2);\r
597       glVertex3f(x2, 0.0, z1);\r
598     glEnd();\r
599   }\r
600 \r
601 }\r
602 \r
603 /**\r
604  * Draw a floor by calling the drawSquare recursion\r
605  */\r
606 void drawFloor() {\r
607   drawSquare(0, -floorSize, -floorSize, floorSize, floorSize);\r
608 }\r
609 \r
610 /**\r
611  * Draw x, z axis on floor\r
612  */\r
613 void drawLine() {\r
614     // **NOTE: fix function\r
615     glDisable(GL_TEXTURE_2D);\r
616     glEnable(GL_BLEND);\r
617     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\r
618     glColor4ub( 0.0, 0.0, 0.0, 0.5 );\r
619 \r
620     glBegin(GL_LINES);\r
621     glVertex3i( 10.0, 0.1, 10.0);\r
622     glVertex3i( -10.0, 0.1, -10.0);\r
623     glEnd();\r
624 \r
625     glDisable(GL_BLEND);\r
626     glEnable(GL_TEXTURE_2D);\r
627 }\r
628 \r
629 /**\r
630  * Display function\r
631  */\r
632 void display() {\r
633   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\r
634   glLoadIdentity();\r
635   gluLookAt(\r
636     0.0, 0.0, 10.0,  /* eye is at (x,y,z) */\r
637     0.0, 0.0,  0.0,  /* center is at (x,y,z) */\r
638     0.0, 1.0,  0.0   /* up is in postivie Y direction */\r
639     );\r
640     glEnable(GL_LIGHT0);\r
641   glLightfv(GL_LIGHT0, GL_POSITION, light0_pos);\r
642   glLightfv(GL_LIGHT0, GL_AMBIENT, ambient0);\r
643   glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0);\r
644   glLightfv(GL_LIGHT0, GL_SPECULAR, specular0);\r
645   glEnable(GL_LIGHTING);\r
646 \r
647   // **NOTE: Currently this rotation function is all that moves the camera off\r
648   //         the flat surface. Need to integrate function into gluLookAt\r
649   glRotatef(30.0, 1.0, 0.0, 0.0);\r
650 \r
651   /* Reposition the light source. */\r
652   lightPosition[0] = 12*cos(lightAngle);\r
653   lightPosition[1] = lightHeight;\r
654   lightPosition[2] = 12*sin(lightAngle);\r
655   lightPosition[3] = 0.0;\r
656 \r
657   glPushMatrix();\r
658 \r
659     /* Perform scene rotations based on user mouse input. */\r
660     glRotatef(angle, 0.0, 1.0, 0.0);\r
661     //glRotatef(angle2, 1.0, 0.0, 0.0); **NOTE: Only one degree of freedom\r
662 \r
663     glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);\r
664 \r
665     drawFloor();\r
666 \r
667     drawLine();\r
668     \r
669     // Draw teapot for a test object\r
670     glPushMatrix();\r
671       glTranslatef(0.0, 1.0, 0.0); // **NOTE: Teapot does not rest on surface\r
672       glutWireTeapot(1);\r
673     glPopMatrix();\r
674 \r
675     // Draw a white ball over the light source\r
676     glPushMatrix();\r
677       glDisable(GL_LIGHTING);\r
678       glColor3f(1.0, 1.0, 1.0);\r
679       glTranslatef(lightPosition[0], lightPosition[1], lightPosition[2]);\r
680       glutSolidSphere(1.0, 50, 50);\r
681       glEnable(GL_LIGHTING);\r
682     glPopMatrix();\r
683 \r
684   glPopMatrix();\r
685 \r
686   glutSwapBuffers();\r
687 }\r
688 \r
689 /**\r
690  * init function; sets initial OpenGL state\r
691  */\r
692 void init() {\r
693   glMatrixMode(GL_PROJECTION);\r
694   glLoadIdentity();\r
695 \r
696   gluPerspective(\r
697     60.0,  /* field of view in degree */\r
698      1.0,  /* aspect ratio */\r
699     near,  /* Z near */\r
700      far   /* Z far */\r
701     );    \r
702 \r
703   glEnable(GL_LIGHT0);\r
704   glLightfv(GL_LIGHT0, GL_POSITION, light0_pos);\r
705   glLightfv(GL_LIGHT0, GL_AMBIENT, ambient0);\r
706   glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0);\r
707   glLightfv(GL_LIGHT0, GL_SPECULAR, specular0);\r
708   glEnable(GL_LIGHTING);\r
709 \r
710   glMatrixMode(GL_MODELVIEW);\r
711   glLoadIdentity();\r
712 }\r
713 \r
714 /**\r
715  * Main function\r
716  * @param argc Number of arguments\r
717  * @param argv Array of arguments\r
718  * @return Program exit code\r
719  */\r
720 int main(int argc, char **argv) {\r
721   if(argc>1)\r
722     strcpy(dataDir, argv[1]);\r
723   else if(opendir(dirDefault1))\r
724     strcpy(dataDir, dirDefault1);\r
725   else if(opendir(dirDefault2))\r
726     strcpy(dataDir, dirDefault2);\r
727   else fileErr(dirDefault1);\r
728 \r
729   for(int i=0; i<NMESH; i++) meshes[i]=NULL;\r
730   for(int i=0; i<NTEXTURE; i++) textures[i]=NULL;\r
731 \r
732   glutInit(&argc, argv);\r
733 \r
734   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);\r
735 \r
736   glutInitWindowSize(500, 500);\r
737   glutCreateWindow("Scene Editor");\r
738 \r
739   glShadeModel(GL_SMOOTH); // Enables Smooth Shading\r
740   glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Black Background\r
741   glClearDepth(1.0f); // Depth Buffer Setup\r
742   glEnable(GL_DEPTH_TEST); // Enables Depth Testing\r
743   glDepthFunc(GL_LEQUAL);  // the type\r
744   glEnable(GL_CULL_FACE);\r
745   glEnable(GL_TEXTURE_2D);\r
746   glLineWidth(1.0);\r
747 \r
748   glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);\r
749 \r
750   glutReshapeFunc(windowReshape);\r
751   glutDisplayFunc(display);\r
752   glutMouseFunc(mouse);\r
753   glutMotionFunc(motion);\r
754 \r
755   makeMenu();\r
756 \r
757   init();\r
758 \r
759   glutMainLoop();\r
760 }\r

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