The Code So Far VI
| Prev: Game Mode | Next: Subwindows | 
The following code starts in window mode. You can then select amongst a set of settings for game mode, and return to window mode. The instructions are displayed on screen using bitmap fonts.
Check out the source code at GitHub.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
// angle of rotation for the camera direction
float angle = 0.0f;
// actual vector representing the camera's direction
float lx=0.0f,lz=-1.0f;
// XZ position of the camera
float x=0.0f, z=5.0f;
// the key states. These variables will be zero
// when no key is being pressesed
float deltaAngle = 0.0f;
float deltaMove = 0;
int xOrigin = -1;
// color for the snowman's nose
float red = 1.0f, blue=0.5f, green=0.5f;
// scale of snowman
float scale = 1.0f;
// default font
void *font = GLUT_STROKE_ROMAN;
// width and height of the window
int h,w;
// variables to compute frames per second
int frame;
long time, timebase;
char s[60];
char currentMode[80];
// this string keeps the last good setting
// for the game mode
char gameModeString[40] = "640x480";
void init();
void changeSize(int ww, int hh) {
	h = hh;
	w = ww;
	// Prevent a divide by zero, when window is too short
	// (you cant make a window of zero width).
	if (h == 0)
		h = 1;
	float ratio =  w * 1.0 / h;
	// Use the Projection Matrix
	glMatrixMode(GL_PROJECTION);
	// Reset Matrix
	glLoadIdentity();
	// Set the viewport to be the entire window
	glViewport(0, 0, w, h);
	// Set the correct perspective.
	gluPerspective(45.0f, ratio, 0.1f, 100.0f);
	// Get Back to the Modelview
	glMatrixMode(GL_MODELVIEW);
}
void drawSnowMan() {
	glScalef(scale, scale, scale);
	glColor3f(1.0f, 1.0f, 1.0f);
// Draw Body
	glTranslatef(0.0f ,0.75f, 0.0f);
	glutSolidSphere(0.75f,20,20);
// Draw Head
	glTranslatef(0.0f, 1.0f, 0.0f);
	glutSolidSphere(0.25f,20,20);
// Draw Eyes
	glPushMatrix();
	glColor3f(0.0f,0.0f,0.0f);
	glTranslatef(0.05f, 0.10f, 0.18f);
	glutSolidSphere(0.05f,10,10);
	glTranslatef(-0.1f, 0.0f, 0.0f);
	glutSolidSphere(0.05f,10,10);
	glPopMatrix();
// Draw Nose
	glColor3f(red, green, blue);
	glRotatef(0.0f,1.0f, 0.0f, 0.0f);
	glutSolidCone(0.08f,0.5f,10,2);
	glColor3f(1.0f, 1.0f, 1.0f);
}
void renderBitmapString(
		float x,
		float y,
		float z,
		void *font,
		char *string) {
	char *c;
	glRasterPos3f(x, y,z);
	for (c=string; *c != '\0'; c++) {
		glutBitmapCharacter(font, *c);
	}
}
void renderStrokeFontString(
		float x,
		float y,
		float z,
		void *font,
		char *string) {  
	char *c;
	glPushMatrix();
	glTranslatef(x, y,z);
	glScalef(0.002f, 0.002f, 0.002f);
	for (c=string; *c != '\0'; c++) {
		glutStrokeCharacter(font, *c);
	}
	glPopMatrix();
}
void restorePerspectiveProjection() {
	glMatrixMode(GL_PROJECTION);
	// restore previous projection matrix
	glPopMatrix();
	// get back to modelview mode
	glMatrixMode(GL_MODELVIEW);
}
void setOrthographicProjection() {
	// switch to projection mode
	glMatrixMode(GL_PROJECTION);
	// save previous matrix which contains the
	//settings for the perspective projection
	glPushMatrix();
	// reset matrix
	glLoadIdentity();
	// set a 2D orthographic projection
	gluOrtho2D(0, w, h, 0);
	// switch back to modelview mode
	glMatrixMode(GL_MODELVIEW);
}
void computePos(float deltaMove) {
	x += deltaMove * lx * 0.1f;
	z += deltaMove * lz * 0.1f;
}
void renderScene(void) {
	if (deltaMove)
		computePos(deltaMove);
	// Clear Color and Depth Buffers
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	// Reset transformations
	glLoadIdentity();
	// Set the camera
	gluLookAt(	x, 1.0f, z,
			x+lx, 1.0f,  z+lz,
			0.0f, 1.0f,  0.0f);
// Draw ground
	glColor3f(0.9f, 0.9f, 0.9f);
	glBegin(GL_QUADS);
		glVertex3f(-100.0f, 0.0f, -100.0f);
		glVertex3f(-100.0f, 0.0f,  100.0f);
		glVertex3f( 100.0f, 0.0f,  100.0f);
		glVertex3f( 100.0f, 0.0f, -100.0f);
	glEnd();
// Draw 36 SnowMen
	char number[3];
	for(int i = -3; i < 3; i++)
		for(int j=-3; j < 3; j++) {
			glPushMatrix();
			glTranslatef(i*10.0f, 0.0f, j * 10.0f);
			drawSnowMan();
			sprintf(number,"%d",(i+3)*6+(j+3));
			renderStrokeFontString(0.0f, 0.5f, 0.0f, (void *)font ,number);
			glPopMatrix();
		}
	// Code to compute frames per second
	frame++;
	time=glutGet(GLUT_ELAPSED_TIME);
	if (time - timebase > 1000) {
		sprintf(s,"Lighthouse3D - FPS:%4.2f",
			frame*1000.0/(time-timebase));
		timebase = time;
		frame = 0;
	}
	setOrthographicProjection();
	void *font= GLUT_BITMAP_8_BY_13;
	glPushMatrix();
	glLoadIdentity();
	renderBitmapString(30,15,0,font,(char *)"GLUT Tutorial @ Lighthouse3D");
	renderBitmapString(30,30,0,font,s);
	renderBitmapString(30,45,0,font,(char *)"F1 - Game Mode  640x480 32 bits");
	renderBitmapString(30,60,0,font,(char *)"F2 - Game Mode  800x600 32 bits");
	renderBitmapString(30,75,0,font,(char *)"F3 - Game Mode 1024x768 32 bits");
	renderBitmapString(30,90,0,font,(char *)"F4 - Game Mode 1280x1024 32 bits");
	renderBitmapString(30,105,0,font,(char *)"F5 - Game Mode 1920x1200 32 bits");
	renderBitmapString(30,120,0,font,(char *)"F6 - Window Mode");
	renderBitmapString(30,135,0,font,(char *)"Esc - Quit");
	renderBitmapString(30,150,0,font,currentMode);
	glPopMatrix();
	restorePerspectiveProjection();
	glutSwapBuffers();
}
// -----------------------------------
//             KEYBOARD
// -----------------------------------
void processNormalKeys(unsigned char key, int xx, int yy) {
	switch (key) {
		case 27:
			if (glutGameModeGet(GLUT_GAME_MODE_ACTIVE) != 0)
				glutLeaveGameMode();
			exit(0);
			break;
	}
}
void pressKey(int key, int xx, int yy) {
	switch (key) {
		case GLUT_KEY_UP : deltaMove = 0.5f; break;
		case GLUT_KEY_DOWN : deltaMove = -0.5f; break;
		case GLUT_KEY_F1:
			// define resolution, color depth
			glutGameModeString("640x480:32");
			// enter full screen
			if (glutGameModeGet(GLUT_GAME_MODE_POSSIBLE)) {
				glutEnterGameMode();
				sprintf(gameModeString,"640x480:32");
				// register callbacks again
				// and init OpenGL context
				init();
			}
			else
				glutGameModeString(gameModeString);
			break;
		case GLUT_KEY_F2:
			// define resolution, color depth
			glutGameModeString("800x600:32");
			// enter full screen
			if (glutGameModeGet(GLUT_GAME_MODE_POSSIBLE)) {
				glutEnterGameMode();
				sprintf(gameModeString,"800x600:32");
				// register callbacks again
				// and init OpenGL context
				init();
			}
			else
				glutGameModeString(gameModeString);
			break;
		case GLUT_KEY_F3:
			// define resolution, color depth
			glutGameModeString("1024x768:32");
			// enter full screen
			if (glutGameModeGet(GLUT_GAME_MODE_POSSIBLE)) {
				glutEnterGameMode();
				sprintf(gameModeString,"1024x768:32");
				// register callbacks again
				// and init OpenGL context
				init();
			}
			else
				glutGameModeString(gameModeString);
			break;
		case GLUT_KEY_F4:
			// define resolution, color depth
			glutGameModeString("1280x1024:32");
			// enter full screen
			if (glutGameModeGet(GLUT_GAME_MODE_POSSIBLE)) {
				glutEnterGameMode();
				sprintf(gameModeString,"1280x1024:32");
				// register callbacks again
				// and init OpenGL context
				init();
			}
			else
				glutGameModeString(gameModeString);
			break;
		case GLUT_KEY_F5:
			// define resolution, color depth
			glutGameModeString("1920x1200");
			// enter full screen
			if (glutGameModeGet(GLUT_GAME_MODE_POSSIBLE)) {
				glutEnterGameMode();
				sprintf(gameModeString,"1920x1200");
				// register callbacks again
				// and init OpenGL context
				init();
			}
			else
				glutGameModeString(gameModeString);
			break;
		case GLUT_KEY_F6:
			// return to default window
			w = 800;h = 600;
			if (glutGameModeGet(GLUT_GAME_MODE_ACTIVE) != 0) {
				glutLeaveGameMode();
				//init();
			}
			break;
	}
	if (glutGameModeGet(GLUT_GAME_MODE_ACTIVE) == 0)
		sprintf(currentMode,"Current Mode: Window");
	else
		sprintf(currentMode,
			"Current Mode: Game Mode %dx%d at %d hertz, %d bpp",
			glutGameModeGet(GLUT_GAME_MODE_WIDTH),
			glutGameModeGet(GLUT_GAME_MODE_HEIGHT),
			glutGameModeGet(GLUT_GAME_MODE_REFRESH_RATE),
			glutGameModeGet(GLUT_GAME_MODE_PIXEL_DEPTH));
}
void releaseKey(int key, int x, int y) {
	switch (key) {
		case GLUT_KEY_UP :
		case GLUT_KEY_DOWN : deltaMove = 0;break;
	}
}
// -----------------------------------
//             MOUSE
// -----------------------------------
void mouseMove(int x, int y) {
	// this will only be true when the left button is down
	if (xOrigin >= 0) {
		// update deltaAngle
		deltaAngle = (x - xOrigin) * 0.001f;
		// update camera's direction
		lx = sin(angle + deltaAngle);
		lz = -cos(angle + deltaAngle);
	}
}
void mouseButton(int button, int state, int x, int y) {
	// only start motion if the left button is pressed
	if (button == GLUT_LEFT_BUTTON) {
		// when the button is released
		if (state == GLUT_UP) {
			angle += deltaAngle;
			xOrigin = -1;
		}
		else  {// state = GLUT_DOWN
			xOrigin = x;
		}
	}
}
void init() {
	// register callbacks
	glutDisplayFunc(renderScene);
	glutReshapeFunc(changeSize);
	glutIdleFunc(renderScene);
	glutIgnoreKeyRepeat(1);
	glutKeyboardFunc(processNormalKeys);
	glutSpecialFunc(pressKey);
	glutSpecialUpFunc(releaseKey);
	glutMouseFunc(mouseButton);
	glutMotionFunc(mouseMove);
	// OpenGL init
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_CULL_FACE);
}
// -----------------------------------
//             MAIN
// -----------------------------------
int main(int argc, char **argv) {
	// init GLUT and create window
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowPosition(100,100);
	glutInitWindowSize(800,600);
	glutCreateWindow("Lighthouse3D - GLUT Tutorial");
	// register callbacks
	init();
	// enter GLUT event processing cycle
	glutMainLoop();
	return 1;
}
| Prev: Game Mode | Next: Subwindows | 
8 Responses to “The Code So Far VI”
Leave a Reply to George Cancel reply
This site uses Akismet to reduce spam. Learn how your comment data is processed.

