Tuesday, January 30, 2007

NeHe Lesson 05: 3D Shapes

The last lesson of the very basics is here. This lesson doesn't bring anything new to the table, but shows you how to combine triangles and quads into pyramids and cubes.
Go read the lesson here first.

I'll put the changed drawing code here for your enjoyment.

/**
* The drawing function. Here we will draw the pyramid and cube.
*/
void drawGLScene()
{
// Clear The Screen And The Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset The Current Modelview Matrix
glLoadIdentity();

// Move Left 1.5 Units And Into The Screen 6.0
glTranslatef(-1.5f, 0.0f, -6.0f);

// Rotate The Triangle On The Y axis
glRotatef(rtri, 0.0f, 1.0f, 0.0f);

// Start Drawing The Pyramid
glBegin(GL_TRIANGLES);
glColor3f(1.0f,0.0f,0.0f); // Red
glVertex3f(0.0f, 1.0f, 0.0f); // Top Of Triangle (Front)
glColor3f(0.0f, 1.0f, 0.0f); // Green
glVertex3f(-1.0f, -1.0f, 1.0f); // Left Of Triangle (Front)
glColor3f(0.0f, 0.0f, 1.0f); // Blue
glVertex3f(1.0f, -1.0f, 1.0f); // Right Of Triangle (Front)

glColor3f(1.0f, 0.0f, 0.0f); // Red
glVertex3f(0.0f, 1.0f, 0.0f); // Top Of Triangle (Right)
glColor3f(0.0f, 0.0f, 1.0f); // Blue
glVertex3f(1.0f, -1.0f, 1.0f); // Left Of Triangle (Right)
glColor3f(0.0f, 1.0f, 0.0f); // Green
glVertex3f(1.0f, -1.0f, -1.0f); // Right Of Triangle (Right)

glColor3f(1.0f, 0.0f, 0.0f); // Red
glVertex3f(0.0f, 1.0f, 0.0f); // Top Of Triangle (Back)
glColor3f(0.0f, 1.0f, 0.0f); // Green
glVertex3f(1.0f, -1.0f, -1.0f); // Left Of Triangle (Back)
glColor3f(0.0f, 0.0f, 1.0f); // Blue
glVertex3f(-1.0f, -1.0f, -1.0f); // Right Of Triangle (Back)

glColor3f(1.0f, 0.0f, 0.0f); // Red
glVertex3f(0.0f, 1.0f, 0.0f); // Top Of Triangle (Left)
glColor3f(0.0f, 0.0f, 1.0f); // Blue
glVertex3f(-1.0f, -1.0f, -1.0f); // Left Of Triangle (Left)
glColor3f(0.0f, 1.0f, 0.0f); // Green
glVertex3f(-1.0f, -1.0f, 1.0f); // Right Of Triangle (Left)
// Done Drawing The Pyramid
glEnd();

// Reset The Current Modelview Matrix
glLoadIdentity();

// Move Right And Into The Screen
glTranslatef(1.5f, 0.0f, -7.0f);

// Rotate The Cube On X, Y & Z
glRotatef(rquad, 1.0f, 1.0f, 1.0f);

// Set The Color To Blue One Time Only
glColor3f(0.5f, 0.5f, 1.0f);

// Start Drawing The Cube
glBegin(GL_QUADS);
glColor3f(0.0f, 1.0f, 0.0f); // Set The Color To Green
glVertex3f(1.0f, 1.0f, -1.0f); // Top Right Of The Quad (Top)
glVertex3f(-1.0f, 1.0f, -1.0f); // Top Left Of The Quad (Top)
glVertex3f(-1.0f, 1.0f, 1.0f); // Bottom Left Of The Quad (Top)
glVertex3f(1.0f, 1.0f, 1.0f); // Bottom Right Of The Quad (Top)

glColor3f(1.0f, 0.5f, 0.0f); // Set The Color To Orange
glVertex3f(1.0f, -1.0f, 1.0f); // Top Right Of The Quad (Bottom)
glVertex3f(-1.0f, -1.0f, 1.0f); // Top Left Of The Quad (Bottom)
glVertex3f(-1.0f, -1.0f, -1.0f); // Bottom Left Of The Quad (Bottom)
glVertex3f(1.0f, -1.0f, -1.0f); // Bottom Right Of The Quad (Bottom)

glColor3f(1.0f, 0.0f, 0.0f); // Set The Color To Red
glVertex3f(1.0f, 1.0f, 1.0f); // Top Right Of The Quad (Front)
glVertex3f(-1.0f, 1.0f, 1.0f); // Top Left Of The Quad (Front)
glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Left Of The Quad (Front)
glVertex3f(1.0f, -1.0f, 1.0f); // Bottom Right Of The Quad (Front)

glColor3f(1.0f, 1.0f, 0.0f); // Set The Color To Yellow
glVertex3f(1.0f, -1.0f, -1.0f); // Bottom Left Of The Quad (Back)
glVertex3f(-1.0f, -1.0f, -1.0f); // Bottom Right Of The Quad (Back)
glVertex3f(-1.0f, 1.0f, -1.0f); // Top Right Of The Quad (Back)
glVertex3f(1.0f, 1.0f, -1.0f); // Top Left Of The Quad (Back)

glColor3f(0.0f, 0.0f, 1.0f); // Set The Color To Blue
glVertex3f(-1.0f, 1.0f, 1.0f); // Top Right Of The Quad (Left)
glVertex3f(-1.0f, 1.0f, -1.0f); // Top Left Of The Quad (Left)
glVertex3f(-1.0f, -1.0f, -1.0f); // Bottom Left Of The Quad (Left)
glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Right Of The Quad (Left)

glColor3f(1.0f, 0.0f, 1.0f); // Set The Color To Violet
glVertex3f(1.0f, 1.0f, -1.0f); // Top Right Of The Quad (Right)
glVertex3f(1.0f, 1.0f, 1.0f); // Top Left Of The Quad (Right)
glVertex3f(1.0f, -1.0f, 1.0f); // Bottom Left Of The Quad (Right)
glVertex3f(1.0f, -1.0f, -1.0f); // Bottom Right Of The Quad (Right)
// Done Drawing The Cube
glEnd();

// Increase The Rotation Variable For The Triangle
rtri += 0.2f;
// Decrease The Rotation Variable For The Quad
rquad -= 0.15f;
}


