glutKeyboardFunc()
I'm learning OpenGL and GLUT and my first project is an Asteroids type game. How could I get keypresses of the Arrow Keys with glutKeyboardFunc() ? 
See my thread about 3D Game Engine. (I know it's not).
Thanks

See my thread about 3D Game Engine. (I know it's not).
Thanks
~ Bring a Pen ~
glutSpecialFunc is what you'll actually use to receive arrow key input in GLUT (dunno why they're two separate functions, but it's how the API was designed). The man page will tell you everything you need to know. If you're not familiar with man pages, open Terminal.app and type "man glutSpecialFunc".
I don't get it. void glutSpecialFunc(void (*func)(int key, int x, int y));
Should I use it like: glutSpecialFunc(GLUT_KEY_UP)? What's x and y for? Should I say:
Should I use it like: glutSpecialFunc(GLUT_KEY_UP)? What's x and y for? Should I say:
Code:
if glutSpecialFunc(GLUT_KEY_UP)
{
boolKeyUp=1;
}

~ Bring a Pen ~
You can find out the code of most keys pressed (including arrows) with glutSpecialFunc, something like this:
Then, after you've figured out which number corresponds to which key you can do something like:
Code:
#include <stdio.h>
...
void keyboard(int key, int x, int y)
{
printf("key %d\n", key);
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(640, 480);
glutCreateWindow("GLUT Program");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutIdleFunc(idle);
glutSpecialFunc(keyboard); // <-- add this for keyboard
glutMainLoop();
return EXIT_SUCCESS;
}
Then, after you've figured out which number corresponds to which key you can do something like:
Code:
void keyboard(int key, int x, int y)
{
//printf("key %d\n", key);
switch (key)
{
case 100:
printf("left arrow pressed\n");
break;
case 101:
printf("up arrow pressed\n");
break;
case 102:
printf("right arrow pressed\n");
break;
case 103:
printf("down arrow pressed\n");
break;
}
}
So I've included that code. I have a few variables that need changing due to that code, e.g.
I tried replacing the printf() statements with that one, but I get errors? I think It's because my variables aren't global, but I don't understand how to make them global. How would I do this, or is there an easier way to do it?
Code:
shipPosX=shipPosX+10
I tried replacing the printf() statements with that one, but I get errors? I think It's because my variables aren't global, but I don't understand how to make them global. How would I do this, or is there an easier way to do it?
~ Bring a Pen ~
Local:
Global:
Code:
void myFunction(void)
{
float shipPosX;
}
Global:
Code:
float shipPosX;
void myFunction(void)
{
;
}
It sounds like you need a stronger foundation in language concepts before moving on, or you'll keep running into problems like these and not understanding why or having a good way to figure it out without asking for help. This book would be an excellent investment.
In addition to that, I just noticed that Learn C on the Mac is back in print too. Looks like there's an electronic version of it as well.
ThemsAllTook Wrote:glutSpecialFunc is what you'll actually use to receive arrow key input in GLUT (dunno why they're two separate functions, but it's how the API was designed).
Oh hey, after putting together a little example code for mikey in another thread, I recalled why one couldn't just use glutSpecialFunc for everything: They reused some of the same ASCII constants for things like arrow keys! I wonder why they did that?
OK, I've got a simple 2D scene with a slightly detailed box with an arrow indicating the direction, and I thought some sort of bullet would be cool. How would I implement the Space Bar or Cmd key into my code?
PS. I've been learning more about C, and got out a book from my local library.
PPS. I Won't be attempting a 3D engine anytime soon, but - just out of interest - I noticed there was a 3-digit coordinate reference for my triangle, if I was building a 3D environment, could I just add a Z-Axis, and a keyboard controller? Is it as easy as that?
PS. I've been learning more about C, and got out a book from my local library.
PPS. I Won't be attempting a 3D engine anytime soon, but - just out of interest - I noticed there was a 3-digit coordinate reference for my triangle, if I was building a 3D environment, could I just add a Z-Axis, and a keyboard controller? Is it as easy as that?

~ Bring a Pen ~
mikey Wrote:OK, I've got a simple 2D scene with a slightly detailed box with an arrow indicating the direction, and I thought some sort of bullet would be cool. How would I implement the Space Bar or Cmd key into my code?I don't know if you can detect the Cmd key with GLUT. For the space bar, be sure to study the code I posted in that other thread about a "simple rectangle". Here's the post: http://www.idevgames.com/forum/showpost....ostcount=8
mikey Wrote:PPS. I Won't be attempting a 3D engine anytime soon, but - just out of interest - I noticed there was a 3-digit coordinate reference for my triangle, if I was building a 3D environment, could I just add a Z-Axis, and a keyboard controller? Is it as easy as that?Right, in a 3D environment you make use of the z-axis. You'd probably also want to set up a perspective projection and use depth testing.
OK, I've tried to implement a laser, but It fires all the time. I don't see how it's drawing a line from ShipPosX,ShipPosY to the coordinates specified by direction.
Here's my code:
__
Here's my code:
Code:
/* All code © mikey, iDevGames member.
SPACE GAME
*/
#include <stdlib.h>
#include <GLUT/glut.h>
int dir;
int shipPosX;
int shipPosY;
int amfiring;
amfiring = 1;
shipPosX = 840;
shipPosY = 525;
void fire()
{
if (dir==0)
{
glBegin(GL_LINES);
glVertex3f(shipPosX,shipPosY,0.0f);
glVertex3f(shipPosX,shipPosY+1000,0.0f);
glEnd();
}
else if (dir==90)
{
glBegin(GL_LINES);
glVertex3f(shipPosX,shipPosY,0.0f);
glVertex3f(shipPosX+1000,shipPosY,0.0f);
glEnd();
}
else if (dir==180)
{
glBegin(GL_LINES);
glVertex3f(shipPosX,shipPosY,0.0f);
glVertex3f(shipPosX,shipPosY-1000,0.0f);
glEnd();
}
else if (dir==-90)
{
glBegin(GL_LINES);
glVertex3f(shipPosX,shipPosY,0.0f);
glVertex3f(shipPosX-1000,shipPosY,0.0f);
glEnd();
}
glutSwapBuffers();
}
void keyboard(int key, int x, int y)
{
//printf("key %d\n", key);
switch (key)
{
case 100:
//lefty
shipPosX=shipPosX-20;
dir=-90;
amfiring = 0;
break;
case 101:
//uppy
shipPosY=shipPosY+20;
dir=0;
amfiring = 0;
break;
case 102:
//righty
shipPosX=shipPosX+20;
dir=90;
amfiring = 0;
break;
case 103:
//downy
shipPosY=shipPosY-20;
dir=180;
amfiring = 0;
break;
case 32:
//spacey
amfiring = 1;
break;
}
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// This code is where you put all drawing code. v
// draw the ship @ the position
// I used to have a velocity, but It didn't work as I hoped.
/*
shipPosX = shipPosX+shipVelX;
shipPosY = shipPosY+shipVelY;
*/
glBegin(GL_LINE_LOOP);
glVertex3f(shipPosX-40,shipPosY-40, 0.0f);
glVertex3f(shipPosX+40,shipPosY-40, 0.0f);
glVertex3f(shipPosX+40, shipPosY+40, 0.0f);
glVertex3f(shipPosX-40,shipPosY+40,0.0f);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex3f(shipPosX-30,shipPosY-30, 0.0f);
glVertex3f(shipPosX+30,shipPosY-30, 0.0f);
glVertex3f(shipPosX+30, shipPosY+30, 0.0f);
glVertex3f(shipPosX-30,shipPosY+30,0.0f);
glEnd();
if (dir==0)
{
glBegin(GL_LINES);
glVertex3f(shipPosX,shipPosY,0.0f);
glVertex3f(shipPosX,shipPosY+40,0.0f);
glEnd();
}
else if (dir==90)
{
glBegin(GL_LINES);
glVertex3f(shipPosX,shipPosY,0.0f);
glVertex3f(shipPosX+40,shipPosY,0.0f);
glEnd();
}
else if (dir==180)
{
glBegin(GL_LINES);
glVertex3f(shipPosX,shipPosY,0.0f);
glVertex3f(shipPosX,shipPosY-40,0.0f);
glEnd();
}
else if (dir==-90)
{
glBegin(GL_LINES);
glVertex3f(shipPosX,shipPosY,0.0f);
glVertex3f(shipPosX-40,shipPosY,0.0f);
glEnd();
}
glEnd();
// That's the ship drawn
if (amfiring = 1)
{
fire();
amfiring = 0;
}
amfiring = 0;
// drawframe
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();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(1680,1050);
glutCreateWindow("GLUT Program");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutIdleFunc(idle);
glutSpecialFunc(keyboard); // <-- add this for keyboard
glutFullScreen();
glutMainLoop();
return EXIT_SUCCESS;
}
// Keyboard Routines\\
__
Quote:Right, in a 3D environment you make use of the z-axis. You'd probably also want to set up a perspective projection and use depth testingHonestly, do you think (I would really like to) I would be capable of starting a 3D environment: A plane? maybe a cube or two in the centre of that plane? I mean, perspective and depth testing can't be too hard?
~ Bring a Pen ~
This is an extremely common pitfall in C: if (amfiring = 1)
It should be if (amfiring == 1)
Also, initialize your globals right where you declare them, like so:
Also, you should only call glutSwapBuffers(); once. You have another call in fire(), which you should remove.
Finally, do be sure to study that code I put together for you in that other thread. It will help you greatly with your keyboard input, which you will no doubt find useful since your laser beam will only appear for one frame with your current technique. And my example also includes a little Boolean typedef you can use instead of 1 or 0.
It should be if (amfiring == 1)
Also, initialize your globals right where you declare them, like so:
Code:
int shipPosX = 840;
int shipPosY = 525;
int amfiring = 1;
Also, you should only call glutSwapBuffers(); once. You have another call in fire(), which you should remove.
Finally, do be sure to study that code I put together for you in that other thread. It will help you greatly with your keyboard input, which you will no doubt find useful since your laser beam will only appear for one frame with your current technique. And my example also includes a little Boolean typedef you can use instead of 1 or 0.
Thanks AnotherJake! D'oh! '==' D'oh!
Please see my edit above.
Please see my edit above.
~ Bring a Pen ~
mikey Wrote:Honestly, do you think (I would really like to) I would be capable of starting a 3D environment: A plane? maybe a cube or two in the centre of that plane? I mean, perspective and depth testing can't be too hard?
You have a lot more to learn to be able to tackle it. To see what I mean by that, here's how you draw a spinning colored cube with lighting and depth testing (Controls: move with w, a, s, d, q, a, and reset with r. Toggle coloring with c):
Code:
#include <stdlib.h>
#include <math.h>
#include <GLUT/glut.h>
static const GLfloat cubeVerts[] =
{
-0.5f,-0.5f, 0.5f, // front
0.5f,-0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f,-0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
0.5f,-0.5f,-0.5f, // rear
-0.5f,-0.5f,-0.5f,
-0.5f, 0.5f,-0.5f,
0.5f, 0.5f,-0.5f,
0.5f,-0.5f,-0.5f,
-0.5f, 0.5f,-0.5f,
-0.5f, 0.5f, 0.5f, // top
0.5f, 0.5f, 0.5f,
0.5f, 0.5f,-0.5f,
-0.5f, 0.5f,-0.5f,
-0.5f, 0.5f, 0.5f,
0.5f, 0.5f,-0.5f,
-0.5f,-0.5f,-0.5f, // bottom
0.5f,-0.5f,-0.5f,
0.5f,-0.5f, 0.5f,
-0.5f,-0.5f, 0.5f,
-0.5f,-0.5f,-0.5f,
0.5f,-0.5f, 0.5f,
0.5f,-0.5f, 0.5f, // right
0.5f,-0.5f,-0.5f,
0.5f, 0.5f,-0.5f,
0.5f, 0.5f, 0.5f,
0.5f,-0.5f, 0.5f,
0.5f, 0.5f,-0.5f,
-0.5f,-0.5f,-0.5f, // left
-0.5f,-0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, 0.5f,-0.5f,
-0.5f,-0.5f,-0.5f,
-0.5f, 0.5f, 0.5f,
};
static const GLfloat cubeNormals[] =
{
0.0f, 0.0f, 1.0f, // front
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f,-1.0f, // rear
0.0f, 0.0f,-1.0f,
0.0f, 0.0f,-1.0f,
0.0f, 0.0f,-1.0f,
0.0f, 0.0f,-1.0f,
0.0f, 0.0f,-1.0f,
0.0f, 1.0f, 0.0f, // top
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f,-1.0f, 0.0f, // bottom
0.0f,-1.0f, 0.0f,
0.0f,-1.0f, 0.0f,
0.0f,-1.0f, 0.0f,
0.0f,-1.0f, 0.0f,
0.0f,-1.0f, 0.0f,
1.0f, 0.0f, 0.0f, // right
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f, // left
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f
};
static const GLubyte cubeColors[] =
{
255, 0, 255, 255, // front (magenta)
255, 0, 255, 255,
255, 0, 255, 255,
255, 0, 255, 255,
255, 0, 255, 255,
255, 0, 255, 255,
255, 0, 0, 255, // rear (red)
255, 0, 0, 255,
255, 0, 0, 255,
255, 0, 0, 255,
255, 0, 0, 255,
255, 0, 0, 255,
0, 0, 255, 255, // top (blue)
0, 0, 255, 255,
0, 0, 255, 255,
0, 0, 255, 255,
0, 0, 255, 255,
0, 0, 255, 255,
0, 255, 255, 255, // bottom (cyan)
0, 255, 255, 255,
0, 255, 255, 255,
0, 255, 255, 255,
0, 255, 255, 255,
0, 255, 255, 255,
0, 255, 0, 255, // right (green)
0, 255, 0, 255,
0, 255, 0, 255,
0, 255, 0, 255,
0, 255, 0, 255,
0, 255, 0, 255,
255, 255, 0, 255, // left (yellow)
255, 255, 0, 255,
255, 255, 0, 255,
255, 255, 0, 255,
255, 255, 0, 255,
255, 255, 0, 255
};
enum
{
false,
true
};
typedef unsigned char Bool;
typedef enum
{
ENTER = 3,
TAB = 9,
RETURN = 13,
ESC = 27,
SPACE = 32,
DEL = 127,
UP_ARROW, DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW,
NUM_KEY_CODES
} KeyCode;
Bool key[NUM_KEY_CODES], keyDown[NUM_KEY_CODES], keyUp[NUM_KEY_CODES];
Bool showColors = true;
int lastFrameTime = 0;
float dt; // delta time (how much time in between frames, used for all movement calculations)
float x = 0.0f, y = 0.0f, z = 0.0f, xRot = 0.0f, yRot = 0.0f;
void resetKeyboardInput(void)
{
int i;
for (i = 0; i < NUM_KEY_CODES; i++)
{
keyDown[i] = false;
keyUp[i] = false;
}
}
void keyboard(unsigned char rawKeyCode, int x, int y)
{
if (rawKeyCode < NUM_KEY_CODES)
{
key[rawKeyCode] = true;
keyDown[rawKeyCode] = true;
}
}
void keyboardUp(unsigned char rawKeyCode, int x, int y)
{
if (rawKeyCode < NUM_KEY_CODES)
{
key[rawKeyCode] = false;
keyUp[rawKeyCode] = false;
}
}
void keyboardSpecial(int rawKeyCode, int x, int y)
{
switch (rawKeyCode)
{
case GLUT_KEY_LEFT:
key[LEFT_ARROW] = true;
keyDown[LEFT_ARROW] = true;
break;
case GLUT_KEY_UP:
key[UP_ARROW] = true;
keyDown[UP_ARROW] = true;
break;
case GLUT_KEY_RIGHT:
key[RIGHT_ARROW] = true;
keyDown[RIGHT_ARROW] = true;
break;
case GLUT_KEY_DOWN:
key[DOWN_ARROW] = true;
keyDown[DOWN_ARROW] = true;
break;
}
}
void keyboardSpecialUp(int rawKeyCode, int x, int y)
{
switch (rawKeyCode)
{
case GLUT_KEY_LEFT:
key[LEFT_ARROW] = false;
keyUp[LEFT_ARROW] = true;
break;
case GLUT_KEY_UP:
key[UP_ARROW] = false;
keyUp[UP_ARROW] = true;
break;
case GLUT_KEY_RIGHT:
key[RIGHT_ARROW] = false;
keyUp[RIGHT_ARROW] = true;
break;
case GLUT_KEY_DOWN:
key[DOWN_ARROW] = false;
keyUp[DOWN_ARROW] = true;
break;
}
}
void update(void)
{
// "key" is cached locally so that it stays down until the next key up event
if (key['a'])
x -= 5.0f * dt;
if (key['d'])
x += 5.0f * dt;
if (key['q'])
y += 5.0f * dt;
if (key['z'])
y -= 5.0f * dt;
if (key['w'])
z -= 5.0f * dt;
if (key['s'])
{
z += 5.0f * dt;
// don't let it go behind the camera
if (z > 0.0f)
z = 0.0f;
}
if (key['r'])
{
// reset
x = y = z = 0.0f;
}
if (keyDown['c'])
showColors = !showColors;
xRot += 90.0f * dt;
while (xRot > 360.0f)
xRot -= 360.0f;
yRot += 90.0f * dt;
while (yRot > 360.0f)
yRot -= 360.0f;
}
void setPerspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar)
{
GLfloat xmin, xmax, ymin, ymax;
ymax = zNear * tanf(fovy * M_PI / 360.0f);
ymin = -ymax;
xmin = ymin * aspect;
xmax = ymax * aspect;
glFrustum(xmin, xmax, ymin, ymax, zNear, zFar);
}
void display(void)
{
update();
if (lastFrameTime == 0)
{
lastFrameTime = glutGet(GLUT_ELAPSED_TIME);
}
int now = glutGet(GLUT_ELAPSED_TIME);
int elapsedMilliseconds = now - lastFrameTime;
dt = elapsedMilliseconds / 1000.0f;
lastFrameTime = now;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
setPerspective(75.0f, (float)glutGet(GLUT_WINDOW_WIDTH) / (float)glutGet(GLUT_WINDOW_HEIGHT), 0.1f, 1000.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// move camera back a bit by moving the entire scene back
glTranslatef(0.0f, 0.0f, -2.0f);
// make a light
float diffuse = 1.0f;
float ambient = 0.1f;
float specular = 1.0f;
float lightDiffuse[] = { diffuse, diffuse, diffuse, 1.0f };
float lightAmbient[] = { ambient, ambient, ambient, 1.0f };
float lightSpecular[] = { specular, specular, specular, 1.0f };
float lightPosition[] = { 2.0f, 4.0f, 2.0f, 0.0f };
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient);
glLightfv(GL_LIGHT0, GL_SPECULAR, lightSpecular);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
// draw a cube
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glNormalPointer(GL_FLOAT, 0, cubeNormals);
if (showColors)
{
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, cubeColors);
}
else
{
glDisableClientState(GL_COLOR_ARRAY);
}
glVertexPointer(3, GL_FLOAT, 0, cubeVerts);
glPushMatrix();
glTranslatef(x, y, z);
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
glDrawArrays(GL_TRIANGLES, 0, 36);
glPopMatrix();
// finished with this frame
glutSwapBuffers();
// do this to clear the key ups and key downs for each frame
resetKeyboardInput();
}
void reshape(int width, int height)
{
glViewport(0, 0, width, height);
}
void idle(void)
{
glutPostRedisplay();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(640, 480);
glutCreateWindow("Spinning Cube");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutIdleFunc(idle);
glutKeyboardFunc(keyboard);
glutKeyboardUpFunc(keyboardUp);
glutSpecialFunc(keyboardSpecial);
glutSpecialUpFunc(keyboardSpecialUp);
glutMainLoop();
return EXIT_SUCCESS;
}