Let us take a look at the cube.c demo program. Following is the full program, with line numbers. We will identify the parts of the progam by these line numbers.
1 // ----------------------
2 // OpenGL cube demo.
3 //
4 // Written by Chris Halsall (chalsall@chalsall.com) for the
5 // O'Reilly Network on Linux.com (oreilly.linux.com).
6 // May 2000.
7 //
8 // Released into the Public Domain; do with it as you wish.
9 // We would like to hear about interesting uses.
10 //
11 // Coded to the groovy tunes of Yello: Pocket Universe.
12
13 #define PROGRAM_TITLE "O'Reilly Net: OpenGL Demo -- C.Halsall"
14
15 #include <stdio.h> // Always a good idea.
16 #include <time.h> // For our FPS stats.
17 #include <GL/gl.h> // OpenGL itself.
18 #include <GL/glu.h> // GLU support library.
19 #include <GL/glut.h> // GLUT support library.
20
21 // Some global variables.
22
23 // Window and texture IDs, window width and height.
24 int Texture_ID;
25 int Window_ID;
26 int Window_Width = 300;
27 int Window_Height = 300;
28
29 // Our display mode settings.
30 int Light_On = 0;
31 int Blend_On = 0;
32 int Texture_On = 0;
33 int Filtering_On = 0;
34 int Alpha_Add = 0;
35
36 int Curr_TexMode = 0;
37 char *TexModesStr[] = {"GL_DECAL","GL_MODULATE","GL_BLEND","GL_REPLACE"};
38 GLint TexModes[] = {GL_DECAL,GL_MODULATE,GL_BLEND,GL_REPLACE};
39
40 // Object and scene global variables.
41
42 // Cube position and rotation speed variables.
43 float X_Rot = 0.9f;
44 float Y_Rot = 0.0f;
45 float X_Speed = 0.0f;
46 float Y_Speed = 0.5f;
47 float Z_Off =-5.0f;
48
49 // Settings for our light. Try playing with these (or add more lights).
50 float Light_Ambient[]= { 0.1f, 0.1f, 0.1f, 1.0f };
51 float Light_Diffuse[]= { 1.2f, 1.2f, 1.2f, 1.0f };
52 float Light_Position[]= { 2.0f, 2.0f, 0.0f, 1.0f };
53
54
55 // ------
56 // Frames per second (FPS) statistic variables and routine.
57
58 #define FRAME_RATE_SAMPLES 50
59 int FrameCount=0;
60 float FrameRate=0;
61
62 static void ourDoFPS(
63 )
64 {
65 static clock_t last=0;
66 clock_t now;
67 float delta;
68
69 if (++FrameCount >= FRAME_RATE_SAMPLES) {
70 now = clock();
71 delta= (now - last) / (float) CLOCKS_PER_SEC;
72 last = now;
73
74 FrameRate = FRAME_RATE_SAMPLES / delta;
75 FrameCount = 0;
76 }
77 }
78
79
80 // ------
81 // String rendering routine; leverages on GLUT routine.
82
83 static void ourPrintString(
84 void *font,
85 char *str
86 )
87 {
88 int i,l=strlen(str);
89
90 for(i=0;i<l;i++)
91 glutBitmapCharacter(font,*str++);
92 }
93
94
95 // ------
96 // Routine which actually does the drawing
97
98 void cbRenderScene(
99 void
100 )
101 {
102 char buf[80]; // For our strings.
103
104 // Enables, disables or otherwise adjusts as
105 // appropriate for our current settings.
106
107 if (Texture_On)
108 glEnable(GL_TEXTURE_2D);
109 else
110 glDisable(GL_TEXTURE_2D);
111
112 if (Light_On)
113 glEnable(GL_LIGHTING);
114 else
115 glDisable(GL_LIGHTING);
116
117 if (Alpha_Add)
118 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
119 else
120 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
121
122 // If we're blending, we don't want z-buffering.
123 if (Blend_On)
124 glDisable(GL_DEPTH_TEST);
125 else
126 glEnable(GL_DEPTH_TEST);
127
128 if (Filtering_On) {
129 glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,
130 GL_LINEAR_MIPMAP_LINEAR);
131 glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
132 } else {
133 glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,
134 GL_NEAREST_MIPMAP_NEAREST);
135 glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
136 }
137
138
139 // Need to manipulate the ModelView matrix to move our model around.
140 glMatrixMode(GL_MODELVIEW);
141
142 // Reset to 0,0,0; no rotation, no scaling.
143 glLoadIdentity();
144
145 // Move the object back from the screen.
146 glTranslatef(0.0f,0.0f,Z_Off);
147
148 // Rotate the calculated amount.
149 glRotatef(X_Rot,1.0f,0.0f,0.0f);
150 glRotatef(Y_Rot,0.0f,1.0f,0.0f);
151
152
153 // Clear the color and depth buffers.
154 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
155
156
157 // OK, let's start drawing our planer quads.
158 glBegin(GL_QUADS);
159
160
161 // Bottom Face. Red, 75% opaque, magnified texture
162
163 glNormal3f( 0.0f, -1.0f, 0.0f); // Needed for lighting
164 glColor4f(0.9,0.2,0.2,.75); // Basic polygon color
165
166 glTexCoord2f(0.800f, 0.800f); glVertex3f(-1.0f, -1.0f, -1.0f);
167 glTexCoord2f(0.200f, 0.800f); glVertex3f( 1.0f, -1.0f, -1.0f);
168 glTexCoord2f(0.200f, 0.200f); glVertex3f( 1.0f, -1.0f, 1.0f);
169 glTexCoord2f(0.800f, 0.200f); glVertex3f(-1.0f, -1.0f, 1.0f);
170
171
172 // Top face; offset. White, 50% opaque.
173
174 glNormal3f( 0.0f, 1.0f, 0.0f); glColor4f(0.5,0.5,0.5,.5);
175
176 glTexCoord2f(0.005f, 1.995f); glVertex3f(-1.0f, 1.3f, -1.0f);
177 glTexCoord2f(0.005f, 0.005f); glVertex3f(-1.0f, 1.3f, 1.0f);
178 glTexCoord2f(1.995f, 0.005f); glVertex3f( 1.0f, 1.3f, 1.0f);
179 glTexCoord2f(1.995f, 1.995f); glVertex3f( 1.0f, 1.3f, -1.0f);
180
181
182 // Far face. Green, 50% opaque, non-uniform texture cooridinates.
183
184 glNormal3f( 0.0f, 0.0f,-1.0f); glColor4f(0.2,0.9,0.2,.5);
185
186 glTexCoord2f(0.995f, 0.005f); glVertex3f(-1.0f, -1.0f, -1.3f);
187 glTexCoord2f(2.995f, 2.995f); glVertex3f(-1.0f, 1.0f, -1.3f);
188 glTexCoord2f(0.005f, 0.995f); glVertex3f( 1.0f, 1.0f, -1.3f);
189 glTexCoord2f(0.005f, 0.005f); glVertex3f( 1.0f, -1.0f, -1.3f);
190
191
192 // Right face. Blue; 25% opaque
193
194 glNormal3f( 1.0f, 0.0f, 0.0f); glColor4f(0.2,0.2,0.9,.25);
195
196 glTexCoord2f(0.995f, 0.005f); glVertex3f( 1.0f, -1.0f, -1.0f);
197 glTexCoord2f(0.995f, 0.995f); glVertex3f( 1.0f, 1.0f, -1.0f);
198 glTexCoord2f(0.005f, 0.995f); glVertex3f( 1.0f, 1.0f, 1.0f);
199 glTexCoord2f(0.005f, 0.005f); glVertex3f( 1.0f, -1.0f, 1.0f);
200
201
202 // Front face; offset. Multi-colored, 50% opaque.
203
204 glNormal3f( 0.0f, 0.0f, 1.0f);
205
206 glColor4f( 0.9f, 0.2f, 0.2f, 0.5f);
207 glTexCoord2f( 0.005f, 0.005f); glVertex3f(-1.0f, -1.0f, 1.3f);
208 glColor4f( 0.2f, 0.9f, 0.2f, 0.5f);
209 glTexCoord2f( 0.995f, 0.005f); glVertex3f( 1.0f, -1.0f, 1.3f);
210 glColor4f( 0.2f, 0.2f, 0.9f, 0.5f);
211 glTexCoord2f( 0.995f, 0.995f); glVertex3f( 1.0f, 1.0f, 1.3f);
212 glColor4f( 0.1f, 0.1f, 0.1f, 0.5f);
213 glTexCoord2f( 0.005f, 0.995f); glVertex3f(-1.0f, 1.0f, 1.3f);
214
215
216 // Left Face; offset. Yellow, varying levels of opaque.
217
218 glNormal3f(-1.0f, 0.0f, 0.0f);
219
220 glColor4f(0.9,0.9,0.2,0.0);
221 glTexCoord2f(0.005f, 0.005f); glVertex3f(-1.3f, -1.0f, -1.0f);
222 glColor4f(0.9,0.9,0.2,0.66);
223 glTexCoord2f(0.995f, 0.005f); glVertex3f(-1.3f, -1.0f, 1.0f);
224 glColor4f(0.9,0.9,0.2,1.0);
225 glTexCoord2f(0.995f, 0.995f); glVertex3f(-1.3f, 1.0f, 1.0f);
226 glColor4f(0.9,0.9,0.2,0.33);
227 glTexCoord2f(0.005f, 0.995f); glVertex3f(-1.3f, 1.0f, -1.0f);
228
229
230 // All polygons have been drawn.
231 glEnd();
232
233 // Move back to the origin (for the text, below).
234 glLoadIdentity();
235
236 // We need to change the projection matrix for the text rendering.
237 glMatrixMode(GL_PROJECTION);
238
239 // But we like our current view too; so we save it here.
240 glPushMatrix();
241
242 // Now we set up a new projection for the text.
243 glLoadIdentity();
244 glOrtho(0,Window_Width,0,Window_Height,-1.0,1.0);
245
246 // Lit or textured text looks awful.
247 glDisable(GL_TEXTURE_2D);
248 glDisable(GL_LIGHTING);
249
250 // We don't want depth-testing either.
251 glDisable(GL_DEPTH_TEST);
252
253 // But, for fun, let's make the text partially transparent too.
254 glColor4f(0.6,1.0,0.6,.75);
255
256 // Render our various display mode settings.
257 sprintf(buf,"Mode: %s", TexModesStr[Curr_TexMode]);
258 glRasterPos2i(2,2); ourPrintString(GLUT_BITMAP_HELVETICA_12,buf);
259
260 sprintf(buf,"AAdd: %d", Alpha_Add);
261 glRasterPos2i(2,14); ourPrintString(GLUT_BITMAP_HELVETICA_12,buf);
262
263 sprintf(buf,"Blend: %d", Blend_On);
264 glRasterPos2i(2,26); ourPrintString(GLUT_BITMAP_HELVETICA_12,buf);
265
266 sprintf(buf,"Light: %d", Light_On);
267 glRasterPos2i(2,38); ourPrintString(GLUT_BITMAP_HELVETICA_12,buf);
268
269 sprintf(buf,"Tex: %d", Texture_On);
270 glRasterPos2i(2,50); ourPrintString(GLUT_BITMAP_HELVETICA_12,buf);
271
272 sprintf(buf,"Filt: %d", Filtering_On);
273 glRasterPos2i(2,62); ourPrintString(GLUT_BITMAP_HELVETICA_12,buf);
274
275
276 // Now we want to render the calulated FPS at the top.
277
278 // To ease, simply translate up. Note we're working in screen
279 // pixels in this projection.
280
281 glTranslatef(6.0f,Window_Height - 14,0.0f);
282
283 // Make sure we can read the FPS section by first placing a
284 // dark, mostly opaque backdrop rectangle.
285 glColor4f(0.2,0.2,0.2,0.75);
286
287 glBegin(GL_QUADS);
288 glVertex3f( 0.0f, -2.0f, 0.0f);
289 glVertex3f( 0.0f, 12.0f, 0.0f);
290 glVertex3f(140.0f, 12.0f, 0.0f);
291 glVertex3f(140.0f, -2.0f, 0.0f);
292 glEnd();
293
294 glColor4f(0.9,0.2,0.2,.75);
295 sprintf(buf,"FPS: %f F: %2d", FrameRate, FrameCount);
296 glRasterPos2i(6,0);
297 ourPrintString(GLUT_BITMAP_HELVETICA_12,buf);
298
299 // Done with this special projection matrix. Throw it away.
300 glPopMatrix();
301
302 // All done drawing. Let's show it.
303 glutSwapBuffers();
304
305 // Now let's do the motion calculations.
306 X_Rot+=X_Speed;
307 Y_Rot+=Y_Speed;
308
309 // And collect our statistics.
310 ourDoFPS();
311 }
312
313
314 // ------
315 // Callback function called when a normal key is pressed.
316
317 void cbKeyPressed(
318 unsigned char key,
319 int x, int y
320 )
321 {
322 switch (key) {
323 case 113: case 81: case 27: // Q (Escape) - We're outta here.
324 glutDestroyWindow(Window_ID);
325 exit(1);
326 break; // exit doesn't return, but anyway...
327
328 case 130: case 98: // B - Blending.
329 Blend_On = Blend_On ? 0 : 1;
330 if (!Blend_On)
331 glDisable(GL_BLEND);
332 else
333 glEnable(GL_BLEND);
334 break;
335
336 case 108: case 76: // L - Lighting
337 Light_On = Light_On ? 0 : 1;
338 break;
339
340 case 109: case 77: // M - Mode of Blending
341 if ( ++ Curr_TexMode > 3 )
342 Curr_TexMode=0;
343 glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,TexModes[Curr_TexMode]);
344 break;
345
346 case 116: case 84: // T - Texturing.
347 Texture_On = Texture_On ? 0 : 1;
348 break;
349
350 case 97: case 65: // A - Alpha-blending hack.
351 Alpha_Add = Alpha_Add ? 0 : 1;
352 break;
353
354 case 102: case 70: // F - Filtering.
355 Filtering_On = Filtering_On ? 0 : 1;
356 break;
357
358 case 115: case 83: case 32: // F (Space) - Freeze!
359 X_Speed=Y_Speed=0;
360 break;
361
362 case 114: case 82: // R - Reverse.
363 X_Speed=-X_Speed;
364 Y_Speed=-Y_Speed;
365 break;
366
367 default:
368 printf ("KP: No action for %d.\n", key);
369 break;
370 }
371 }
372
373
374 // ------
375 // Callback Function called when a special key is pressed.
376
377 void cbSpecialKeyPressed(
378 int key,
379 int x,
380 int y
381 )
382 {
383 switch (key) {
384 case GLUT_KEY_PAGE_UP: // move the cube into the distance.
385 Z_Off -= 0.05f;
386 break;
387
388 case GLUT_KEY_PAGE_DOWN: // move the cube closer.
389 Z_Off += 0.05f;
390 break;
391
392 case GLUT_KEY_UP: // decrease x rotation speed;
393 X_Speed -= 0.01f;
394 break;
395
396 case GLUT_KEY_DOWN: // increase x rotation speed;
397 X_Speed += 0.01f;
398 break;
399
400 case GLUT_KEY_LEFT: // decrease y rotation speed;
401 Y_Speed -= 0.01f;
402 break;
403
404 case GLUT_KEY_RIGHT: // increase y rotation speed;
405 Y_Speed += 0.01f;
406 break;
407
408 default:
409 printf ("SKP: No action for %d.\n", key);
410 break;
411 }
412 }
413
414
415 // ------
416 // Function to build a simple full-color texture with alpha channel,
417 // and then create mipmaps. This could instead load textures from
418 // graphics files from disk, or render textures based on external
419 // input.
420
421 void ourBuildTextures(
422 void
423 )
424 {
425 GLenum gluerr;
426 GLubyte tex[128][128][4];
427 int x,y,t;
428 int hole_size = 3300; // ~ == 57.45 ^ 2.
429
430 // Generate a texture index, then bind it for future operations.
431 glGenTextures(1,&Texture_ID);
432 glBindTexture(GL_TEXTURE_2D,Texture_ID);
433
434 // Iterate across the texture array.
435
436 for(y=0;y<128;y++) {
437 for(x=0;x<128;x++) {
438
439 // A simple repeating squares pattern.
440 // Dark blue on white.
441
442 if ( ( (x+4)%32 < 8 ) && ( (y+4)%32 < 8)) {
443 tex[x][y][0]=tex[x][y][1]=0; tex[x][y][2]=120;
444 } else {
445 tex[x][y][0]=tex[x][y][1]=tex[x][y][2]=240;
446 }
447
448 // Make a round dot in the texture's alpha-channel.
449
450 // Calculate distance to center (squared).
451 t = (x-64)*(x-64) + (y-64)*(y-64) ;
452
453 if ( t < hole_size) // Don't take square root; compare squared.
454 tex[x][y][3]=255; // The dot itself is opaque.
455 else if (t < hole_size + 100)
456 tex[x][y][3]=128; // Give our dot an anti-aliased edge.
457 else
458 tex[x][y][3]=0; // Outside of the dot, it's transparent.
459
460 }
461 }
462
463 // The GLU library helps us build MipMaps for our texture.
464
465 if ((gluerr=gluBuild2DMipmaps(GL_TEXTURE_2D, 4, 128, 128, GL_RGBA,
466 GL_UNSIGNED_BYTE, (void *)tex))) {
467
468 fprintf(stderr,"GLULib%s\n",gluErrorString(gluerr));
469 exit(-1);
470 }
471
472 // Some pretty standard settings for wrapping and filtering.
473 glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
474 glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
475
476 // We start with GL_DECAL mode.
477 glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
478 }
479
480
481 // ------
482 // Callback routine executed whenever our window is resized. Lets us
483 // request the newly appropriate perspective projection matrix for
484 // our needs. Try removing the gluPerspective() call to see what happens.
485
486 void cbResizeScene(
487 int Width,
488 int Height
489 )
490 {
491 // Let's not core dump, no matter what.
492 if (Height == 0)
493 Height = 1;
494
495 glViewport(0, 0, Width, Height);
496
497 glMatrixMode(GL_PROJECTION);
498 glLoadIdentity();
499 gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);
500
501 glMatrixMode(GL_MODELVIEW);
502
503 Window_Width = Width;
504 Window_Height = Height;
505 }
506
507
508 // ------
509 // Does everything needed before losing control to the main
510 // OpenGL event loop.
511
512 void ourInit(
513 int Width,
514 int Height
515 )
516 {
517 ourBuildTextures();
518
519 // Color to clear color buffer to.
520 glClearColor(0.1f, 0.1f, 0.1f, 0.0f);
521
522 // Depth to clear depth buffer to; type of test.
523 glClearDepth(1.0);
524 glDepthFunc(GL_LESS);
525
526 // Enables Smooth Color Shading; try GL_FLAT for (lack of) fun.
527 glShadeModel(GL_SMOOTH);
528
529 // Load up the correct perspective matrix; using a callback directly.
530 cbResizeScene(Width,Height);
531
532 // Set up a light, turn it on.
533 glLightfv(GL_LIGHT1, GL_POSITION, Light_Position);
534 glLightfv(GL_LIGHT1, GL_AMBIENT, Light_Ambient);
535 glLightfv(GL_LIGHT1, GL_DIFFUSE, Light_Diffuse);
536 glEnable (GL_LIGHT1);
537
538 // A handy trick -- have surface material mirror the color.
539 glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
540 glEnable(GL_COLOR_MATERIAL);
541 }
542
543 // ------
544 // The main() function. Inits OpenGL. Calls our own init function,
545 // then passes control onto OpenGL.
546
547 int main(
548 int argc,
549 char **argv
550 )
551 {
552 glutInit(&argc, argv);
553
554 // To see OpenGL drawing, take out the GLUT_DOUBLE request.
555 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
556 glutInitWindowSize(Window_Width, Window_Height);
557
558 // Open a window
559 Window_ID = glutCreateWindow( PROGRAM_TITLE );
560
561 // Register the callback function to do the drawing.
562 glutDisplayFunc(&cbRenderScene);
563
564 // If there's nothing to do, draw.
565 glutIdleFunc(&cbRenderScene);
566
567 // It's a good idea to know when our window's resized.
568 glutReshapeFunc(&cbResizeScene);
569
570 // And let's get some keyboard input.
571 glutKeyboardFunc(&cbKeyPressed);
572 glutSpecialFunc(&cbSpecialKeyPressed);
573
574 // OK, OpenGL's ready to go. Let's call our own init function.
575 ourInit(Window_Width, Window_Height);
576
577 // Print out a bit of help dialog.
578 printf("\n" PROGRAM_TITLE "\n\n\
579 Use arrow keys to rotate, 'R' to reverse, 'S' to stop.\n\
580 Page up/down will move cube away from/towards camera.\n\n\
581 Use first letter of shown display mode settings to alter.\n\n\
582 Q or [Esc] to quit; OpenGL window must have focus for input.\n");
583
584 // Pass off control to OpenGL.
585 // Above functions are called as appropriate.
586 glutMainLoop();
587
588 return 1;
589 }
590