2 * CITS2231 Graphics Scene Editor
\r
3 * @author Ashley Tyndall (20915779)
\r
12 #include <GL/glut.h>
\r
16 // Type definitions for vertex-coordinates, normals, texture-coordinates,
\r
17 // and triangles (via the indices of 3 vertices).
\r
18 typedef GLfloat vertex[3];
\r
19 typedef GLfloat normal[3];
\r
20 typedef GLfloat texCoord[2];
\r
21 typedef GLint vertexIndex;
\r
22 typedef vertexIndex triangle[3];
\r
24 // A type for a mesh
\r
26 int nVertices; // The number of vertices in the mesh
\r
27 vertex* vertices; // Array with coordinates of vertices
\r
28 normal* normals; // Array with normals of vertices
\r
29 texCoord* texCoords; // Array with texture-coordinates of vertices
\r
30 int nTriangles; // The number of triangles in the mesh
\r
31 triangle* triangles; // Array of trangles via 3 indices into "vertices"
\r
34 #define NMESH 54 // The number of meshes (in the models-textures dir)
\r
35 mesh* meshes[NMESH]; // An array of pointers to the meshes - see getMesh
\r
37 // A type for a 2D texture, with height and width in pixels
\r
41 GLubyte *rgbData; // Array of bytes with the colour data for the texture
\r
44 #define NTEXTURE 30 // The number of textures (in the models-textures dir)
\r
45 texture* textures[NTEXTURE]; // An array of texture pointers - see getTexture
\r
48 // You'll need to add scale, rotation, material, mesh number, etc.,
\r
49 // to this structure
\r
58 ROTATION_TEXTURE_SCALE,
\r
63 MATERIAL_AMBIENT_RGB,
\r
64 MATERIAL_DIFFUSE_RGB,
\r
65 MATERIAL_SPECULAR_RGB,
\r
68 MATERIAL_GREEN_ADSS,
\r
73 LIGHT_RGBALL_LIGHT_1,
\r
75 LIGHT_RGBALL_LIGHT_2
\r
79 const char *textureMenuEntries[NTEXTURE] = {
\r
80 "1 Plain", "2 Rust", "3 Concrete", "4 Carpet", "5 Beach Sand",
\r
81 "6 Rocky", "7 Brick", "8 Water", "9 Paper", "10 Marble",
\r
82 "11 Wood", "12 Scales", "13 Fur", "14 Denim", "15 Hessian",
\r
83 "16 Orange Peel", "17 Ice Crystals", "18 Grass", "19 Corrugated Iron", "20 Styrofoam",
\r
84 "21 Bubble Wrap", "22 Leather", "23 Camouflage", "24 Asphalt", "25 Scratched Ice",
\r
85 "26 Rattan", "27 Snow", "28 Dry Mud", "29 Old Concrete", "30 Leopard Skin"
\r
88 const char *objectMenuEntries[NMESH] = {
\r
89 "1 Thin Dinosaur","2 Big Dog","3 Saddle Dinosaur", "4 Dragon", "5 Cleopatra",
\r
90 "6 Bone I", "7 Bone II", "8 Rabbit", "9 Long Dragon", "10 Buddha",
\r
91 "11 Sitting Rabbit", "12 Frog", "13 Cow", "14 Monster", "15 Sea Horse",
\r
92 "16 Head", "17 Pelican", "18 Horse", "19 Kneeling Angel", "20 Porsche I",
\r
93 "21 Truck", "22 Statue of Liberty", "23 Sitting Angel", "24 Metal Part", "25 Car",
\r
94 "26 Apatosaurus", "27 Airliner", "28 Motorbike", "29 Dolphin", "30 Spaceman",
\r
95 "31 Winnie the Pooh", "32 Shark", "33 Crocodile", "34 Toddler", "35 Fat Dinosaur",
\r
96 "36 Chihuahua", "37 Sabre-toothed Tiger", "38 Lioness", "39 Fish", "40 Horse (head down)",
\r
97 "41 Horse (head up)", "42 Skull", "43 Fighter Jet I", "44 Toad", "45 Convertible",
\r
98 "46 Porsche II", "47 Hare", "48 Vintage Car", "49 Fighter Jet II", "50 Winged Monkey",
\r
99 "51 Chef", "52 Parasaurolophus", "53 Rooster", "54 T-rex"
\r
102 #define MAXOBJECTS 256
\r
103 SceneObject sceneObjs[MAXOBJECTS]; // An array with details of the objects in a scene
\r
104 int nObjects=0; // How many objects there are in the scene currently.
\r
106 // Directories containing models
\r
107 char *dirDefault1 = "models-textures";
\r
108 char *dirDefault2 = "/cslinux/examples/CITS2231/project-files/models-textures";
\r
110 char dataDir[200]; // Stores the directory name for the meshes and textures.
\r
113 * Prints out error message when file cannot be read
\r
114 * @param fileName Name of file that could not be read
\r
116 void fileErr(char* fileName) {
\r
117 printf("Error reading file: %s\n", fileName);
\r
118 printf("If not in the CSSE labs, you will need to include the directory containing\n");
\r
119 printf("the models on the command line, or put it in the same folder as the exectutable.");
\r
120 exit(EXIT_FAILURE);
\r
124 * Reads .bmp texture files and converts them to a texture object
\r
125 * @param fileName .bmp texture file
\r
126 * @return texture object
\r
128 texture* loadTexture(char *fileName) {
\r
129 texture* t = malloc(sizeof (texture));
\r
132 t->rgbData = LoadDIBitmap(fileName, &info);
\r
133 t->height=info->bmiHeader.biHeight;
\r
134 t->width=info->bmiHeader.biWidth;
\r
140 * Reads .x files and converts them to a mesh object
\r
141 * @param fileName .x mesh file
\r
142 * @return mesh object
\r
144 mesh* loadMesh(char* fileName) {
\r
145 mesh* m = malloc(sizeof (mesh));
\r
146 FILE* fp = fopen(fileName, "r");
\r
147 char line[256] = "";
\r
148 int lineBuffSize = 256;
\r
150 if(fp == NULL) fileErr(fileName);
\r
152 while(strcmp(line,"Mesh {\r\n") != 0 && strcmp(line,"Mesh {\n") != 0 )
\r
153 fgets(line, lineBuffSize, fp);
\r
155 fscanf(fp, "%d;\n", &(m->nVertices));
\r
156 m->vertices = malloc(m->nVertices * sizeof(vertex));
\r
157 for(int i=0; i < m->nVertices; i++)
\r
158 fscanf(fp, "%f; %f; %f;%*[,;]\n", &(m->vertices[i][0]), &(m->vertices[i][1]), &(m->vertices[i][2]) );
\r
160 fscanf(fp, "%d;\n", &(m->nTriangles));
\r
161 m->triangles = malloc(m->nTriangles * sizeof(triangle));
\r
162 for(int i=0; i < m->nTriangles; i++)
\r
163 fscanf(fp, "%*d; %d, %d, %d;%*[;,]", m->triangles[i], m->triangles[i]+1, m->triangles[i]+2);
\r
165 while(strcmp(line," MeshNormals {\r\n") != 0 && strcmp(line," MeshNormals {\n") != 0)
\r
166 fgets(line, lineBuffSize, fp);
\r
168 fgets(line, lineBuffSize, fp);
\r
169 m->normals = malloc(m->nVertices * sizeof(normal));
\r
170 for(int i=0; i < m->nVertices; i++)
\r
171 fscanf(fp, "%f; %f; %f;%*[;,]\n",
\r
172 &(m->normals[i][0]), &(m->normals[i][1]), &(m->normals[i][2]));
\r
174 while(strcmp(line,"MeshTextureCoords {\r\n") != 0 && strcmp(line,"MeshTextureCoords {\n") != 0)
\r
175 fgets(line, lineBuffSize, fp);
\r
177 fgets(line, lineBuffSize, fp);
\r
178 m->texCoords = malloc(m->nVertices * sizeof(texCoord));
\r
179 for(int i=0; i < m->nVertices; i++)
\r
180 fscanf(fp, "%f;%f;%*[,;]\n", &(m->texCoords[i][0]), &(m->texCoords[i][1]) );
\r
186 // [You may want to add to this function.]
\r
188 * Loads mesh[i] if it isn't already loaded.
\r
189 * You must call getMesh(i) at least once before using mesh[i].
\r
193 void getMesh(int i) { // getMesh(i) loads mesh[i] if it isn't already loaded.
\r
194 char fileName[220];
\r
195 if(i>=NMESH || i<0) {
\r
196 printf("Error in getMesh - wrong model number");
\r
199 if(meshes[i] != NULL)
\r
201 sprintf(fileName, "%s/model%d.x", dataDir, i+1);
\r
202 meshes[i] = loadMesh(fileName);
\r
206 * Loads texture i if it isn't already loaded
\r
208 * After calling getTexture(i), you can make texture i the current texture using
\r
209 * glBindTexture(GL_TEXTURE_2D, i);
\r
210 * Use i=0 to return to the default plain texture.
\r
212 * You can then scale the texture via:
\r
213 * glMatrixMode(GL_TEXTURE);
\r
214 * See the textbook, section 8.8.3.
\r
216 * You must call getTexture(i) at least once before using texture i.
\r
217 * @param i Texture ID
\r
219 void getTexture(int i) {
\r
220 char fileName[220];
\r
221 if(i<1 || i>NTEXTURE) {
\r
222 printf("Error in getTexture - wrong texture number");
\r
225 if(textures[i-1] != NULL)
\r
227 sprintf(fileName, "%s/texture%d.bmp", dataDir, i);
\r
229 textures[i-1] = loadTexture(fileName);
\r
231 glBindTexture(GL_TEXTURE_2D, i);
\r
233 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textures[i-1]->width, textures[i-1]->height,
\r
234 0, GL_RGB, GL_UNSIGNED_BYTE, textures[i-1]->rgbData);
\r
235 gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, textures[i-1]->width, textures[i-1]->height, GL_RGB,
\r
236 GL_UNSIGNED_BYTE, textures[i-1]->rgbData);
\r
237 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
\r
238 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
\r
239 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
\r
240 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
\r
242 glBindTexture(GL_TEXTURE_2D, 0); // Back to default texture
\r
246 * Event hander for main menu events
\r
247 * @param id ID of menu item selected
\r
249 void processMainEvents(int id) {
\r
251 case ROTATE_MOVE_CAMERA:
\r
255 case POSITION_SCALE:
\r
259 case ROTATION_TEXTURE_SCALE:
\r
264 exit(EXIT_SUCCESS);
\r
270 * Event hander for materials menu events
\r
271 * @param id ID of menu item selected
\r
273 void processMaterialEvents(int id) {
\r
275 case MATERIAL_ALL_RGB:
\r
279 case MATERIAL_AMBIENT_RGB:
\r
283 case MATERIAL_DIFFUSE_RGB:
\r
287 case MATERIAL_SPECULAR_RGB:
\r
291 case MATERIAL_ALL_ADSS:
\r
295 case MATERIAL_RED_ADSS:
\r
299 case MATERIAL_GREEN_ADSS:
\r
303 case MATERIAL_BLUE_ADSS:
\r
311 * Event hander for light menu events
\r
312 * @param id ID of menu item selected
\r
314 void processLightEvents(int id) {
\r
316 case LIGHT_MOVE_LIGHT_1:
\r
320 case LIGHT_RGBALL_LIGHT_1:
\r
324 case LIGHT_MOVE_LIGHT_2:
\r
328 case LIGHT_RGBALL_LIGHT_2:
\r
336 * Event hander for object menu events
\r
337 * @param id ID of object selected
\r
339 void processObjectEvents(int id) {
\r
344 * Event hander for texture menu events
\r
345 * @param id ID of texutre selected
\r
347 void processTextureEvents(int id) {
\r
352 * Event hander for ground texture menu events
\r
353 * @param id ID of ground texture selected
\r
355 void processGTextureEvents(int id) {
\r
360 * Rounds up numbers, from http://stackoverflow.com/questions/3407012/c-rounding-up-to-the-nearest-multiple-of-a-number
\r
361 * @param numToRound Number to round
\r
362 * @param multiple Multiple to round up to
\r
363 * @return Rounded number
\r
365 int roundUp(int numToRound, int multiple) {
\r
366 if(multiple == 0) {
\r
370 int remainder = numToRound % multiple;
\r
371 if (remainder == 0)
\r
373 return numToRound + multiple - remainder;
\r
377 * Makes a submenu from an array of items, splitting the list into subsubmenus
\r
378 * of only 10 items.
\r
379 * @param menuEntries Array of menu items
\r
380 * @param menuEntriesSize Size of menuEntries
\r
381 * @param callback Callback function for this array of menu items
\r
382 * @return Reference to menu created
\r
384 int makeSubmenuFromArray( const char *menuEntries[], unsigned int menuEntriesSize, void *callback ) {
\r
385 if ( menuEntriesSize == 0 ) return -1;
\r
387 int menuNumber = roundUp(menuEntriesSize, 10) / 10;
\r
388 int submenuObjects[menuNumber-1];
\r
390 for( int i = 0; i < menuNumber; i++ ) {
\r
391 submenuObjects[i] = glutCreateMenu(callback);
\r
392 int startNum = i*11 - (i-1);
\r
393 for ( int j = startNum - 1; j < (startNum+9); j++ ) {
\r
394 if ( j == menuEntriesSize ) break; // Detect if we've reached the end of the array
\r
395 glutAddMenuEntry( menuEntries[j], j + 1 );
\r
399 int mainMenu = glutCreateMenu(callback);
\r
400 for ( int i = 0; i < menuNumber; i++ ) {
\r
401 char name[10]; // buffer to hold name
\r
402 int startNum = i*11 - (i-1);
\r
403 int endNum = startNum + 9;
\r
404 if ( i == menuNumber - 1 ) { // We're on the last one
\r
405 endNum = startNum + (menuEntriesSize - startNum); // Work out final number
\r
407 sprintf(name, "%d-%d", startNum, endNum);
\r
408 glutAddSubMenu( name, submenuObjects[i] );
\r
415 * Creates menu for program
\r
418 // Construct material menu
\r
419 int materialMenu = glutCreateMenu(processMaterialEvents);
\r
420 glutAddMenuEntry("All R/G/B", MATERIAL_ALL_RGB);
\r
421 glutAddMenuEntry("Ambient R/G/B", MATERIAL_AMBIENT_RGB);
\r
422 glutAddMenuEntry("Diffuse R/G/B", MATERIAL_DIFFUSE_RGB);
\r
423 glutAddMenuEntry("Specular R/G/B", MATERIAL_SPECULAR_RGB);
\r
424 glutAddMenuEntry("All Amb/Diff/Spec/Shine", MATERIAL_ALL_ADSS);
\r
425 glutAddMenuEntry("Red Amb/Diff/Spec/Shine", MATERIAL_RED_ADSS);
\r
426 glutAddMenuEntry("Green Amb/Diff/Spec/Shine", MATERIAL_GREEN_ADSS);
\r
427 glutAddMenuEntry("Blue Amb/Diff/Spec/Shine", MATERIAL_BLUE_ADSS);
\r
429 // Construct light menu
\r
430 int lightMenu = glutCreateMenu(processLightEvents);
\r
431 glutAddMenuEntry("Move Light 1", LIGHT_MOVE_LIGHT_1);
\r
432 glutAddMenuEntry("R/G/B/All Light 1", LIGHT_RGBALL_LIGHT_1);
\r
433 glutAddMenuEntry("Move Light 2", LIGHT_MOVE_LIGHT_2);
\r
434 glutAddMenuEntry("R/G/B/All Light 2", LIGHT_RGBALL_LIGHT_2);
\r
436 // Construct object menu
\r
437 int objectMenuEntriesSize = sizeof(objectMenuEntries) / sizeof(objectMenuEntries[0]);
\r
438 int objectMenu = makeSubmenuFromArray( objectMenuEntries, objectMenuEntriesSize, processObjectEvents );
\r
440 // Construct texture / ground texture menus
\r
441 int textureMenuEntriesSize = sizeof(textureMenuEntries) / sizeof(textureMenuEntries[0]);
\r
442 int textureMenu = makeSubmenuFromArray( textureMenuEntries, textureMenuEntriesSize, processTextureEvents );
\r
443 int gTextureMenu = makeSubmenuFromArray( textureMenuEntries, textureMenuEntriesSize, processGTextureEvents );
\r
445 // Construct main menu
\r
446 glutCreateMenu(processMainEvents);
\r
447 //glutAddMenuEntry("Rotate/Move Camera", ROTATE_MOVE_CAMERA);
\r
448 //glutAddSubMenu("Add object", objectMenu);
\r
449 //glutAddMenuEntry("Position/Scale", POSITION_SCALE);
\r
450 //glutAddMenuEntry("Rotation/Texture Scale", ROTATION_TEXTURE_SCALE);
\r
451 //glutAddSubMenu("Material", materialMenu);
\r
452 //glutAddSubMenu("Texture", textureMenu);
\r
453 //glutAddSubMenu("Ground texture", gTextureMenu);
\r
454 //glutAddSubMenu("Lights", lightMenu);
\r
455 glutAddMenuEntry("Exit", EXIT);
\r
457 // Bind to right mouse button
\r
458 glutAttachMenu(GLUT_RIGHT_BUTTON);
\r
462 * Called when window is resized
\r
463 * @param w New width
\r
464 * @param h New height
\r
466 void windowReshape(int w, int h) {
\r
467 GLdouble near = -10.0;
\r
468 GLdouble far = 10.0;
\r
470 glViewport(0, 0, (GLsizei) w, (GLsizei) h);
\r
471 glMatrixMode(GL_PROJECTION);
\r
474 glOrtho(near, far, near*(GLfloat)h/(GLfloat)w,
\r
475 far*(GLfloat)h/(GLfloat)w, near, far);
\r
477 glOrtho(near*(GLfloat)w/(GLfloat)h,
\r
478 far*(GLfloat)w/(GLfloat)h, near, far, near, far);
\r
479 glMatrixMode(GL_MODELVIEW);
\r
484 * Called when mouse event occurs
\r
485 * @param btn Mouse button
\r
486 * @param state State of mouse button
\r
487 * @param x Mouse x position
\r
488 * @param y Mouse y position
\r
490 void mouse(int btn, int state, int x, int y) {
\r
494 static GLfloat floorVertices[4][3] = {
\r
495 { -20.0, 0.0, 20.0 },
\r
496 { 20.0, 0.0, 20.0 },
\r
497 { 20.0, 0.0, -20.0 },
\r
498 { -20.0, 0.0, -20.0 },
\r
501 /* Draw a floor (possibly textured). */
\r
505 glDisable(GL_LIGHTING);
\r
507 //if (useTexture) {
\r
508 // glEnable(GL_TEXTURE_2D);
\r
512 glTexCoord2f(0.0, 0.0);
\r
513 glVertex3fv(floorVertices[0]);
\r
514 glTexCoord2f(0.0, 16.0);
\r
515 glVertex3fv(floorVertices[1]);
\r
516 glTexCoord2f(16.0, 16.0);
\r
517 glVertex3fv(floorVertices[2]);
\r
518 glTexCoord2f(16.0, 0.0);
\r
519 glVertex3fv(floorVertices[3]);
\r
522 /*if (useTexture) {
\r
523 glDisable(GL_TEXTURE_2D);
\r
526 glEnable(GL_LIGHTING);
\r
530 static GLfloat lightColor[] = {0.8, 1.0, 0.8, 1.0}; /* green-tinted */
\r
531 static GLfloat lightPosition[4];
\r
532 static float lightAngle = 0.0, lightHeight = 20;
\r
539 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
\r
542 /*glTranslatef( 0.0f, 0.0f, 0.0f);
\r
544 glVertex3f( 0.0f, 1.0f, -1.0f);
\r
545 glVertex3f( 0.0f, 1.0f, 1.0f);
\r
546 glVertex3f( 0.0f, -1.0f, 1.0f);
\r
547 glVertex3f( 0.0f, -1.0f, -1.0f);
\r
551 //glTranslatef( 0.0f, 0.0f, -5.0f); // Move into the Screen 10.0
\r
552 //glutSolidTeapot(1);
\r
554 /* glMatrixMode(GL_MODELVIEW);
\r
556 gluLookAt(0.7f, 0.4f, 0.9f, -2.0f, -1.0f, -7.0f, 1.0f, 10.0f, 1.0f);
\r
559 glMatrixMode(GL_PROJECTION);
\r
560 glLoadIdentity();*/
\r
563 /* Reposition the light source. */
\r
564 lightPosition[0] = 12*cos(lightAngle);
\r
565 lightPosition[1] = lightHeight;
\r
566 lightPosition[2] = 12*sin(lightAngle);
\r
567 //if (directionalLight) {
\r
568 lightPosition[3] = 0.0;
\r
570 // lightPosition[3] = 1.0;
\r
575 /* Tell GL new light source position. */
\r
576 glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
\r
578 /* Draw "bottom" of floor in blue. */
\r
579 glFrontFace(GL_CW); /* Switch face orientation. */
\r
580 glColor4f(0.1, 0.1, 0.7, 1.0);
\r
582 glFrontFace(GL_CCW);
\r
584 /* Draw "top" of floor. Use blending to blend in reflection. */
\r
585 glEnable(GL_BLEND);
\r
586 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
\r
587 glColor4f(0.7, 0.0, 0.0, 0.3);
\r
588 glColor4f(1.0, 1.0, 1.0, 0.3);
\r
590 glDisable(GL_BLEND);
\r
593 glDisable(GL_LIGHTING);
\r
595 /* Draw a yellow ball at the light source. */
\r
596 glTranslatef(lightPosition[0], lightPosition[1], lightPosition[2]);
\r
597 glutSolidSphere(1.0, 5, 5);
\r
599 glEnable(GL_LIGHTING);
\r
607 * init function, sets OpenGL's starting state
\r
610 glMatrixMode(GL_PROJECTION);
\r
612 // gluPerspective( 60, 1, 0.1, 1000.0);
\r
613 gluPerspective( /* field of view in degree */ 40.0,
\r
614 /* aspect ratio */ 1.0,
\r
615 /* Z near */ 20.0, /* Z far */ 100.0);
\r
616 glMatrixMode(GL_MODELVIEW);
\r
617 gluLookAt(0.0, 8.0, 60.0, /* eye is at (0,8,60) */
\r
618 0.0, 8.0, 0.0, /* center is at (0,8,0) */
\r
619 0.0, 1.0, 0.); /* up is in postivie Y direction */
\r
621 glMatrixMode(GL_MODELVIEW);
\r
627 * @param argc Number of arguments
\r
628 * @param argv Array of arguments
\r
629 * @return Program exit code
\r
631 int main(int argc, char **argv) {
\r
634 strcpy(dataDir, argv[1]);
\r
635 else if(opendir(dirDefault1))
\r
636 strcpy(dataDir, dirDefault1);
\r
637 else if(opendir(dirDefault2))
\r
638 strcpy(dataDir, dirDefault2);
\r
639 else fileErr(dirDefault1);
\r
641 for(int i=0; i<NMESH; i++) meshes[i]=NULL;
\r
642 for(int i=0; i<NTEXTURE; i++) textures[i]=NULL;
\r
644 glutInit(&argc, argv);
\r
646 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
\r
647 glutInitWindowSize(500, 500);
\r
648 glutCreateWindow("Scene Editor");
\r
650 glShadeModel(GL_SMOOTH); // Enables Smooth Shading
\r
651 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Black Background
\r
652 glClearDepth(1.0f); // Depth Buffer Setup
\r
653 glEnable(GL_DEPTH_TEST); // Enables Depth Testing
\r
654 glDepthFunc(GL_LEQUAL); // the type
\r
656 // glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
\r
658 glutReshapeFunc(windowReshape);
\r
659 glutDisplayFunc(display);
\r
660 glutMouseFunc(mouse);
\r
666 glMatrixMode(GL_PROJECTION);
\r
667 gluPerspective( /* field of view in degree */ 40.0,
\r
668 /* aspect ratio */ 1.0,
\r
669 /* Z near */ 20.0, /* Z far */ 100.0);
\r
670 glMatrixMode(GL_MODELVIEW);
\r
671 gluLookAt(0.0, 8.0, 60.0, /* eye is at (0,8,60) */
\r
672 0.0, 8.0, 0.0, /* center is at (0,8,0) */
\r
673 0.0, 1.0, 0.); /* up is in postivie Y direction */
\r
675 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
\r
676 glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor);
\r
677 glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1);
\r
678 glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05);
\r
679 glEnable(GL_LIGHT0);
\r
680 glEnable(GL_LIGHTING);
\r