1 //========================================================================
2 // This is a small test application for GLFW.
3 // This is an OpenGL port of the famous "PONG" game (the first computer
4 // game ever?). It is very simple, and could be improved alot. It was
5 // created in order to show off the gaming capabilities of GLFW.
6 //========================================================================
7
8 import glfw;
9 import std.math;
10 import std.c.stdlib;
11
12 //========================================================================
13 // Constants
14 //========================================================================
15
16 // Screen resolution
17 const int WIDTH = 640;
18 const int HEIGHT = 480;
19
20 // Player size (units)
21 const float PLAYER_XSIZE = 0.05;
22 const float PLAYER_YSIZE = 0.15;
23
24 // Ball size (units)
25 const float BALL_SIZE = 0.02;
26
27 // Maximum player movement speed (units / second)
28 const float MAX_SPEED = 1.5;
29
30 // Player movement acceleration (units / seconds^2)
31 const float ACCELERATION = 4.0;
32
33 // Player movement deceleration (units / seconds^2)
34 const float DECELERATION = 2.0;
35
36 // Ball movement speed (units / second)
37 const float BALL_SPEED = 0.4;
38
39 // Menu options
40 const int MENU_NONE = 0;
41 const int MENU_PLAY = 1;
42 const int MENU_QUIT = 2;
43
44 // Game events
45 const int NOBODY_WINS = 0;
46 const int PLAYER1_WINS = 1;
47 const int PLAYER2_WINS = 2;
48
49 // Winner ID
50 const int NOBODY = 0;
51 const int PLAYER1 = 1;
52 const int PLAYER2 = 2;
53
54 // Camera positions
55 const int CAMERA_CLASSIC = 0;
56 const int CAMERA_ABOVE = 1;
57 const int CAMERA_SPECTATOR = 2;
58 const int CAMERA_DEFAULT = CAMERA_CLASSIC;
59
60
61 //========================================================================
62 // Textures
63 //========================================================================
64
65 const int TEX_TITLE = 0;
66 const int TEX_MENU = 1;
67 const int TEX_INSTR = 2;
68 const int TEX_WINNER1 = 3;
69 const int TEX_WINNER2 = 4;
70 const int TEX_FIELD = 5;
71 const int NUM_TEXTURES = 6;
72
73 // Texture names
74 const char[] tex_name[ NUM_TEXTURES ] = [
75 "pong3d_title.tga",
76 "pong3d_menu.tga",
77 "pong3d_instr.tga",
78 "pong3d_winner1.tga",
79 "pong3d_winner2.tga",
80 "pong3d_field.tga"
81 ];
82
83 // OpenGL texture object IDs
84 GLuint tex_id[ NUM_TEXTURES ];
85
86
87 //========================================================================
88 // Global variables
89 //========================================================================
90
91 // Display information
92 int width, height;
93
94 // Frame information
95 double thistime, oldtime, dt, starttime;
96
97 // Camera information
98 int camerapos;
99
100 // Player information
101 struct Player {
102 double ypos; // -1.0 to +1.0
103 double yspeed; // -MAX_SPEED to +MAX_SPEED
104 }
105 Player player1, player2;
106
107 // Ball information
108 struct Ball {
109 double xpos, ypos;
110 double xspeed, yspeed;
111 }
112 Ball ball;
113
114 // And the winner is...
115 int winner;
116
117 // Lighting configuration
118 const GLfloat env_ambient[4] = [1.0f,1.0f,1.0f,1.0f];
119 const GLfloat light1_position[4] = [-3.0f,3.0f,2.0f,1.0f];
120 const GLfloat light1_diffuse[4] = [1.0f,1.0f,1.0f,0.0f];
121 const GLfloat light1_ambient[4] = [0.0f,0.0f,0.0f,0.0f];
122
123 // Object material properties
124 const GLfloat player1_diffuse[4] = [1.0f,0.3f,0.3f,1.0f];
125 const GLfloat player1_ambient[4] = [0.3f,0.1f,0.0f,1.0f];
126 const GLfloat player2_diffuse[4] = [0.3f,1.0f,0.3f,1.0f];
127 const GLfloat player2_ambient[4] = [0.1f,0.3f,0.1f,1.0f];
128 const GLfloat ball_diffuse[4] = [1.0f,1.0f,0.5f,1.0f];
129 const GLfloat ball_ambient[4] = [0.3f,0.3f,0.1f,1.0f];
130 const GLfloat border_diffuse[4] = [0.3f,0.3f,1.0f,1.0f];
131 const GLfloat border_ambient[4] = [0.1f,0.1f,0.3f,1.0f];
132 const GLfloat floor_diffuse[4] = [1.0f,1.0f,1.0f,1.0f];
133 const GLfloat floor_ambient[4] = [0.3f,0.3f,0.3f,1.0f];
134
135
136 //========================================================================
137 // LoadTextures() - Load textures from disk and upload to OpenGL card
138 //========================================================================
139
LoadTextures()140 void LoadTextures( )
141 {
142 int i;
143
144 // Generate texture objects
145 glGenTextures( NUM_TEXTURES, tex_id );
146
147 // Load textures
148 for( i = 0; i < NUM_TEXTURES; i ++ )
149 {
150 // Select texture object
151 glBindTexture( GL_TEXTURE_2D, tex_id[ i ] );
152
153 // Set texture parameters
154 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
155 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
156 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
157 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
158
159 // Upload texture from file to texture memory
160 glfwLoadTexture2D( tex_name[ i ], 0 );
161 }
162 }
163
164
165 //========================================================================
166 // DrawImage() - Draw a 2D image as a texture
167 //========================================================================
168
DrawImage(int texnum,float x1,float x2,float y1,float y2)169 void DrawImage( int texnum, float x1, float x2, float y1, float y2 )
170 {
171 glEnable( GL_TEXTURE_2D );
172 glBindTexture( GL_TEXTURE_2D, tex_id[ texnum ] );
173 glBegin( GL_QUADS );
174 glTexCoord2f( 0.0f, 1.0f );
175 glVertex2f( x1, y1 );
176 glTexCoord2f( 1.0f, 1.0f );
177 glVertex2f( x2, y1 );
178 glTexCoord2f( 1.0f, 0.0f );
179 glVertex2f( x2, y2 );
180 glTexCoord2f( 0.0f, 0.0f );
181 glVertex2f( x1, y2 );
182 glEnd();
183 glDisable( GL_TEXTURE_2D );
184 }
185
186
187 //========================================================================
188 // GameMenu() - Game menu (returns menu option)
189 //========================================================================
190
GameMenu()191 int GameMenu( )
192 {
193 int option;
194
195 // Enable sticky keys
196 glfwEnable( GLFW_STICKY_KEYS );
197
198 // Wait for a game menu key to be pressed
199 do
200 {
201 // Get window size
202 glfwGetWindowSize( &width, &height );
203
204 // Set viewport
205 glViewport( 0, 0, width, height );
206
207 // Clear display
208 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
209 glClear( GL_COLOR_BUFFER_BIT );
210
211 // Setup projection matrix
212 glMatrixMode( GL_PROJECTION );
213 glLoadIdentity();
214 glOrtho( 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f );
215
216 // Setup modelview matrix
217 glMatrixMode( GL_MODELVIEW );
218 glLoadIdentity();
219
220 // Display title
221 glColor3f( 1.0f, 1.0f, 1.0f );
222 DrawImage( TEX_TITLE, 0.1f, 0.9f, 0.0f, 0.3f );
223
224 // Display menu
225 glColor3f( 1.0f, 1.0f, 0.0f );
226 DrawImage( TEX_MENU, 0.38f, 0.62f, 0.35f, 0.5f );
227
228 // Display instructions
229 glColor3f( 0.0f, 1.0f, 1.0f );
230 DrawImage( TEX_INSTR, 0.32f, 0.68f, 0.65f, 0.85f );
231
232 // Swap buffers
233 glfwSwapBuffers();
234
235 // Check for keys
236 if( glfwGetKey( 'Q' ) || !glfwGetWindowParam( GLFW_OPENED ) )
237 {
238 option = MENU_QUIT;
239 }
240 else if( glfwGetKey( GLFW_KEY_F1 ) )
241 {
242 option = MENU_PLAY;
243 }
244 else
245 {
246 option = MENU_NONE;
247 }
248
249 // To avoid horrible busy waiting, sleep for at least 20 ms
250 glfwSleep( 0.02 );
251 }
252 while( option == MENU_NONE );
253
254 // Disable sticky keys
255 glfwDisable( GLFW_STICKY_KEYS );
256
257 return option;
258 }
259
260
261 //========================================================================
262 // NewGame() - Initialize a new game
263 //========================================================================
264
NewGame()265 void NewGame( )
266 {
267 // Frame information
268 starttime = thistime = glfwGetTime();
269
270 // Camera information
271 camerapos = CAMERA_DEFAULT;
272
273 // Player 1 information
274 player1.ypos = 0.0;
275 player1.yspeed = 0.0;
276
277 // Player 2 information
278 player2.ypos = 0.0;
279 player2.yspeed = 0.0;
280
281 // Ball information
282 ball.xpos = -1.0 + PLAYER_XSIZE;
283 ball.ypos = player1.ypos;
284 ball.xspeed = 1.0;
285 ball.yspeed = 1.0;
286 }
287
288
289 //========================================================================
290 // PlayerControl() - Player control
291 //========================================================================
292
PlayerControl()293 void PlayerControl( )
294 {
295 float joy1pos[ 2 ];
296 float joy2pos[ 2 ];
297
298 // Get joystick X & Y axis positions
299 glfwGetJoystickPos( GLFW_JOYSTICK_1, joy1pos, 2 );
300 glfwGetJoystickPos( GLFW_JOYSTICK_2, joy2pos, 2 );
301
302 // Player 1 control
303 if( glfwGetKey( 'A' ) || joy1pos[ 1 ] > 0.2f )
304 {
305 player1.yspeed += dt * ACCELERATION;
306 if( player1.yspeed > MAX_SPEED )
307 {
308 player1.yspeed = MAX_SPEED;
309 }
310 }
311 else if( glfwGetKey( 'Z' ) || joy1pos[ 1 ] < -0.2f )
312 {
313 player1.yspeed -= dt * ACCELERATION;
314 if( player1.yspeed < -MAX_SPEED )
315 {
316 player1.yspeed = -MAX_SPEED;
317 }
318 }
319 else
320 {
321 player1.yspeed /= exp( DECELERATION * dt );
322 }
323
324 // Player 2 control
325 if( glfwGetKey( 'K' ) || joy2pos[ 1 ] > 0.2f )
326 {
327 player2.yspeed += dt * ACCELERATION;
328 if( player2.yspeed > MAX_SPEED )
329 {
330 player2.yspeed = MAX_SPEED;
331 }
332 }
333 else if( glfwGetKey( 'M' ) || joy2pos[ 1 ] < -0.2f )
334 {
335 player2.yspeed -= dt * ACCELERATION;
336 if( player2.yspeed < -MAX_SPEED )
337 {
338 player2.yspeed = -MAX_SPEED;
339 }
340 }
341 else
342 {
343 player2.yspeed /= exp( DECELERATION * dt );
344 }
345
346 // Update player 1 position
347 player1.ypos += dt * player1.yspeed;
348 if( player1.ypos > 1.0 - PLAYER_YSIZE )
349 {
350 player1.ypos = 1.0 - PLAYER_YSIZE;
351 player1.yspeed = 0.0;
352 }
353 else if( player1.ypos < -1.0 + PLAYER_YSIZE )
354 {
355 player1.ypos = -1.0 + PLAYER_YSIZE;
356 player1.yspeed = 0.0;
357 }
358
359 // Update player 2 position
360 player2.ypos += dt * player2.yspeed;
361 if( player2.ypos > 1.0 - PLAYER_YSIZE )
362 {
363 player2.ypos = 1.0 - PLAYER_YSIZE;
364 player2.yspeed = 0.0;
365 }
366 else if( player2.ypos < -1.0 + PLAYER_YSIZE )
367 {
368 player2.ypos = -1.0 + PLAYER_YSIZE;
369 player2.yspeed = 0.0;
370 }
371 }
372
373
374 //========================================================================
375 // BallControl() - Ball control
376 //========================================================================
377
BallControl()378 int BallControl( )
379 {
380 int event;
381 double ballspeed;
382
383 // Calculate new ball speed
384 ballspeed = BALL_SPEED * (1.0 + 0.02*(thistime-starttime));
385 ball.xspeed = ball.xspeed > 0 ? ballspeed : -ballspeed;
386 ball.yspeed = ball.yspeed > 0 ? ballspeed : -ballspeed;
387 ball.yspeed *= 0.74321;
388
389 // Update ball position
390 ball.xpos += dt * ball.xspeed;
391 ball.ypos += dt * ball.yspeed;
392
393 // Did the ball hit a top/bottom wall?
394 if( ball.ypos >= 1.0 )
395 {
396 ball.ypos = 2.0 - ball.ypos;
397 ball.yspeed = -ball.yspeed;
398 }
399 else if( ball.ypos <= -1.0 )
400 {
401 ball.ypos = -2.0 - ball.ypos;
402 ball.yspeed = -ball.yspeed;
403 }
404
405 // Did the ball hit/miss a player?
406 event = NOBODY_WINS;
407
408 // Is the ball entering the player 1 goal?
409 if( ball.xpos < -1.0 + PLAYER_XSIZE )
410 {
411 // Did player 1 catch the ball?
412 if( ball.ypos > (player1.ypos-PLAYER_YSIZE) &&
413 ball.ypos < (player1.ypos+PLAYER_YSIZE) )
414 {
415 ball.xpos = -2.0 + 2.0*PLAYER_XSIZE - ball.xpos;
416 ball.xspeed = -ball.xspeed;
417 }
418 else
419 {
420 event = PLAYER2_WINS;
421 }
422 }
423
424 // Is the ball entering the player 2 goal?
425 if( ball.xpos > 1.0 - PLAYER_XSIZE )
426 {
427 // Did player 2 catch the ball?
428 if( ball.ypos > (player2.ypos-PLAYER_YSIZE) &&
429 ball.ypos < (player2.ypos+PLAYER_YSIZE) )
430 {
431 ball.xpos = 2.0 - 2.0*PLAYER_XSIZE - ball.xpos;
432 ball.xspeed = -ball.xspeed;
433 }
434 else
435 {
436 event = PLAYER1_WINS;
437 }
438 }
439
440 return event;
441 }
442
443
444 //========================================================================
445 // DrawBox() - Draw a 3D box
446 //========================================================================
447
448 const float TEX_SCALE = 4.0f;
449
450
DrawBox(float x1,float y1,float z1,float x2,float y2,float z2)451 void DrawBox( float x1, float y1, float z1, float x2, float y2, float z2 )
452 {
453 // Draw six sides of a cube
454 glBegin( GL_QUADS );
455 // Side 1 (down)
456 glNormal3f( 0.0f, 0.0f, -1.0f );
457 glTexCoord2f( 0.0f, 0.0f );
458 glVertex3f( x1,y2,z1 );
459 glTexCoord2f( TEX_SCALE, 0.0f );
460 glVertex3f( x2,y2,z1 );
461 glTexCoord2f( TEX_SCALE, TEX_SCALE );
462 glVertex3f( x2,y1,z1 );
463 glTexCoord2f( 0.0f, TEX_SCALE );
464 glVertex3f( x1,y1,z1 );
465 // Side 2 (up)
466 glNormal3f( 0.0f, 0.0f, 1.0f );
467 glTexCoord2f( 0.0f, 0.0f );
468 glVertex3f( x1,y1,z2 );
469 glTexCoord2f( TEX_SCALE, 0.0f );
470 glVertex3f( x2,y1,z2 );
471 glTexCoord2f( TEX_SCALE, TEX_SCALE );
472 glVertex3f( x2,y2,z2 );
473 glTexCoord2f( 0.0f, TEX_SCALE );
474 glVertex3f( x1,y2,z2 );
475 // Side 3 (backward)
476 glNormal3f( 0.0f, -1.0f, 0.0f );
477 glTexCoord2f( 0.0f, 0.0f );
478 glVertex3f( x1,y1,z1 );
479 glTexCoord2f( TEX_SCALE, 0.0f );
480 glVertex3f( x2,y1,z1 );
481 glTexCoord2f( TEX_SCALE, TEX_SCALE );
482 glVertex3f( x2,y1,z2 );
483 glTexCoord2f( 0.0f, TEX_SCALE );
484 glVertex3f( x1,y1,z2 );
485 // Side 4 (forward)
486 glNormal3f( 0.0f, 1.0f, 0.0f );
487 glTexCoord2f( 0.0f, 0.0f );
488 glVertex3f( x1,y2,z2 );
489 glTexCoord2f( TEX_SCALE, 0.0f );
490 glVertex3f( x2,y2,z2 );
491 glTexCoord2f( TEX_SCALE, TEX_SCALE );
492 glVertex3f( x2,y2,z1 );
493 glTexCoord2f( 0.0f, TEX_SCALE );
494 glVertex3f( x1,y2,z1 );
495 // Side 5 (left)
496 glNormal3f( -1.0f, 0.0f, 0.0f );
497 glTexCoord2f( 0.0f, 0.0f );
498 glVertex3f( x1,y1,z2 );
499 glTexCoord2f( TEX_SCALE, 0.0f );
500 glVertex3f( x1,y2,z2 );
501 glTexCoord2f( TEX_SCALE, TEX_SCALE );
502 glVertex3f( x1,y2,z1 );
503 glTexCoord2f( 0.0f, TEX_SCALE );
504 glVertex3f( x1,y1,z1 );
505 // Side 6 (right)
506 glNormal3f( 1.0f, 0.0f, 0.0f );
507 glTexCoord2f( 0.0f, 0.0f );
508 glVertex3f( x2,y1,z1 );
509 glTexCoord2f( TEX_SCALE, 0.0f );
510 glVertex3f( x2,y2,z1 );
511 glTexCoord2f( TEX_SCALE, TEX_SCALE );
512 glVertex3f( x2,y2,z2 );
513 glTexCoord2f( 0.0f, TEX_SCALE );
514 glVertex3f( x2,y1,z2 );
515 glEnd();
516 }
517
518
519 //========================================================================
520 // UpdateDisplay() - Draw graphics (all game related OpenGL stuff goes
521 // here)
522 //========================================================================
523
UpdateDisplay()524 void UpdateDisplay( )
525 {
526 // Get window size
527 glfwGetWindowSize( &width, &height );
528
529 // Set viewport
530 glViewport( 0, 0, width, height );
531
532 // Clear display
533 glClearColor( 0.02f, 0.02f, 0.02f, 0.0f );
534 glClearDepth( 1.0f );
535 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
536
537 // Setup projection matrix
538 glMatrixMode( GL_PROJECTION );
539 glLoadIdentity();
540 gluPerspective(
541 55.0f, // Angle of view
542 cast(GLfloat)width/cast(GLfloat)height, // Aspect
543 1.0f, // Near Z
544 100.0f // Far Z
545 );
546
547 // Setup modelview matrix
548 glMatrixMode( GL_MODELVIEW );
549 glLoadIdentity();
550 switch( camerapos )
551 {
552 default:
553 case CAMERA_CLASSIC:
554 gluLookAt(
555 0.0f, 0.0f, 2.5f,
556 0.0f, 0.0f, 0.0f,
557 0.0f, 1.0f, 0.0f
558 );
559 break;
560 case CAMERA_ABOVE:
561 gluLookAt(
562 0.0f, 0.0f, 2.5f,
563 cast(float)ball.xpos, cast(float)ball.ypos, 0.0f,
564 0.0f, 1.0f, 0.0f
565 );
566 break;
567 case CAMERA_SPECTATOR:
568 gluLookAt(
569 0.0f, -2.0, 1.2f,
570 cast(float)ball.xpos, cast(float)ball.ypos, 0.0f,
571 0.0f, 0.0f, 1.0f
572 );
573 break;
574 }
575
576 // Enable depth testing
577 glEnable( GL_DEPTH_TEST );
578 glDepthFunc( GL_LEQUAL );
579
580 // Enable lighting
581 glEnable( GL_LIGHTING );
582 glLightModelfv( GL_LIGHT_MODEL_AMBIENT, env_ambient );
583 glLightModeli( GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE );
584 glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
585 glLightfv( GL_LIGHT1, GL_POSITION, light1_position );
586 glLightfv( GL_LIGHT1, GL_DIFFUSE, light1_diffuse );
587 glLightfv( GL_LIGHT1, GL_AMBIENT, light1_ambient );
588 glEnable( GL_LIGHT1 );
589
590 // Front face is counter-clock-wise
591 glFrontFace( GL_CCW );
592
593 // Enable face culling (not necessary, but speeds up rendering)
594 glCullFace( GL_BACK );
595 glEnable( GL_CULL_FACE );
596
597 // Draw Player 1
598 glMaterialfv( GL_FRONT, GL_DIFFUSE, player1_diffuse );
599 glMaterialfv( GL_FRONT, GL_AMBIENT, player1_ambient );
600 DrawBox( -1.0, cast(GLfloat)player1.ypos-PLAYER_YSIZE, 0.0,
601 -1.0+PLAYER_XSIZE, cast(GLfloat)player1.ypos+PLAYER_YSIZE, 0.1 );
602
603 // Draw Player 2
604 glMaterialfv( GL_FRONT, GL_DIFFUSE, player2_diffuse );
605 glMaterialfv( GL_FRONT, GL_AMBIENT, player2_ambient );
606 DrawBox( 1.0-PLAYER_XSIZE, cast(GLfloat)player2.ypos-PLAYER_YSIZE, 0.0,
607 1.0, cast(GLfloat)player2.ypos+PLAYER_YSIZE, 0.1 );
608
609 // Draw Ball
610 glMaterialfv( GL_FRONT, GL_DIFFUSE, ball_diffuse );
611 glMaterialfv( GL_FRONT, GL_AMBIENT, ball_ambient );
612 DrawBox( cast(GLfloat)ball.xpos-BALL_SIZE, cast(GLfloat)ball.ypos-BALL_SIZE, 0.0,
613 cast(GLfloat)ball.xpos+BALL_SIZE, cast(GLfloat)ball.ypos+BALL_SIZE, BALL_SIZE*2 );
614
615 // Top game field border
616 glMaterialfv( GL_FRONT, GL_DIFFUSE, border_diffuse );
617 glMaterialfv( GL_FRONT, GL_AMBIENT, border_ambient );
618 DrawBox( -1.1f, 1.0f, 0.0f, 1.1f, 1.1f, 0.1f );
619 // Bottom game field border
620 glColor3f( 0.0f, 0.0f, 0.7f );
621 DrawBox( -1.1f, -1.1f, 0.0f, 1.1f, -1.0f, 0.1f );
622 // Left game field border
623 DrawBox( -1.1f, -1.0f, 0.0f, -1.0f, 1.0f, 0.1f );
624 // Left game field border
625 DrawBox( 1.0f, -1.0f, 0.0f, 1.1f, 1.0f, 0.1f );
626
627 // Enable texturing
628 glEnable( GL_TEXTURE_2D );
629 glBindTexture( GL_TEXTURE_2D, tex_id[ TEX_FIELD ] );
630
631 // Game field floor
632 glMaterialfv( GL_FRONT, GL_DIFFUSE, floor_diffuse );
633 glMaterialfv( GL_FRONT, GL_AMBIENT, floor_ambient );
634 DrawBox( -1.01f, -1.01f, -0.01f, 1.01f, 1.01f, 0.0f );
635
636 // Disable texturing
637 glDisable( GL_TEXTURE_2D );
638
639 // Disable face culling
640 glDisable( GL_CULL_FACE );
641
642 // Disable lighting
643 glDisable( GL_LIGHTING );
644
645 // Disable depth testing
646 glDisable( GL_DEPTH_TEST );
647 }
648
649
650 //========================================================================
651 // GameOver()
652 //========================================================================
653
GameOver()654 void GameOver( )
655 {
656 // Enable sticky keys
657 glfwEnable( GLFW_STICKY_KEYS );
658
659 // Until the user presses ESC or SPACE
660 while( !glfwGetKey( GLFW_KEY_ESC ) && !glfwGetKey( ' ' ) &&
661 glfwGetWindowParam( GLFW_OPENED ) )
662 {
663 // Draw display
664 UpdateDisplay();
665
666 // Setup projection matrix
667 glMatrixMode( GL_PROJECTION );
668 glLoadIdentity();
669 glOrtho( 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f );
670
671 // Setup modelview matrix
672 glMatrixMode( GL_MODELVIEW );
673 glLoadIdentity();
674
675 // Enable blending
676 glEnable( GL_BLEND );
677
678 // Dim background
679 glBlendFunc( GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA );
680 glColor4f( 0.3f, 0.3f, 0.3f, 0.3f );
681 glBegin( GL_QUADS );
682 glVertex2f( 0.0f, 0.0f );
683 glVertex2f( 1.0f, 0.0f );
684 glVertex2f( 1.0f, 1.0f );
685 glVertex2f( 0.0f, 1.0f );
686 glEnd();
687
688 // Display winner text
689 glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_COLOR );
690 if( winner == PLAYER1 )
691 {
692 glColor4f( 1.0f, 0.5f, 0.5f, 1.0f );
693 DrawImage( TEX_WINNER1, 0.35f, 0.65f, 0.46f, 0.54f );
694 }
695 else if( winner == PLAYER2 )
696 {
697 glColor4f( 0.5f, 1.0f, 0.5f, 1.0f );
698 DrawImage( TEX_WINNER2, 0.35f, 0.65f, 0.46f, 0.54f );
699 }
700
701 // Disable blending
702 glDisable( GL_BLEND );
703
704 // Swap buffers
705 glfwSwapBuffers();
706 }
707
708 // Disable sticky keys
709 glfwDisable( GLFW_STICKY_KEYS );
710 }
711
712
713 //========================================================================
714 // GameLoop() - Game loop
715 //========================================================================
716
GameLoop()717 void GameLoop( )
718 {
719 int playing, event;
720
721 // Initialize a new game
722 NewGame();
723
724 // Enable sticky keys
725 glfwEnable( GLFW_STICKY_KEYS );
726
727 // Loop until the game ends
728 playing = GL_TRUE;
729 while( playing && glfwGetWindowParam( GLFW_OPENED ) )
730 {
731 // Frame timer
732 oldtime = thistime;
733 thistime = glfwGetTime();
734 dt = thistime - oldtime;
735
736 // Get user input and update player positions
737 PlayerControl();
738
739 // Move the ball, and check if a player hits/misses the ball
740 event = BallControl();
741
742 // Did we have a winner?
743 switch( event )
744 {
745 case PLAYER1_WINS:
746 winner = PLAYER1;
747 playing = GL_FALSE;
748 break;
749 case PLAYER2_WINS:
750 winner = PLAYER2;
751 playing = GL_FALSE;
752 break;
753 default:
754 break;
755 }
756
757 // Did the user press ESC?
758 if( glfwGetKey( GLFW_KEY_ESC ) )
759 {
760 playing = GL_FALSE;
761 }
762
763 // Did the user change camera view?
764 if( glfwGetKey( '1' ) )
765 {
766 camerapos = CAMERA_CLASSIC;
767 }
768 else if( glfwGetKey( '2' ) )
769 {
770 camerapos = CAMERA_ABOVE;
771 }
772 else if( glfwGetKey( '3' ) )
773 {
774 camerapos = CAMERA_SPECTATOR;
775 }
776
777 // Draw display
778 UpdateDisplay();
779
780 // Swap buffers
781 glfwSwapBuffers();
782 }
783
784 // Disable sticky keys
785 glfwDisable( GLFW_STICKY_KEYS );
786
787 // Show winner
788 GameOver();
789 }
790
791
792 //========================================================================
793 // main() - Program entry point
794 //========================================================================
795
main()796 int main( )
797 {
798 int menuoption;
799
800 // Initialize GLFW
801 if( !glfwInit() )
802 {
803 exit( 0 );
804 }
805
806 // Open OpenGL window
807 if( !glfwOpenWindow( WIDTH, HEIGHT, 0,0,0,0, 16,0, GLFW_FULLSCREEN ) )
808 {
809 glfwTerminate();
810 exit( 0 );
811 }
812
813 // Load all textures
814 LoadTextures();
815
816 // Main loop
817 do
818 {
819 // Get menu option
820 menuoption = GameMenu();
821
822 // If the user wants to play, let him...
823 if( menuoption == MENU_PLAY )
824 {
825 GameLoop();
826 }
827 }
828 while( menuoption != MENU_QUIT );
829
830 // Unload all textures
831 if( glfwGetWindowParam( GLFW_OPENED ) )
832 {
833 glDeleteTextures( NUM_TEXTURES, tex_id );
834 }
835
836 // Terminate GLFW
837 glfwTerminate();
838
839 return 0;
840 }
841