Windows XP SATA Installation

May 2nd, 2008

I’ve just had the worst time trying to install Windows XP on a new laptop.

If your PC has a SATA drive and when you install XP it cant find it, your motherboard probably has inbuilt SATA drivers. Try turning them off or to “Compatibility” mode, then XP will see your drive.

Sidescroll 2 - Double Buffer

April 29th, 2008

A double buffer is a technique to smooth out the animations and graphics as they are displayed to the screen.

This is needed because if we were drawing directly to the screen it would be something like this:

  • 1. Blank the screen
  • 2. Draw player graphic to the screen
  • 3. Draw enemy 1 to the screen
  • 4. Draw enemy 2 to the screen
  • 5. etc.
  • 6. start again

Because of this, our eye is fast enough to see the gap between when we blank the screen and when the individual graphics are drawn, and it results in a flickery image.

If we used double buffering it would go like this:

  • 1. Blank the buffer
  • 2. Draw player graphic to the buffer
  • 3. Draw enemy 1 to the buffer
  • 4. Draw enemy 2 to the buffer
  • 5. etc.
  • 6. Copy the entire buffer to the screen in one go
  • 7. Start again

So all of the graphics are put together off screen, just in memory. Because we never actually blank the screen (only the buffer), our eye isn’t quick enough to notice the difference of the two images, and it appears like a moving image.

To make things easier I use a data structure and a couple of functions to handle all of the buffering (I think they came from a tutorial, and I modified them to suit my needs).

First is the data structure to hold all of the buffer info:

struct DBUFFER{
        HWND windowHwnd;
        HDC windowDc;
        HDC bufferDc;
        HBITMAP bufferBitmap;
        HBITMAP unloadBufferBitmap;
        RECT rect;
};

Then we declare our functions for loading and unloading the buffer:

bool initDoubleBuffer(DBUFFER &doubleBuffer);
void freeDoubleBuffer(DBUFFER &doubleBuffer);

initDoubleBuffer()

bool initDoubleBuffer(DBUFFER &doubleBuffer){
        if(!doubleBuffer.windowHwnd){
                return false;
        }

        GetClientRect(doubleBuffer.windowHwnd,&doubleBuffer.rect);
        doubleBuffer.windowDc = GetDC(doubleBuffer.windowHwnd);

        if(doubleBuffer.windowDc == NULL){
                return false;
        }

        doubleBuffer.bufferDc = CreateCompatibleDC(doubleBuffer.windowDc);

        if(doubleBuffer.bufferDc == NULL){
                return false;
        }

        doubleBuffer.bufferBitmap = CreateCompatibleBitmap(
                doubleBuffer.windowDc,
                doubleBuffer.rect.right,
                doubleBuffer.rect.bottom);

        if(doubleBuffer.bufferBitmap == NULL){
                return false;
        }

        doubleBuffer.unloadBufferBitmap = (HBITMAP)SelectObject(
                doubleBuffer.bufferDc,
                doubleBuffer.bufferBitmap);

        return true;
}

freeDoubleBuffer()

void freeDoubleBuffer(DBUFFER &doubleBuffer){
        if(!doubleBuffer.windowHwnd){
                return;
        }
        if(doubleBuffer.unloadBufferBitmap){
                SelectObject(doubleBuffer.bufferDc,
                        doubleBuffer.unloadBufferBitmap);
                DeleteObject(doubleBuffer.bufferBitmap);
                DeleteDC(doubleBuffer.bufferDc);
        }
        if(doubleBuffer.windowDc){
                ReleaseDC(doubleBuffer.windowHwnd,
                        doubleBuffer.windowDc);
        }
        memset(&doubleBuffer,0,sizeof(DBUFFER));
}

Now we can actually call the buffer into existence, right after we create our window, and before the main loop:

DBUFFER doubleBuffer;
doubleBuffer.windowHwnd = hwnd;
if(!initDoubleBuffer(doubleBuffer)){
        return EXIT_FAILURE;
}
HDC tempDc = CreateCompatibleDC(doubleBuffer.windowDc);
if(!tempDc){
        return EXIT_FAILURE;
}

And make sure we unload it, after the main loop:

freeDoubleBuffer(doubleBuffer);

So heres the code all together so far:

#include <windows.h>
#include <iostream>

#define WINDOW_NAME "sidescroll"
#define WINDOW_TITLE "Sidescroll Game"
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600

struct DBUFFER{
        HWND windowHwnd;
        HDC windowDc;
        HDC bufferDc;
        HBITMAP bufferBitmap;
        HBITMAP unloadBufferBitmap;
        RECT rect;
};

bool initDoubleBuffer(DBUFFER &doubleBuffer);
void freeDoubleBuffer(DBUFFER &doubleBuffer);

LRESULT CALLBACK WinProc(
        HWND hwnd,
        UINT message,
        WPARAM wparam,
        LPARAM lparam);