Excellent tutorial!
Many thanks!
i’m getting an error every time i leave fullscreen, the computer gets stuck on a black screen with only the mouse showing, can’t alt tab or force close (using MAC OS X)
i tried a couple of things and the solution i found was to create the window again when leave the fullscreen
case GLUT_KEY_F6:
// return to default window
w = 800;h = 600;
if (glutGameModeGet(GLUT_GAME_MODE_ACTIVE) != 0) {
glutLeaveGameMode();
glutCreateWindow(“Lighthouse3D – GLUT Tutorial”);
init();
}
break;
i’m not sure if it`s because i’m on a mac but it worked
Thanks, your fix worked for me too.
First, thanks for this great tutorial, and second, I had some problems when leaving Game Mode and returning back to Window Mode. Program crashed. The solution was:
– New global var:
int current_window;– change at case GLUT_KEY_F6:
glutLeaveGameMode();glutSetWindow(current_window);
– change in main:
glutCreateWindow("Lighthouse3D - GLUT Tutorial");current_window = glutGetWindow();
First: very cool tutorial.
I had the same problem, thanks, the window id solved it for me too.
Very nice tutorial… I learned a lot 🙂 this is my first time an was able to understand it.. Thanks
SYNTAX ERROR here
// Draw 36 SnowMen
char number[3];
for(int i = -3; i < 3; i++)
for(int j=-3; j < 3;++) {
you forgot the variable "j" just make it
// Draw 36 SnowMen
char number[3];
for(int i = -3; i < 3; i++)
for(int j=-3; j < 3;j++) {
Thanks. Code updated 🙂