Real-Time Software Renderer, all from scratch

C++, GDI BitBlt, and nothing else! – under current development

Strong graphics knowledge must be built from a strong foundation, and I could think of no better way to learn the entire graphics pipeline than to implement everything from scratch. My real time software renderer uses no graphics library, no math library, and only the lowest level of the win32 API to blit device independent bitmaps to the screen.

The current build of the software renderer supports OBJ model loading with flat, gouraud, and phong shading. N number of directional lights are supported as well as a prerender depth buffer pass.

Currently the rendering pipeline is being restructured to become a true multithreaded lockless deferred software renderer.

the Stanford Dragon

in the wild

the Stanford Bunny

the Current Build

the Glorious Code – snippet

Just a taste

void cs580::Display::drawBitmap(
    const HDC& hdc, const HBITMAP& bitmap,
    const unsigned int* const frame_buffer ) const
    HDC const new_hdc = CreateCompatibleDC(hdc);
    HBITMAP const old_bitmap = (HBITMAP)SelectObject(new_hdc, bitmap);

    SetDIBits(new_hdc, bitmap, 0, height_, frame_buffer, bitmap_info_, DIB_RGB_COLORS);

    if (show_text_){
        if (show_fps_)

        for(unsigned int i = 0; i < display_text_.size(); i++){
            text_info info = display_text_[i];
            drawText(new_hdc, info.x, info.y, info.text);

    BitBlt(hdc, 0, 0, width_, height_, new_hdc, 0, 0, SRCCOPY);

    SelectObject(new_hdc, old_bitmap);

const int cs580::Display::newDIB(
    HDC hdc, HBITMAP* dib_bitmap, BITMAPINFO** bitmap_info,
    const int width, const int height )
    void* pvBits;

    //BITMAPINFO bitmap_info;
    (*bitmap_info) = new BITMAPINFO();
    ZeroMemory(&(*bitmap_info)->bmiHeader, sizeof(BITMAPINFOHEADER));
    (*bitmap_info)->bmiHeader.biWidth = width;
    (*bitmap_info)->bmiHeader.biHeight = -height;
    (*bitmap_info)->bmiHeader.biPlanes = 1;
    (*bitmap_info)->bmiHeader.biBitCount = 32;
    (*bitmap_info)->bmiHeader.biCompression = BI_RGB;
    (*bitmap_info)->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);

    (*dib_bitmap) = CreateDIBSection(hdc, (*bitmap_info),
        DIB_RGB_COLORS, &pvBits, NULL, 0);

    return 0;

const int cs580::Display::freeDIB( HBITMAP* bitmap )
    if (!(*bitmap))
        return -1;

    (*bitmap) = NULL;

    return 0;