These tutorials focus mainly on OpenGL, Win32 programming and the ODE physics engine. OpenGL has moved on to great heights and I don't cover the newest features but cover all of the basic concepts you will need with working example programs.

 

Working with the Win32 API is a great way to get to the heart of Windows and is just as relevant today as ever before. Whereas ODE has been marginalized as hardware accelerated physics becomes more common.

 

Games and graphics utilities can be made quickly and easily using game engines like Unity so this and Linux development in general will be the focus of my next tutorials.    

  

 

Listing of resource.h



#define IDI_ICON 101

Listing of resource.rc



#include "resource.h"



IDI_ICON ICON "icon.ico"

Listing of main.cpp



// Win32 Tutorial (Win32 & OpenGL)

// Alan Baylis 2004



#include <windows.h>

#include "resource.h"

#include <gl\gl.h>

#include <gl\glu.h>



const char ClassName[] = "MainWindowClass";

HWND hWnd;

HDC hDC;

HGLRC hRC;

RECT ScreenRect;

RECT ClientRect;

float RotateX, RotateY, RotateZ;



void SetGLProjection(int Width, int Height)

{

    if (Height == 0)                        

        Height = 1;

    glViewport(0, 0, Width, Height);                

    glMatrixMode(GL_PROJECTION);                

    glLoadIdentity();                        

    gluPerspective(45.0 ,(float)Width / (float)Height, 1.0, 200.0);

}



void SetGLView(int Width, int Height)

{

    SetGLProjection(Width, Height);

    glMatrixMode(GL_MODELVIEW);

    glLoadIdentity();

}



void InitGL(int Width, int Height)

{

    SetGLView(Width, Height);



    glCullFace(GL_BACK);

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

    glClearDepth(1.0);

    glDepthFunc(GL_LESS);

    glEnable(GL_DEPTH_TEST);

    glShadeModel(GL_SMOOTH);

    glEnable(GL_NORMALIZE);

    glEnable(GL_CULL_FACE);



    GLfloat light_ambient[] = {0.2, 0.2, 0.2, 1.0};

    glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);

    GLfloat light_position[] = {200.0, 200.0, 200.0, 1.0};

    glLightfv(GL_LIGHT0, GL_POSITION, light_position);

    glEnable(GL_LIGHTING);

    glEnable(GL_LIGHT0);



    GLfloat mat_ambient[] = {0.1, 0.5, 1.0, 1.0};

    GLfloat mat_diffuse[] = {0.1, 0.5, 1.0, 1.0};

    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);

    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);

}



void ResizeGLScene(int Width, int Height)

{

    SetGLView(Width, Height);

}



void DrawGLScene(void)

{

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);



    GLfloat light_position[] = {200.0, 200.0, 200.0, 1.0};

    glLightfv(GL_LIGHT0, GL_POSITION, light_position);



    glPushMatrix();



    glTranslatef(0.0, 0.0, -5.0);



    glRotatef(RotateX, 1, 0, 0);

    glRotatef(RotateY, 0, 1, 0);

    glRotatef(RotateZ, 0, 0, 1);



    glBegin(GL_QUADS);

    //Front Face



    glNormal3f(0.0, 0.0, 1.0);

    glVertex3f(-1.0f, -1.0f, 1.0f);

    glVertex3f( 1.0f, -1.0f, 1.0f);

    glVertex3f( 1.0f,  1.0f, 1.0f);

    glVertex3f(-1.0f,  1.0f, 1.0f);



    // Back Face



    glNormal3f(0.0, 0.0, -1.0);

    glVertex3f(-1.0f, -1.0f, -1.0f);

    glVertex3f(-1.0f,  1.0f, -1.0f);

    glVertex3f( 1.0f,  1.0f, -1.0f);

    glVertex3f( 1.0f, -1.0f, -1.0f);



    // Top Face



    glNormal3f(0.0, 1.0, 0.0);

    glVertex3f(-1.0f,  1.0f, -1.0f);

    glVertex3f(-1.0f,  1.0f,  1.0f);

    glVertex3f( 1.0f,  1.0f,  1.0f);

    glVertex3f( 1.0f,  1.0f, -1.0f);



    // Bottom Face



    glNormal3f(0.0, -1.0, 0.0);

    glVertex3f(-1.0f, -1.0f, -1.0f);

    glVertex3f( 1.0f, -1.0f, -1.0f);

    glVertex3f( 1.0f, -1.0f,  1.0f);

    glVertex3f(-1.0f, -1.0f,  1.0f);



    // Right face



    glNormal3f(1.0, 0.0, 0.0);

    glVertex3f( 1.0f, -1.0f, -1.0f);

    glVertex3f( 1.0f,  1.0f, -1.0f);

    glVertex3f( 1.0f,  1.0f,  1.0f);

    glVertex3f( 1.0f, -1.0f,  1.0f);



    // Left Face



    glNormal3f(-1.0, 0.0, 0.0);

    glVertex3f(-1.0f, -1.0f, -1.0f);

    glVertex3f(-1.0f, -1.0f,  1.0f);

    glVertex3f(-1.0f,  1.0f,  1.0f);

    glVertex3f(-1.0f,  1.0f, -1.0f);

    glEnd();



    glPopMatrix();



    RotateX += 0.1;

    RotateY += -0.2;

    RotateZ += 0.3;

}



bool CreateGLContexts(HWND hWnd, HDC& hDC, HGLRC& hRC)

