Thursday, January 25, 2007

NeHe Lesson 01: Setting up an OpenGL window

Hi, and welcome to the NeHe lesson 01 done in the D programming language.

This code snippet shows you how to set up SDL to display an OpenGL window, How to use Derelict to load shared libraries and a basic loop for reading input and then drawing the screen.

I'm trying to use documenting comments in the code as specified by Ddoc.


/**
* The first lesson in the NeHe tutorial series.
* Originally written by Jeff Molofee.
*
* Authors: Jeff Molofee
* Olli Aalto
*/
module lesson01;

import derelict.opengl.gl;
import derelict.opengl.glu;
import derelict.sdl.sdl;

import tango.stdc.stringz;

/// The window title
const char[] WINDOW_TITLE = "NeHe's OpenGL Lesson 01 (D version)";

/// The main loop flag
bool running;

/**
* Module constructor. Here we load the GL, GLU and SDL shared libraries,
* and the initialize SDL.
*/
static this()
{
DerelictGL.load();
DerelictGLU.load();
DerelictSDL.load();

if (SDL_Init(SDL_INIT_VIDEO) < args =" the" fullscreen =" false;"> 1)
{
fullScreen = args[1] == "-fullscreen";
}

createGLWindow(WINDOW_TITLE, 640, 480, 16, fullScreen);
initGL();

running = true;
while (running)
{
processEvents();

drawGLScene();

SDL_GL_SwapBuffers();
SDL_Delay(10);
}
}

/**
* Process all the pending events.
*/
void processEvents()
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_KEYUP:
keyReleased(event.key.keysym.sym);
break;
case SDL_QUIT:
running = false;
break;
default:
break;
}
}
}

/**
* Process a key released event.
*/
void keyReleased(int key)
{
switch (key)
{
case SDLK_ESCAPE:
running = false;
break;
default:
break;
}
}

/**
* Resize and initialize the OpenGL window.
*/
void resizeGLScene(GLsizei width, GLsizei height)
{
if (height == 0)
{
height = 1;
}

// Reset The Current Viewport
glViewport(0, 0, width, height);

// Select The Projection Matrix
glMatrixMode(GL_PROJECTION);

// Reset The Projection Matrix
glLoadIdentity();

// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f, cast(GLfloat)width / cast(GLfloat)height,
0.1f, 100.0f);

// Select The Modelview Matrix
glMatrixMode(GL_MODELVIEW);

// Reset The Modelview Matrix
glLoadIdentity();
}

/**
* Initialize OpenGL.
*/
void initGL()
{
// Enables Smooth Shading
glShadeModel(GL_SMOOTH);

// Black Background
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

// Depth Buffer Setup
glClearDepth(1.0f);

// Enables Depth Testing
glEnable(GL_DEPTH_TEST);

// The Type Of Depth Test To Do
glDepthFunc(GL_LEQUAL);

// Really Nice Perspective Calculations
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}

/**
* The drawing function. Now we only clear the color and depht buffers, so that
* the window stays black.
*/
void drawGLScene()
{
// Clear The Screen And The Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Reset The Current Modelview Matrix
glLoadIdentity();
}

/**
* Initializes and opens the SDL window.
*/
void createGLWindow(char[] title, int width, int height, int bits,
bool fullScreen)
{
// Set the OpenGL attributes
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

// Set the window title
SDL_WM_SetCaption(toUtf8z(title), null);

// Note the SDL_DOUBLEBUF flag is not required to enable double
// buffering when setting an OpenGL video mode.
// Double buffering is enabled or disabled using the
// SDL_GL_DOUBLEBUFFER attribute. (See above.)
int mode = SDL_OPENGL;
if (fullScreen)
{
mode |= SDL_FULLSCREEN;
}

// Now open a SDL OpenGL window with the given parameters
if (SDL_SetVideoMode(width, height, bits, mode) is null)
{
throw new Exception("Failed to open OpenGL window: " ~ getSDLError());
}

resizeGLScene(width, height);
}

/**
* Get the SDL error as a D string.
*
* Returns: A D string containing the current SDL error.
*/
char[] getSDLError()
{
return fromUtf8z(SDL_GetError());
}

You can download the code from here.