<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Last Stop &#187; mac os x</title>
	<atom:link href="http://laststop.spaceislimited.org/tag/mac-os-x/feed/" rel="self" type="application/rss+xml" />
	<link>http://laststop.spaceislimited.org</link>
	<description>it&#039;s going to be a long ride</description>
	<lastBuildDate>Wed, 28 Jan 2009 13:21:30 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Programming Pong in C and OpenGL &#8211; Part VI</title>
		<link>http://laststop.spaceislimited.org/2009/01/19/programming-pong-in-c-and-opengl-part-vi/</link>
		<comments>http://laststop.spaceislimited.org/2009/01/19/programming-pong-in-c-and-opengl-part-vi/#comments</comments>
		<pubDate>Mon, 19 Jan 2009 13:32:23 +0000</pubDate>
		<dc:creator>Timothy M. Rodriguez</dc:creator>
				<category><![CDATA[Technical Nonsense]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[c]]></category>
		<category><![CDATA[glut]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[mac os x]]></category>
		<category><![CDATA[opengl]]></category>
		<category><![CDATA[pong]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://laststop.spaceislimited.org/?p=57</guid>
		<description><![CDATA[Here&#8217;s the last part of my multi-part series on programming your very own pong clone in c and opengl!  It&#8217;s been a long time coming, so I hope you enjoy.  There&#8217;s lots of improvements in this version including a completely custom old-style &#8220;LED Alarm Clock&#8221; scoreboard, flashes on bounce, funky changing colors, improved collision detection, [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_61" class="wp-caption aligncenter" style="width: 409px"><a href="http://laststop.spaceislimited.org/wp-content/uploads/2009/01/timgl_05.png"><img class="size-full" title="Awesome Flashy Pong!" src="http://laststop.spaceislimited.org/wp-content/uploads/2009/01/timgl_05.png" alt="The latest version of my sample clone with scoreboard, etc." width="399" height="414" /></a><p class="wp-caption-text">The latest version of my sample clone!</p></div>
<p>Here&#8217;s the last part of my multi-part series on programming your very own pong clone in c and opengl!  It&#8217;s been a long time coming, so I hope you enjoy.  There&#8217;s lots of improvements in this version including a completely custom old-style &#8220;LED Alarm Clock&#8221; scoreboard, flashes on bounce, funky changing colors, improved collision detection, and a round ball! <img src='http://laststop.spaceislimited.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><span id="more-57"></span></p>
<p>Here&#8217;s the code!</p>
<pre class="brush: c">

#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;math.h&gt;

#include &lt;OpenAL/al.h&gt;
#include &lt;GLUT/glut.h&gt;

#define PADDLE_MOVE_SPEED 350
#define CLEAR_COLOR_DECAY 2.0
#define BALL_RADIUS 10
#define BALL_FACETS 60
#define START_SPEED 200

int lastFrameTime = 0, windowWidth = 0, windowHeight = 0, now = 0;
float midWidth = 0, midHeight = 0;
float elapsedTime = 0, elapsedMilliSeconds = 0;
char player1Move = 0, player2Move = 0;
float player1V = 0, player2V = 0;

float PI = 3.14159265358979323846264;

//scores
int player1Score = 0, player2Score = 0;

//the following variables calculate a random starting projectile trajectory
float randomDirection;
long longMax = 0x7fffffff;	//max of longs 2^31-1 (2^(n-1)-1 for 2&#039;s complement) float trajectory[2] = {0, 0};

float projMove[2] = {0, 0};
double trajectory[2] = {0, 0};
short moveSpeed = START_SPEED;

//glitz and glamour
float player1ColorDirection[3];
float player2ColorDirection[3];
float player1Color[3];
float player2Color[3];
float colorMoveSpeed = 2.0;
double vectorLength1 = 0;
double vectorLength2 = 0;

float ballColorDirection[3];
float ballColor[3];
double ballVectorLength = 0;

//background explosion color
float clearColor[3];

int i = 0;

//scoreboard
char player1Num1[7] = {1, 1, 1, 0, 1, 1, 1};	//digital display set to zero, (each segment is enabled or disabled)
char player1Num2[7] = {1, 1, 1, 0, 1, 1, 1};
char player2Num1[7] = {1, 1, 1, 0, 1, 1, 1};	//digital display set to zero, (each segment is enabled or disabled)
char player2Num2[7] = {1, 1, 1, 0, 1, 1, 1};

//digit representations
char digit0[7] = {1, 1, 1, 0, 1, 1, 1};
char digit1[7] = {0, 0, 1, 0, 0, 0, 1};
char digit2[7] = {0, 1, 1, 1, 1, 1, 0};
char digit3[7] = {0, 1, 1, 1, 0, 1, 1};
char digit4[7] = {1, 0, 1, 1, 0, 0, 1};
char digit5[7] = {1, 1, 0, 1, 0, 1, 1};
char digit6[7] = {1, 1, 0, 1, 1, 1, 1};
char digit7[7] = {0, 1, 1, 0, 0, 0, 1};
char digit8[7] = {1, 1, 1, 1, 1, 1, 1};
char digit9[7] = {1, 1, 1, 1, 0, 1, 1};

void setSpaceEffect(void) {
for (i=0; i &lt; 3; i++) {
player1ColorDirection[i] = (float) random() / (float) 0x7fffffff; //random vector
player2ColorDirection[i] = (float) random() / (float) 0x7fffffff;
ballColorDirection[i] = (float) random() / (float) 0x7fffffff;
}
//figure out vector lenngth
for (i=0; i &lt; 3; i++) {
vectorLength1 += player1ColorDirection[i] * player1ColorDirection[i];
vectorLength2 += player2ColorDirection[i] * player2ColorDirection[i];
ballVectorLength += ballColorDirection[i] * ballColorDirection[i];
}
sqrt(vectorLength1);
sqrt(vectorLength2);
sqrt(ballVectorLength);
//normalize vector
for (i=0; i &lt; 3; i++) {
player1ColorDirection[i] /= vectorLength1;
player2ColorDirection[i] /= vectorLength2;
ballColorDirection[i] /= ballVectorLength;
}
}

void calculateColor(float color[3], float colorDirection[3]) {
//caculate the next color based on the direction and elapsed time values
for (i=0; i &lt; 3; i++) {
color[i] += colorDirection[i] * colorMoveSpeed * elapsedTime;
if (color[i] &gt; 1) {
color[i] = 1;
colorDirection[i] *= -1;
}
else if (color[i] &lt; 0) {
color[i] = 0;
colorDirection[i] *= -1;
}
}
}

void calculateClearColor(float color[3]) {
for (i=0; i &lt; 3; i++) {
color[i] -= CLEAR_COLOR_DECAY * elapsedTime;
if(color[i] &lt; 0)
color[i] = 0;
}
}

void setClearColor(float color[3]) {
for (i=0; i &lt; 3; i++) {
color[i] = 1.0;
}
}

void resetProjectile(void) {
//set starting random trajectory
randomDirection = 2 * PI * (float) random() / (float) 0x7fffffff;
trajectory[0] = (float) cos(randomDirection);
trajectory[1] = (float) sin(randomDirection);
projMove[0] = midWidth;
projMove[1] = midHeight;
}

/*draw a digital (a la clock style) digit some place specified by x and y
*the enabled array is which segments of the display are enabled (counted starting from top left in a snake/8 fasion)
*
* 1 -
* 0| |2
* 3 -
* 4| |6
* 5 -
*/
void drawDigit(char enabled[7], float x, float y) {
glPushMatrix();
glTranslatef(x, y, 0);	//position digit to be drawn
//draw digital number (a la digital clock) segment by segment
glColor3f(1.0, 1.0, 1.0);
//draw segment 5
if(enabled[5]) {
glBegin(GL_QUADS);
glVertex2f(0,0);
glVertex2f(10,0);
glVertex2f(10,2);
glVertex2f(0,2);
glEnd();
}

//draw segment 3
if(enabled[3]) {
glBegin(GL_QUADS);
glVertex2f(0,9);
glVertex2f(10,9);
glVertex2f(10,11);
glVertex2f(0,11);
glEnd();
}

//draw segment 1
if(enabled[1]) {
glBegin(GL_QUADS);
glVertex2f(0,18);
glVertex2f(10,18);
glVertex2f(10,20);
glVertex2f(0,20);
glEnd();
}

//draw segment 4
if(enabled[4]) {
glBegin(GL_QUADS);
glVertex2f(0,2);
glVertex2f(2,2);
glVertex2f(2,9);
glVertex2f(0,9);
glEnd();
}

//draw segment 0
if(enabled[0]) {
glBegin(GL_QUADS);
glVertex2f(0,11);
glVertex2f(2,11);
glVertex2f(2,20);
glVertex2f(0,20);
glEnd();
}

//draw segment 6
if(enabled[6]) {
glBegin(GL_QUADS);
glVertex2f(8,2);
glVertex2f(10,2);
glVertex2f(10,9);
glVertex2f(8,9);
glEnd();
}

//draw segment 2
if(enabled[2]) {
glBegin(GL_QUADS);
glVertex2f(8,11);
glVertex2f(10,11);
glVertex2f(10,20);
glVertex2f(8,20);
glEnd();
}

glPopMatrix();
}

void setDigitEnablePattern(char enabled[7], char digit) {

switch(digit) {
case 0:
for(i=0; i&lt;7; i++) {
enabled[i] = digit0[i];
}
break;
case 1:
for(i=0; i&lt;7; i++) {
enabled[i] = digit1[i];
}
break;
case 2:
for(i=0; i&lt;7; i++) {
enabled[i] = digit2[i];
}
break;
case 3:
for(i=0; i&lt;7; i++) {
enabled[i] = digit3[i];
}
break;
case 4:
for(i=0; i&lt;7; i++) {
enabled[i] = digit4[i];
}
break;
case 5:
for(i=0; i&lt;7; i++) {
enabled[i] = digit5[i];
}
break;
case 6:
for(i=0; i&lt;7; i++) {
enabled[i] = digit6[i];
}
break;
case 7:
for(i=0; i&lt;7; i++) {
enabled[i] = digit7[i];
}
break;
case 8:
for(i=0; i&lt;7; i++) {
enabled[i] = digit8[i];
}
break;
case 9:
for(i=0; i&lt;7; i++) {
enabled[i] = digit9[i];
}
break;
}
}

void drawScore(char player1, char player2) {

if(player1 &lt; 10) {
setDigitEnablePattern(player1Num1, 0);
setDigitEnablePattern(player1Num2, player1);
}
else if (player1 &lt; 100) {
setDigitEnablePattern(player1Num1, player1 / 10);
setDigitEnablePattern(player1Num2, player1 - ((player1/10) * 10));
}
else {	//max out at 99
setDigitEnablePattern(player1Num1, 9);
setDigitEnablePattern(player1Num2, 9);
}

if(player2 &lt; 10) {
setDigitEnablePattern(player2Num1, 0);
setDigitEnablePattern(player2Num2, player2);
}
else if (player2 &lt; 100) {
setDigitEnablePattern(player2Num1, player2 / 10);
setDigitEnablePattern(player2Num2, player2 - ((player2/10) * 10));
}
else {	//max out at 99
setDigitEnablePattern(player2Num1, 9);
setDigitEnablePattern(player2Num2, 9);
}

drawDigit(player1Num1, (windowWidth/4)-15, 20);
drawDigit(player1Num2, (windowWidth/4)+5, 20);
drawDigit(player2Num1, ((windowWidth/4)*3)-15, 20);
drawDigit(player2Num2, ((windowWidth/4)*3)+5, 20);

}

void display(void)
{
//get window parameters
windowWidth = glutGet(GLUT_WINDOW_WIDTH);
windowHeight = glutGet(GLUT_WINDOW_HEIGHT);

midWidth = windowWidth/2;
midHeight = windowHeight/2;

//start timing code
if (lastFrameTime == 0) {
lastFrameTime = glutGet(GLUT_ELAPSED_TIME);
resetProjectile();	//since this is the fist time, this is actually a set <img src='http://laststop.spaceislimited.org/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' />
player1V = midHeight;
player2V = midHeight;
//initialize the space effect colors
setSpaceEffect();
glClearColor(0.0, 0.0, 0.0, 0.0);	//set clear color to black
}

now = glutGet(GLUT_ELAPSED_TIME);
elapsedMilliSeconds = now - lastFrameTime;
elapsedTime = elapsedMilliSeconds/1000.0f;
lastFrameTime = now;

calculateClearColor(clearColor);
glClearColor(clearColor[0], clearColor[1], clearColor[2], 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glShadeModel(GL_FLAT);

//draw score
drawScore(player1Score, player2Score);

//calculate move distances
switch (player1Move) {
case 1:		//move up
player1V += PADDLE_MOVE_SPEED * elapsedTime;
break;
case -1:	//move up
player1V -= PADDLE_MOVE_SPEED * elapsedTime;
break;
default:	//do nothing
break;
}
//check out of bounds
if (player1V &gt; windowHeight-50) {
//bounce back
player1Move = -1;
}
if (player1V &lt; 0+50) {
//bounce back other way
player1Move = 1;
}

switch (player2Move) {
case 1:		//move up
player2V += PADDLE_MOVE_SPEED * elapsedTime;
break;
case -1:	//move up
player2V -= PADDLE_MOVE_SPEED * elapsedTime;
break;
default:	//do nothing
break;
}
//check out of bounds
if (player2V &gt; windowHeight-50) {
//bounce back
player2Move = -1;
}
if (player2V &lt; 0+50) {
//bounce back other way
player2Move = 1;
}

//create and position player 1
glPushMatrix();

calculateColor(player1Color, player1ColorDirection);
glColor3f(player1Color[0], player1Color[1], player1Color[2]);	//player 1 color

glTranslatef(30.0f, player1V, 0.0f);

glBegin(GL_QUADS);
glVertex2f(-10, -50);
glVertex2f(-10, 50);
glVertex2f(10, 50);
glVertex2f(10, -50);
glEnd();

glPopMatrix();

//create and position player 2
glPushMatrix();

calculateColor(player2Color, player2ColorDirection);
glColor3f(player2Color[0], player2Color[1], player2Color[2]);	//player 2 color

glTranslatef(windowWidth-30, player2V, 0.0f);

glBegin(GL_QUADS);
glVertex2f(-10, -50);
glVertex2f(-10, 50);
glVertex2f(10, 50);
glVertex2f(10, -50);
glEnd();

glPopMatrix();

/***************************************
*	Projectile CODE!!!
*
***************************************/

//calculate move distances
projMove[0] += moveSpeed * trajectory[0] * elapsedTime;
projMove[1] += moveSpeed * trajectory[1] * elapsedTime;

//create and move projectile
glPushMatrix();

calculateColor(ballColor, ballColorDirection);
glColor3f(ballColor[0], ballColor[1], ballColor[2]);	//player 1 color

glTranslatef(projMove[0], projMove[1], 0.0f);

glBegin(GL_TRIANGLE_FAN);
for(i=0; i &lt; 360; i += 360 / BALL_FACETS) {
glVertex2f(sin(i * PI / 180) * BALL_RADIUS, cos(i * PI / 180) * BALL_RADIUS);
}
glEnd();

glPopMatrix();

//set bounds for projectile
if (projMove[0] &gt; (windowWidth)) {	//player 1 scored - out of bounds right
player1Score++;
moveSpeed = START_SPEED;
printf(&quot;Player 1 Scored!  Score: %f &quot;, player1Score);
resetProjectile();
}

else if (projMove[0] &lt; (0)) {		//player 2 scored - out of bounds left
player2Score++;
moveSpeed = START_SPEED;
resetProjectile();
}

else if (projMove[1] &gt; (windowHeight-10)) {	//out of bounds top
trajectory[1] *= -1;
projMove[1] -= 0.5;
}

else if (projMove[1] &lt; (10)) {	//out of bounds bottom
trajectory[1] *= -1;
projMove[1] += 0.5;
}

//collision detection code
else if (projMove[0] &lt; 50 &amp;amp;amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp;amp;amp; projMove[0] &gt; 49) {		//intersecting with line of left paddle
if (projMove[1] &lt;= player1V + 50 &amp;amp;amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp;amp;amp; projMove[1] &gt;= player1V-50) {
trajectory[0] *= -1;
moveSpeed += 30;
setClearColor(clearColor);
projMove[0] += 0.5;
}
}

else if (projMove[0] &gt; windowWidth-50 &amp;amp;amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp;amp;amp; projMove[0] &lt; windowWidth-49) {		//intersecting with line of right paddle
if (projMove[1] &lt;= player2V + 50 &amp;amp;amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp;amp;amp; projMove[1] &gt;= player2V-50) {
trajectory[0] *= -1;
moveSpeed += 30;
setClearColor(clearColor);
projMove[0] -= 0.5;
}
}

/******************************
*  END PROJECTILE CODE
*
******************************/

glutSwapBuffers();

}

void reshape(int width, int height)
{
glViewport(0, 0, width, height);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, width, 0, height);
glMatrixMode(GL_MODELVIEW);
}

void idle(void)
{
glutPostRedisplay();
}

void keyboard(unsigned char key, int x, int y) {
switch (key) {
case &#039;w&#039;:
//do something
player1Move=1;
glutPostRedisplay();
break;
case &#039;s&#039;:
//do something
player1Move=-1;
glutPostRedisplay();
break;
case &#039;o&#039;:
//do something
player2Move=1;
glutPostRedisplay();
break;
case &#039;l&#039;:
//do something
player2Move=-1;
glutPostRedisplay();
break;
default:
//some other key
break;
}

}

void keyboardup(unsigned char key, int x, int y) {
switch (key) {
case &#039;w&#039;:
//do something
player1Move=0;
glutPostRedisplay();
break;
case &#039;s&#039;:
player1Move=0;
glutPostRedisplay();
break;
case &#039;o&#039;:
player2Move=0;
glutPostRedisplay();
break;
case &#039;l&#039;:
player2Move=0;
glutPostRedisplay();
break;
default:
//some other key
break;
}

}

int main(int argc, char** argv)
{
glutInit(&amp;amp;amp;amp;amp;amp;amp;amp;argc, argv);

glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(500, 500);

glutCreateWindow(&quot;Tim GL&quot;);

glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutKeyboardUpFunc(keyboardup);
glutIdleFunc(idle);

glutMainLoop();
return EXIT_SUCCESS;
}
</pre>
<p>I delayed so long because I wanted to refactor this code to better separate components and functions, but I didn&#8217;t get the time to do so.  (That&#8217;s why I should do it that way from the start!)  You can get a direct copy of the binary <a title="TimGL 0.5!" href="/downloads/TimGL_0.5.zip">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://laststop.spaceislimited.org/2009/01/19/programming-pong-in-c-and-opengl-part-vi/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Programming Pong in C and OpenGL &#8211; Part V</title>
		<link>http://laststop.spaceislimited.org/2008/07/22/programming-pong-in-c-and-opengl-part-v/</link>
		<comments>http://laststop.spaceislimited.org/2008/07/22/programming-pong-in-c-and-opengl-part-v/#comments</comments>
		<pubDate>Wed, 23 Jul 2008 00:42:40 +0000</pubDate>
		<dc:creator>Timothy M. Rodriguez</dc:creator>
				<category><![CDATA[Technical Nonsense]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[c]]></category>
		<category><![CDATA[glut]]></category>
		<category><![CDATA[mac os x]]></category>
		<category><![CDATA[opengl]]></category>
		<category><![CDATA[pong]]></category>

		<guid isPermaLink="false">http://laststop.spaceislimited.org/?p=23</guid>
		<description><![CDATA[It’s been a while since I last updated on this, but hopefully you’ve brushed up on your C and OpenGL skills.  Here you&#8217;ll find the entire source code to a pong implementation in C and OpenGL. Enjoy! In interest of actually finally getting this post out the door, I’m just going to post the code!  [...]]]></description>
			<content:encoded><![CDATA[<p>It’s been a while since I last updated on this, but hopefully you’ve brushed up on your C and OpenGL skills.  Here you&#8217;ll find the entire source code to a pong implementation in C and OpenGL.</p>
<h3>Enjoy!</h3>
<p><span id="more-23"></span></p>
<p>In interest of actually finally getting this post out the door, I’m just going to post the code!  This is actually a snapshot of the code from a month or so back and I apologize for not tidying it up.  The reason I’m using a snapshot from a while back is because I have a newer, more glitzy version with a scoreboard and some simple effects that aren’t really necessary to get the basic game down.  I will post that code in a future post though when I’ve polished it up a bit more!  This is also most definitely not up to proper coding standards, but it gets the job done.  It was a late night hack-fest, so please disregard the lack of neatness!</p>
<h3>A word on use..</h3>
<p>You’re free to use the code however you like.  If you use it though, I would most definitely appreciate it if you post a link to <a title="Last Stop" href="http://laststop.spaceislimited.org" target="_blank">Last Stop</a> on your website or blog and a mention in the credits of the application.  Please also credit the references to Timothy M. Rodriguez.  You don’t have to do this, but it’d be nice.  I’d also very much love an e-mail or comment letting me know about your project!</p>
<h3>On to the Code!</h3>
<blockquote><p>#include &lt;stdlib.h&gt;<br />
#include &lt;stdio.h&gt;<br />
#include &lt;math.h&gt;</p>
<p>#include &lt;GLUT/glut.h&gt;</p>
<p>static int lastFrameTime = 0, windowWidth = 0, windowHeight = 0, now = 0;<br />
static float midWidth = 0, midHeight = 0;<br />
static float elapsedTime = 0, elapsedMilliSeconds = 0;<br />
static char player1Move = 0, player2Move = 0;<br />
static float player1V = 0, player2V = 0;</p>
<p>static float PI = 3.14159265358979323846264;</p>
<p>//scores<br />
static int player1Score = 0, player2Score = 0;</p>
<p>//the following variables calculate a random starting projectile trajectory<br />
static float randomDirection;<br />
static long longMax = 0x7fffffff;    //max of longs 2^31-1 (2^(n-1)-1 for 2&#8242;s complement) static float trajectory[2] = {0, 0};</p>
<p>static float projMove[2] = {0, 0};<br />
static double trajectory[2] = {0, 0};<br />
static char moveSpeed = 70;</p>
<p>void resetProjectile(void) {<br />
//set starting random trajectory<br />
randomDirection = 2 * PI * (float) random() / (float) 0x7fffffff;<br />
trajectory[0] = (float) cos(randomDirection);<br />
trajectory[1] = (float) sin(randomDirection);<br />
projMove[0] = midWidth;<br />
projMove[1] = midHeight;<br />
}</p>
<p>void display(void)<br />
{<br />
//get window parameters<br />
windowWidth = glutGet(GLUT_WINDOW_WIDTH);<br />
windowHeight = glutGet(GLUT_WINDOW_HEIGHT);</p>
<p>midWidth = windowWidth/2;<br />
midHeight = windowHeight/2;</p>
<p>//start timing code<br />
if (lastFrameTime == 0) {<br />
lastFrameTime = glutGet(GLUT_ELAPSED_TIME);<br />
resetProjectile();    //since this is the fist time, this is actually a set <img src='http://laststop.spaceislimited.org/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /><br />
}</p>
<p>now = glutGet(GLUT_ELAPSED_TIME);<br />
elapsedMilliSeconds = now &#8211; lastFrameTime;<br />
elapsedTime = elapsedMilliSeconds/1000.0f;<br />
lastFrameTime = now;</p>
<p>glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);<br />
glShadeModel(GL_FLAT);</p>
<p>//calculate move distances<br />
switch (player1Move) {<br />
case 1:        //move up<br />
player1V += 150 * elapsedTime;<br />
break;<br />
case -1:    //move up<br />
player1V -= 150 * elapsedTime;<br />
break;<br />
default:    //do nothing<br />
break;<br />
}<br />
//check out of bounds<br />
if (player1V &gt; (windowHeight/2)-50) {<br />
//bounce back<br />
player1Move = -1;<br />
}<br />
if (player1V &lt; -(windowHeight/2)+50) {<br />
//bounce back other way<br />
player1Move = 1;<br />
}</p>
<p>switch (player2Move) {<br />
case 1:        //move up<br />
player2V += 150 * elapsedTime;<br />
break;<br />
case -1:    //move up<br />
player2V -= 150 * elapsedTime;<br />
break;<br />
default:    //do nothing<br />
break;<br />
}<br />
//check out of bounds<br />
if (player2V &gt; (windowHeight/2)-50) {<br />
//bounce back<br />
player2Move = -1;<br />
}<br />
if (player2V &lt; -(windowHeight/2)+50) {<br />
//bounc back other way<br />
player2Move = 1;<br />
}</p>
<p>//create and position player 1<br />
glPushMatrix();</p>
<p>glColor3ub(255, 0, 0);    //red</p>
<p>glTranslatef(0.0f, player1V, 0.0f);</p>
<p>glBegin(GL_QUADS);<br />
glVertex2f(20.0f, (midHeight-50));<br />
glVertex2f(20.0f, (midHeight+50));<br />
glVertex2f(50.0f, (midHeight+50));<br />
glVertex2f(50.0f, (midHeight-50));<br />
glEnd();</p>
<p>glPopMatrix();</p>
<p>//create and position player 2<br />
glPushMatrix();</p>
<p>glColor3ub(0, 0, 255);    //blue</p>
<p>glTranslatef(0.0f, player2V, 0.0f);</p>
<p>glBegin(GL_QUADS);<br />
glVertex2f(windowWidth-20.0f, (midHeight-50));<br />
glVertex2f(windowWidth-20.0f, (midHeight+50));<br />
glVertex2f(windowWidth-50.0f, (midHeight+50));<br />
glVertex2f(windowWidth-50.0f, (midHeight-50));<br />
glEnd();</p>
<p>glPopMatrix();</p>
<p>/***************************************<br />
*    Projectile CODE!!!<br />
*<br />
***************************************/</p>
<p>//calculate move distances<br />
projMove[0] += moveSpeed * trajectory[0] * elapsedTime;<br />
projMove[1] += moveSpeed * trajectory[1] * elapsedTime;</p>
<p>//create and move projectile<br />
glPushMatrix();</p>
<p>glColor3ub(255, 255, 255);</p>
<p>glTranslatef(projMove[0], projMove[1], 0.0f);</p>
<p>glBegin(GL_QUADS);<br />
glVertex2f(-10, -10);<br />
glVertex2f(10, -10);<br />
glVertex2f(10, 10);<br />
glVertex2f(-10, 10);<br />
glEnd();</p>
<p>glPopMatrix();</p>
<p>//set bounds for projectile<br />
if (projMove[0] &gt; (windowWidth)) {    //player 1 scored &#8211; out of bounds right<br />
player1Score++;<br />
printf(&#8220;Player 1 Scored!  Score: %f &#8220;, player1Score);<br />
printf(&#8220;projMove[0] %f projMove[1] %f &#8220;, projMove[0], projMove[1]);<br />
resetProjectile();<br />
}</p>
<p>if (projMove[0] &lt; (0)) {        //player 2 scored &#8211; out of bounds left<br />
player2Score++;<br />
resetProjectile();<br />
}</p>
<p>if (projMove[1] &gt; (windowHeight)) {    //out of bounds top<br />
resetProjectile();<br />
}</p>
<p>if (projMove[1] &lt; (0)) {    //out of bounds bottom<br />
resetProjectile();<br />
}</p>
<p>//collision detection code</p>
<p>/******************************<br />
*  END PROJECTILE CODE<br />
*<br />
******************************/</p>
<p>glutSwapBuffers();</p>
<p>}</p>
<p>void reshape(int width, int height)<br />
{<br />
glViewport(0, 0, width, height);</p>
<p>glMatrixMode(GL_PROJECTION);<br />
glLoadIdentity();<br />
gluOrtho2D(0, width, 0, height);<br />
glMatrixMode(GL_MODELVIEW);<br />
}</p>
<p>void idle(void)<br />
{<br />
glutPostRedisplay();<br />
}</p>
<p>void keyboard(unsigned char key, int x, int y) {<br />
switch (key) {<br />
case &#8216;w&#8217;:<br />
//do something<br />
player1Move=1;<br />
glutPostRedisplay();<br />
break;<br />
case &#8216;s&#8217;:<br />
//do something<br />
player1Move=-1;<br />
glutPostRedisplay();<br />
break;<br />
case &#8216;a&#8217;:<br />
player1Move=0;<br />
glutPostRedisplay();<br />
break;<br />
case &#8216;o&#8217;:<br />
//do something<br />
player2Move=1;<br />
glutPostRedisplay();<br />
break;<br />
case &#8216;l&#8217;:<br />
//do something<br />
player2Move=-1;<br />
glutPostRedisplay();<br />
break;<br />
case &#8216;k&#8217;:<br />
player2Move=0;<br />
glutPostRedisplay();<br />
break;<br />
default:<br />
//some other key<br />
break;<br />
}</p>
<p>}</p>
<p>void keyboardup(unsigned char key, int x, int y) {<br />
switch (key) {<br />
case &#8216;i&#8217;:<br />
//do something<br />
player1Move=0;<br />
glutPostRedisplay();<br />
break;<br />
case &#8216;u&#8217;:<br />
player2Move=0;<br />
glutPostRedisplay();<br />
break;<br />
default:<br />
//some other key<br />
break;<br />
}</p>
<p>}</p>
<p>int main(int argc, char** argv)<br />
{<br />
glutInit(&amp;argc, argv);</p>
<p>glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);<br />
glutInitWindowSize(500, 500);</p>
<p>glutCreateWindow(&#8220;Tim GL&#8221;);</p>
<p>glutDisplayFunc(display);<br />
glutReshapeFunc(reshape);<br />
glutKeyboardFunc(keyboard);<br />
glutKeyboardUpFunc(keyboardup);<br />
glutIdleFunc(idle);</p>
<p>glutMainLoop();<br />
return EXIT_SUCCESS;<br />
}</p></blockquote>
<p>Well that&#8217;s a lot of code, but don&#8217;t be intimidated!  If you read through it (maybe a couple of times), you&#8217;ll start to understand it.  The main loop is short and sweet.  We start glut, create a window with it, and then register callback functions for displaying the game, reshaping (what to do if someone changes the size of the window), and for keyboard downpress and release events (keyboard func and keyboardupfunct).  Our display function then pretty much does all the work, and I use a bunch of global variables to keep track of state, such as where the projectile and the paddles are.  There&#8217;s also some brute force vanilla collision detection, which I hope you can appreciate.  The funny part is that most real collision detection systems use this concept, called the bounding box.  In pong, the bounding box of the paddle <em>is</em> the paddle.</p>
<p>You can get a compiled Mac OS X version <a title="Pong for Mac OS X" href="http://laststop.spaceislimited.org/downloads/TimGL.zip" target="_self">here</a>, but if you have your IDE setup right a straight copy and paste <em>should</em> work.  (If you had to make any changes, please let me know.)</p>
<p>Let any and all questions loose in the comments..</p>
]]></content:encoded>
			<wfw:commentRss>http://laststop.spaceislimited.org/2008/07/22/programming-pong-in-c-and-opengl-part-v/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