int WINAPI WinMain(
        HINSTANCE hinstance,
        HINSTANCE hprev,
        PSTR cmdline,
        int ishow){

        HWND hwnd;
        MSG msg;
        WNDCLASSEX wndclassex = {0};

        wndclassex.cbSize = sizeof(WNDCLASSEX);
        wndclassex.style = CS_HREDRAW | CS_VREDRAW;
        wndclassex.lpfnWndProc = WinProc;
        wndclassex.hInstance = hinstance;
        wndclassex.lpszClassName = WINDOW_NAME;
        wndclassex.hCursor = (HCURSOR)LoadImage(
                NULL,
                MAKEINTRESOURCE(IDC_ARROW),
                IMAGE_CURSOR,
                0, 0, LR_SHARED);

        RegisterClassEx(&wndclassex);

        hwnd = CreateWindowEx(
                NULL,
                WINDOW_NAME,
                WINDOW_TITLE,
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                WINDOW_WIDTH,
                WINDOW_HEIGHT,
                NULL,
                NULL,
                hinstance,
                NULL);

        if(!hwnd){
                return EXIT_FAILURE;
        }

        DBUFFER doubleBuffer;
        doubleBuffer.windowHwnd = hwnd;
        if(!initDoubleBuffer(doubleBuffer)){
                return EXIT_FAILURE;
        }
        HDC tempDc = CreateCompatibleDC(doubleBuffer.windowDc);
        if(!tempDc){
                return EXIT_FAILURE;
        }

        ShowWindow(hwnd, ishow);
        UpdateWindow(hwnd);

        while(1){
                if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
                        if(msg.message == WM_QUIT){
                                break;
                        }
                        TranslateMessage(&msg);
                        DispatchMessage(&msg);
                }
        }

        freeDoubleBuffer(doubleBuffer);

        return 0;
}

LRESULT CALLBACK WinProc(
        HWND hwnd,
        UINT message,
        WPARAM wparam,
        LPARAM lparam){

        PAINTSTRUCT ps;
        switch(message){
                case WM_PAINT:
                        BeginPaint(hwnd,&ps);
                        EndPaint(hwnd,&ps);
                        return 0;
                case WM_DESTROY:
                        PostQuitMessage(0);
                        return 0;
        }
        return DefWindowProc(hwnd, message, wparam, lparam);
}

bool initDoubleBuffer(DBUFFER &doubleBuffer){
        if(!doubleBuffer.windowHwnd){
                return false;
        }

        GetClientRect(doubleBuffer.windowHwnd,&doubleBuffer.rect);
        doubleBuffer.windowDc = GetDC(doubleBuffer.windowHwnd);

        if(doubleBuffer.windowDc == NULL){
                return false;
        }

        doubleBuffer.bufferDc = CreateCompatibleDC(doubleBuffer.windowDc);

        if(doubleBuffer.bufferDc == NULL){
                return false;
        }

        doubleBuffer.bufferBitmap = CreateCompatibleBitmap(
                doubleBuffer.windowDc,
                doubleBuffer.rect.right,
                doubleBuffer.rect.bottom);

        if(doubleBuffer.bufferBitmap == NULL){
                return false;
        }

        doubleBuffer.unloadBufferBitmap = (HBITMAP)SelectObject(
                doubleBuffer.bufferDc,
                doubleBuffer.bufferBitmap);

        return true;
}

void freeDoubleBuffer(DBUFFER &doubleBuffer){
        if(!doubleBuffer.windowHwnd){
                return;
        }
        if(doubleBuffer.unloadBufferBitmap){
                SelectObject(doubleBuffer.bufferDc,
                        doubleBuffer.unloadBufferBitmap);
                DeleteObject(doubleBuffer.bufferBitmap);
                DeleteDC(doubleBuffer.bufferDc);
        }
        if(doubleBuffer.windowDc){
                ReleaseDC(doubleBuffer.windowHwnd,
                        doubleBuffer.windowDc);
        }
        memset(&doubleBuffer,0,sizeof(DBUFFER));
}

Sidescroll 1 - Window

April 24th, 2008

First things first, you have to have a window to play your game in. I’ve stuffed around a little bit with win32 when I did a bit of OpenGL so I still had a few tutorials that I had done and just stole the window code from that.

So here is how I make a window in c++.

Start by including the win32 functions and standard I/O functions:

#include <windows.h>
#include <iostream>
 

Essentially to make a window you need only a couple of things:

  • window name
  • window title
  • width
  • height

So we can start by declaring these into some variables:

#define WINDOW_NAME "sidescroll"
#define WINDOW_TITLE "Sidescroll Game"
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
 

Next we need to declare the function thats going to handle the window events:

LRESULT CALLBACK WinProc(
        HWND hwnd,
        UINT message,
        WPARAM wparam,
        LPARAM lparam);

We’ll use that later.

Now when you’re dealing with windows you don’t use the normal Main() function, instead its just WinMain():

int WINAPI WinMain(
        HINSTANCE hinstance,
        HINSTANCE hprev,
        PSTR cmdline,
        int ishow){

}

Thats the function thats going to get called when you run the program, so we want it to spawn our window:

int WINAPI WinMain(
        HINSTANCE hinstance,
        HINSTANCE hprev,
        PSTR cmdline,
        int ishow){

        HWND hwnd;
        MSG msg;
        WNDCLASSEX wndclassex = {0};

        wndclassex.cbSize = sizeof(WNDCLASSEX);
        wndclassex.style = CS_HREDRAW | CS_VREDRAW;
        wndclassex.lpfnWndProc = WinProc;
        wndclassex.hInstance = hinstance;
        wndclassex.lpszClassName = WINDOW_NAME;
        wndclassex.hCursor = (HCURSOR)LoadImage(
                NULL,
                MAKEINTRESOURCE(IDC_ARROW),
                IMAGE_CURSOR,
                0, 0, LR_SHARED);

        RegisterClassEx(&wndclassex);

        hwnd = CreateWindowEx(
                NULL,
                WINDOW_NAME,
                WINDOW_TITLE,
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                WINDOW_WIDTH,
                WINDOW_HEIGHT,
                NULL,
                NULL,
                hinstance,
                NULL);

        if(!hwnd){
                return EXIT_FAILURE;
        }

        ShowWindow(hwnd, ishow);
        UpdateWindow(hwnd);

        return 0;
}

Thats going to spawn an empty window, but we need it to react to events, like when we ask it to close. So we use the following loop to check for these events, just before the return of our WinMain() function:

while(1){
        if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
                if(msg.message == WM_QUIT){
                        break;
                }
                TranslateMessage(&msg);
                DispatchMessage(&msg);
        }
}

Now we need to put in that WinProc() function to deal with the events:

LRESULT CALLBACK WinProc(
        HWND hwnd,
        UINT message,
        WPARAM wparam,
        LPARAM lparam){

        PAINTSTRUCT ps;
        switch(message){
                case WM_PAINT:
                        BeginPaint(hwnd,&ps);
                        EndPaint(hwnd,&ps);
                        return 0;
                case WM_DESTROY:
                        PostQuitMessage(0);
                        return 0;
        }
        return DefWindowProc(hwnd, message, wparam, lparam);
}

And that’s it, we now have a working window. heres the whole code:

#include <windows.h>
#include <iostream>

#define WINDOW_NAME "sidescroll"
#define WINDOW_TITLE "Sidescroll Game"
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600

LRESULT CALLBACK WinProc(
        HWND hwnd,
        UINT message,
        WPARAM wparam,
        LPARAM lparam);

int WINAPI WinMain(
        HINSTANCE hinstance,
        HINSTANCE hprev,
        PSTR cmdline,
        int ishow){

        HWND hwnd;
        MSG msg;
        WNDCLASSEX wndclassex = {0};

        wndclassex.cbSize = sizeof(WNDCLASSEX);
        wndclassex.style = CS_HREDRAW | CS_VREDRAW;
        wndclassex.lpfnWndProc = WinProc;
        wndclassex.hInstance = hinstance;
        wndclassex.lpszClassName = WINDOW_NAME;
        wndclassex.hCursor = (HCURSOR)LoadImage(
                NULL,
                MAKEINTRESOURCE(IDC_ARROW),
                IMAGE_CURSOR,
                0, 0, LR_SHARED);

        RegisterClassEx(&wndclassex);

        hwnd = CreateWindowEx(
                NULL,
                WINDOW_NAME,
                WINDOW_TITLE,
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                WINDOW_WIDTH,
                WINDOW_HEIGHT,
                NULL,
                NULL,
                hinstance,
                NULL);

        if(!hwnd){
                return EXIT_FAILURE;
        }

        ShowWindow(hwnd, ishow);
        UpdateWindow(hwnd);

        while(1){
                if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
                        if(msg.message == WM_QUIT){
                                break;
                        }
                        TranslateMessage(&msg);
                        DispatchMessage(&msg);
                }
        }

        return 0;
}

LRESULT CALLBACK WinProc(
        HWND hwnd,
        UINT message,
        WPARAM wparam,
        LPARAM lparam){

        PAINTSTRUCT ps;
        switch(message){
                case WM_PAINT:
                        BeginPaint(hwnd,&ps);
                        EndPaint(hwnd,&ps);
                        return 0;
                case WM_DESTROY:
                        PostQuitMessage(0);
                        return 0;
        }
        return DefWindowProc(hwnd, message, wparam, lparam);
}

Sidescroll Project

April 24th, 2008

I was playing Darius Twin (old SNES game) the other night with a mate and remembered just how much fun these sort of games were. I had previously had a stab at making one a few years ago in VB6, but have long since lost all the files and code.

I got inspired to have another go, and this time to code it in a real language, like C.

Now I’ve never been great with C++, I can muddle though and usually hack something together, but being so used to PHP and the great things it can do with arrays and such, I usually end up wanting to kill myself by the end of it.

So this project represents the opportunity to brush up my skills and produce something actually half cool.

I’ll be posting some bits and pieces about what I’ve done so far, and then keep updated on progress.

New Blog

April 24th, 2008

Wow, so this is my new blog.

I haven’t had a blog (or even a personal site) for the longest time now, and I decided that its probably time to get arse moving and get one up.

It’ll probably become home to various projects, such as half finished programming stuff, and just general nonsense.