{

    static PIXELFORMATDESCRIPTOR pfd;

    pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);

    pfd.nVersion = 1;

    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; 

    pfd.iPixelType = PFD_TYPE_RGBA;

    pfd.cColorBits = 16;

    pfd.cRedBits = 0;

    pfd.cRedShift = 0;

    pfd.cGreenBits = 0;

    pfd.cGreenShift = 0;

    pfd.cBlueBits = 0;

    pfd.cBlueShift = 0;

    pfd.cAlphaBits = 0;

    pfd.cAlphaShift = 0;

    pfd.cAccumBits = 0;

    pfd.cAccumRedBits = 0;

    pfd.cAccumGreenBits = 0;

    pfd.cAccumBlueBits = 0;

    pfd.cAccumAlphaBits = 0;

    pfd.cDepthBits = 16;

    pfd.cStencilBits = 0;

    pfd.cAuxBuffers = 0;

    pfd.iLayerType = PFD_MAIN_PLANE;

    pfd.bReserved = 0;

    pfd.dwLayerMask = 0;

    pfd.dwVisibleMask = 0;

    pfd.dwDamageMask = 0;



    hDC = GetDC(hWnd);



    intPixelFormat;

    PixelFormat = ChoosePixelFormat(hDC, &pfd);



    if (!PixelFormat)

    {

        MessageBox(0, "Can't Find A Suitable PixelFormat.", "Error", MB_OK | MB_ICONERROR);

        return FALSE;

    }



    if(!SetPixelFormat(hDC, PixelFormat, &pfd))

    {

        MessageBox(0, "Can't Set The PixelFormat.", "Error", MB_OK | MB_ICONERROR);

        return FALSE;

    }



    hRC = wglCreateContext(hDC);



    if(!hRC)

    {

        MessageBox(0, "Can't Create A GL Rendering Context.", "Error", MB_OK | MB_ICONERROR);

        return FALSE;

    }



    if(!wglMakeCurrent(hDC, hRC))

    {

        MessageBox(0, "Can't activate GLRC.", "Error", MB_OK | MB_ICONERROR);

        return FALSE;

    }



    return TRUE;

}



void ReleaseGLContexts(HWND hWnd, HDC hDC, HGLRC hRC)

{

    ChangeDisplaySettings(NULL, 0);

    wglMakeCurrent(hDC, NULL);

    wglDeleteContext(hRC);

    ReleaseDC(hWnd, hDC);

}



LRESULT CALLBACK WndProc( HWND    hWnd,

                          UINT    Msg,

                          WPARAM  wParam,

                          LPARAM  lParam )

{

    switch (Msg)

    {

        case WM_CREATE:

            if (CreateGLContexts(hWnd, hDC, hRC))

            {

                GetClientRect(hWnd, &ClientRect);

                InitGL(ClientRect.right, ClientRect.bottom);

            }

            else

                PostQuitMessage(0);

        break;



        case WM_KEYDOWN: 

            switch (wParam)

            {

                case VK_ESCAPE:

                case VK_RETURN:

                case VK_SPACE:

                    SendMessage(hWnd, WM_CLOSE, 0, 0);

                break;

            }

        break;



        case WM_SIZE:

            GetClientRect(hWnd, &ClientRect);

            ResizeGLScene(ClientRect.right, ClientRect.bottom);

        break;



        case WM_CLOSE:

            ReleaseGLContexts(hWnd, hDC, hRC);

            DestroyWindow(hWnd);

        break;



        case WM_DESTROY:

            PostQuitMessage(0);

        break;



        default:

            return (DefWindowProc(hWnd, Msg, wParam, lParam));

    }

    return (0);

}



INT WINAPI WinMain( HINSTANCE  hInstance,

                    HINSTANCE  hPrevInstance,

                    LPSTR      lpCmdLine,

                    INT        nCmdShow )

{

    WNDCLASSEX    wc;



    wc.cbSize           = sizeof(WNDCLASSEX);

    wc.style            = 0;

    wc.lpfnWndProc      = (WNDPROC)WndProc;

    wc.cbClsExtra       = 0;

    wc.cbWndExtra       = 0;

    wc.hInstance        = hInstance;

    wc.hIcon            = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));

    wc.hIconSm          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));

    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);

    wc.hbrBackground    = (HBRUSH)(COLOR_WINDOW + 1);

    wc.lpszMenuName     = NULL;

    wc.lpszClassName    = ClassName;



    if (!RegisterClassEx(&wc))

    {

        MessageBox(NULL, "Failed To Register The Window Class.", "Error", MB_OK | MB_ICONERROR);

        return 0;

    }



    GetWindowRect(GetDesktopWindow(), &ScreenRect);



    hWnd = CreateWindowEx(

    0,

    ClassName,

    "Win32 & OpenGL",

    WS_OVERLAPPEDWINDOW,

    (ScreenRect.right - 500) / 2 , (ScreenRect.bottom - 500) / 2,

    500, 500,

    NULL,

    NULL,

    hInstance,

    NULL);



    if (!hWnd)

    {

        MessageBox(NULL, "Window Creation Failed.", "Error", MB_OK | MB_ICONERROR);

        return 0;

    }



    ShowWindow(hWnd, SW_SHOW);

    UpdateWindow(hWnd);



    MSG Msg;



    while (1)

    {

        while (PeekMessage(&Msg, NULL, 0, 0, PM_NOREMOVE))

        {

            if (GetMessage(&Msg, NULL, 0, 0))

            {



                TranslateMessage(&Msg);

                DispatchMessage(&Msg);

            }

            else

            {

                return Msg.wParam;

            }

        }



        DrawGLScene();

        glFinish();

        SwapBuffers(hDC);

    }

}