You can download the code from here.

Friday, January 26, 2007

NeHe Lesson 04: Rotation

The fourth NeHe lesson is about using the glRotate*() functions. Go read what he has to say about them here. The lesson builds on the previous one. I'll show the parts the have changed here.

First of we need to declare two need variables for the rotation.

/// Angle For The Triangle
GLfloat rtri = 0.0f;
/// Angle For The Quad
GLfloat rquad = 0.0f;

Here you must be careful with how D initializes floating point variables. For example if we had declared them like this: (Like the C-version)

/// Angle For The Triangle
GLfloat rtri;
/// Angle For The Quad
GLfloat rquad;

Then the variables would have been initialized to NaN and the triangle and the quad would not have shown on the screen at all. I've fallen for this many times, especially with these tutorials.

The drawGLScene function is the same except the calls to glRotatef and the glLoadIdentity in the middle. Try to leave it out and see what happens.

Having the variables rtri and rquad initialized to 0.0f wont do us much good if we don't change them, so there is at the end we change them slightly to archive the moving rotation effect.

/**
* The drawing function. Here we will draw the triangle and the quad.
* Now with color and rotation.
*/
void drawGLScene()
{
// Clear The Screen And The Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset The Current Modelview Matrix
glLoadIdentity();

// Move Left 1.5 Units And Into The Screen 6.0
glTranslatef(-1.5f, 0.0f, -6.0f);

// Rotate The Triangle On The Y axis
glRotatef(rtri, 0.0f, 1.0f, 0.0f);

// Drawing Using Triangles
glBegin(GL_TRIANGLES);
// Set The Color To Red
glColor3f(1.0f, 0.0f, 0.0f);
// Top
glVertex3f(0.0f, 1.0f, 0.0f);

// Set The Color To Green
glColor3f(0.0f, 1.0f, 0.0f);
// Bottom Left
glVertex3f(-1.0f, -1.0f, 0.0f);

// Set The Color To Blue
glColor3f(0.0f, 0.0f, 1.0f);
// Bottom Right
glVertex3f(1.0f, -1.0f, 0.0f);
// Finished Drawing The Triangle
glEnd();

// Reset The Current Modelview Matrix
glLoadIdentity();

// Move Right 1.5 Units And Into The Screen 6.0
glTranslatef(1.5f, 0.0f, -6.0f);

// Rotate The Quad On The X axis
glRotatef(rquad, 1.0f, 0.0f, 0.0f);

// Set The Color To Blue One Time Only
glColor3f(0.5f, 0.5f, 1.0f);

// Draw A Quad
glBegin(GL_QUADS);
// Top Left
glVertex3f(-1.0f, 1.0f, 0.0f);
// Top Right
glVertex3f(1.0f, 1.0f, 0.0f);
// Bottom Right
glVertex3f(1.0f, -1.0f, 0.0f);
// Bottom Left
glVertex3f(-1.0f, -1.0f, 0.0f);
// Done Drawing The Quad
glEnd();

// Increase The Rotation Variable For The Triangle
rtri += 0.2f;
// Decrease The Rotation Variable For The Quad
rquad -= 0.15f;
}


You can download the code from here.

NeHe Lesson 03: Adding Color

