--- /dev/null
+#if defined(WIN32)
+#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
+#include "glut.h"
+#elif defined(__APPLE__) || defined(MACOSX)
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+enum {
+ FRAME=40,
+ HEIGHT=100,
+ PADDLESIZE=10
+};
+
+static int score1;
+static int score2;
+static GLdouble paddle1;
+static GLdouble paddle2;
+static GLdouble ballX;
+static GLdouble ballY;
+static GLdouble ballVecX;
+static GLdouble ballVecY;
+
+
+static void initball(void) {
+ ballX = 0.0;
+ ballY = 0.0;
+ if(ballVecX < 0)
+ ballVecX = -1.0;
+ else
+ ballVecX = 1.0;
+ ballVecY = 1.0;
+}
+
+static void run(void) {
+ // Check for collisions with paddles
+ if(ballVecX < 0 && ballX <= -HEIGHT + -ballVecX * 1.5) {
+ if(ballY >= paddle1 - PADDLESIZE && ballY <= paddle1 + PADDLESIZE) {
+ ballVecX *= -1.15;
+ ballVecY *= 1.15;
+ }
+ }
+ if(ballVecX > 0 && ballX >= HEIGHT - ballVecX * 1.5) {
+ if(ballY >= paddle2 - PADDLESIZE && ballY <= paddle2 + PADDLESIZE) {
+ ballVecX *= -1.15;
+ ballVecY *= 1.15;
+ }
+ }
+
+ // Check if it's past the top or bottom of the screen
+ if(ballY >= HEIGHT || ballY <= -HEIGHT) {
+ ballVecY *= -1;
+ }
+
+ // Check if it's past the sides of the screen
+ if(ballX >= HEIGHT) {
+ ++score1;
+ initball();
+ return;
+ }
+ if(ballX <= -HEIGHT) {
+ ++score2;
+ initball();
+ return;
+ }
+
+ // Move the ball
+ ballX += ballVecX;
+ ballY += ballVecY;
+}
+
+static void display(void) {
+ glClear(GL_COLOR_BUFFER_BIT);
+ glColor3d(0.0, 0.0, 0.0);
+
+ // Draw the paddles
+ glLineWidth(2.0);
+ glBegin(GL_LINES);
+ glVertex2d(-HEIGHT + 1, paddle1 - PADDLESIZE);
+ glVertex2d(-HEIGHT + 1, paddle1 + PADDLESIZE);
+ glVertex2d( HEIGHT - 1, paddle2 + PADDLESIZE);
+ glVertex2d( HEIGHT - 1, paddle2 - PADDLESIZE);
+ glEnd();
+
+ // Draw the ball
+ glPointSize(5.0);
+ glBegin(GL_POINTS);
+ glVertex2d(ballX, ballY);
+ glEnd();
+
+ // Write the score
+ glRasterPos2d(-5.0, HEIGHT - 10.0);
+ glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, '0' + score1);
+ glRasterPos2d( 5.0, HEIGHT - 10.0);
+ glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, '0' + score2);
+
+ glutSwapBuffers();
+}
+
+static void resize(int w, int h) {
+ glViewport(0, 0, w, h);
+ glLoadIdentity();
+ glOrtho(-HEIGHT, HEIGHT, -HEIGHT, HEIGHT, -1.0, 1.0);
+}
+
+static void keyboard(unsigned char key, int x, int y) {
+ (void)x;(void)y;
+
+ switch(key) {
+ case 'q':
+ case 'Q':
+ case '\033':
+ exit(0);
+
+ case 'w':
+ if(paddle1 + PADDLESIZE < HEIGHT)
+ paddle1 += PADDLESIZE;
+ break;
+ case 's':
+ if(paddle1 - PADDLESIZE > -HEIGHT)
+ paddle1 -= PADDLESIZE;
+ break;
+
+ case 'i':
+ if(paddle2 + PADDLESIZE < HEIGHT)
+ paddle2 += PADDLESIZE;
+ break;
+ case 'k':
+ if(paddle2 - PADDLESIZE > -HEIGHT)
+ paddle2 -= PADDLESIZE;
+ break;
+
+ default:
+ return;
+ }
+ glutPostRedisplay();
+}
+
+static void timer(int lastTime) {
+ int curTime = glutGet(GLUT_ELAPSED_TIME);
+ do {
+ lastTime += FRAME;
+ run();
+ } while(lastTime + FRAME < curTime);
+ glutPostRedisplay();
+ glutTimerFunc(FRAME - (curTime - lastTime), timer, curTime);
+}
+
+static void init(void) {
+ glClearColor(1.0, 1.0, 1.0, 0.0);
+ initball();
+}
+
+int main(int argc, char *argv[]) {
+ glutInitWindowPosition(100, 100);
+ glutInitWindowSize(640, 480);
+ glutInit(&argc, argv);
+ glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
+ glutCreateWindow(argv[0]);
+ glutDisplayFunc(display);
+ glutReshapeFunc(resize);
+ glutKeyboardFunc(keyboard);
+ glutTimerFunc(FRAME, timer, glutGet(GLUT_ELAPSED_TIME));
+ init();
+ glutMainLoop();
+ return 0;
+}
+