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

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