This lesson adds some color to the dark realm of OpenGL magic. Go read what the Master has to say about color incantations.

I'll show you the whole spell here for your convenience. This lesson adds directly to the previous one.


/**
* The drawing function. Here we will draw the triangle and the quad.
* Now with color.
*/
void drawGLScene()
{
// Clear The Screen And The Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset The Current Modelview Matrix
glLoadIdentity();

// Move Left 1.5 Units And Into The Screen 6.0
glTranslatef(-1.5f, 0.0f, -6.0f);

// Drawing Using Triangles
glBegin(GL_TRIANGLES);
// Set The Color To Red
glColor3f(1.0f, 0.0f, 0.0f);
// Top
glVertex3f(0.0f, 1.0f, 0.0f);

// Set The Color To Green
glColor3f(0.0f, 1.0f, 0.0f);
// Bottom Left
glVertex3f(-1.0f, -1.0f, 0.0f);

// Set The Color To Blue
glColor3f(0.0f, 0.0f, 1.0f);
// Bottom Right
glVertex3f(1.0f, -1.0f, 0.0f);
// Finished Drawing The Triangle
glEnd();

// Move Right 3 Units
glTranslatef(3.0f, 0.0f, 0.0f);

// Set The Color To Blue One Time Only
glColor3f(0.5f, 0.5f, 1.0f);

// Draw A Quad
glBegin(GL_QUADS);
// Top Left
glVertex3f(-1.0f, 1.0f, 0.0f);
// Top Right
glVertex3f(1.0f, 1.0f, 0.0f);
// Bottom Right
glVertex3f(1.0f, -1.0f, 0.0f);
// Bottom Left
glVertex3f(-1.0f, -1.0f, 0.0f);
// Done Drawing The Quad
glEnd();
}


You can download the code from here.

NeHe Lesson 02: Your First Polygon

The NeHe lesson 2 is here. There's not much new code, but the GL functions used are maybe the most important you'll ever learn when doing OpenGL coding. So I suggest if you passed the link at the beginning then don't miss is it this time. Read the tutorial. NeHe explains things so much better than I ever could. Afterwards you can marvel how similar the D version looks like. Isn't it great. :)

The only difference between the first lesson and this one is the drawing function. I'll post only it as you can go and get the first one from here and just replace the drawGLScene function.

/**
* The drawing function. Here we will draw the triangle and the quad.
*/
void drawGLScene()
{
// Clear The Screen And The Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset The Current Modelview Matrix
glLoadIdentity();

// Move Left 1.5 Units And Into The Screen 6.0
glTranslatef(-1.5f, 0.0f, -6.0f);

// Drawing Using Triangles
glBegin(GL_TRIANGLES);
glVertex3f(0.0f, 1.0f, 0.0f); // Top
glVertex3f(-1.0f, -1.0f, 0.0f); // Bottom Left
glVertex3f(1.0f, -1.0f, 0.0f); // Bottom Right
// Finished Drawing The Triangle
glEnd();

// Move Right 3 Units
glTranslatef(3.0f, 0.0f, 0.0f);

// Draw A Quad
glBegin(GL_QUADS);
glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left
glVertex3f(1.0f, 1.0f, 0.0f); // Top Right
glVertex3f(1.0f, -1.0f, 0.0f); // Bottom Right
glVertex3f(-1.0f, -1.0f, 0.0f); // Bottom Left
// Done Drawing The Quad
glEnd();
}

Don't forget to change the title of the window to "NeHe's First Polygon Tutorial (D version)". Or to something else if you feel like it.

You can download the code from here.

Thursday, January 25, 2007

A few words

I wanted to say a few words about the requirements for building the lessons from my blog. First of all I'm working on a Windows box and wont be doing very much testing on the other platforms. The code is mostly cross-platform so it should compile and run just fine on Linux or Mac OS X. I'll try to point out places where I've used platform specific code.

Next you will need the D compiler. There are two choices at the moment, the DMD from DigitalMars and GDC a GCC based compiler from here.

You also need the shared library for your platform from the SDL website.

I use Derelict for OpenGL and SDL bindings. You can grab them from there or do as I do and use DSSS, the D Shared Software System.

After that you should be ready to go.

Please note, that I'm not going to go over how you can compile a D program or the basic usage of the SDL library. For those problems there are already very good documentation on the net. Google is your friend.

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.

Introduction

So here it is. My very first blog post. Been thinking about this for a while now. Finally figured out what I could write about. I'm going to put my versions of the NeHe OpenGL tutorials, written in the D programming language, here. I will be using the SDL library for window handling and input.

I have also some other stuff which relates to D, OpenGL and games. I'll be posting about them too when I feel that I have a single module which is "good enough" to post about. Right now I have almost finished vector and matrix templates.

But now I will welcome you to my blog. Let the writing commence.