Sunday, September 18, 2011

Walking The Graphics Pipeline - Part 1


There once was a time, many, many years ago that I was very, very versed in the language of rendering programmers.  That was many moons ago (talking 2004 here … pre DirectX 9b days).  I’ve only been marginally keeping up, so when people talk about deferred renderers, I know what they’re talking about from a purely theoretical level.

I’m tired of only understanding it from a theoretical level.  So I’m going to be taking the next couple of months to get my chops up to snuff.  And I thought I’d take you all along for the ride.

I’m going to be focusing on DirectX 11 for the majority of these articles.  It’s new and whiz-bangy.  It’s not particularly useful when it comes to things like Xbox development, but it is the ‘next’ gen api.  I’m also not going to talk about OpenGL here, simply because I want to keep my focus on one thing.  I will probably approach OpenGL in a later post.

So, where to start?  I’m tempted to use the DirectX sample framework as it gives us a *lot* to work with.  I’m not going to use their wrapper for DirectX, as that defeats the purpose of this exercise. As well, all dev will be running in both x86 and x64 modes.

For now, this will be a simple Windows app.  Nothing fancy here.  So, putting a window up on screen looks like this, in straight C/C++:



// wtgp_01.cpp : An simple application base.
// We are doing nothing at this point in time aside from
// displaying a window.
//  x86 and x64 support.
//

#include "stdafx.h"

HINSTANCE	g_hInst = NULL;
HWND		g_hWnd	= NULL;

//==============================================
// TODO:
//   Eventually move this off into a separate utility library
//   We output any caught memory leaks here.
#if defined(DEBUG) || defined(_DEBUG)
#include "crtdbg.h"
#endif
//==============================================

#include "wtgp_01.h"

//--------------------------------------------------------------------------------------
// Forward declarations
//--------------------------------------------------------------------------------------
HRESULT InitWindow( HINSTANCE _instance, int _cmdShow );
LRESULT CALLBACK    WndProc( HWND, UINT, WPARAM, LPARAM );

int APIENTRY _tWinMain(HINSTANCE _instance, HINSTANCE _prevInstance, LPTSTR _cmdLine, int _cmdShow)
{
	UNREFERENCED_PARAMETER(_prevInstance);
	UNREFERENCED_PARAMETER(_cmdLine);

	// Enable run-time memory check for debug builds.
	// Again, this should live in a separate library
#if defined(DEBUG) | defined(_DEBUG)
	_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

	if( FAILED( InitWindow( _instance, _cmdShow ) ) )
	{
		return 0;
	}

	// Main message loop
	MSG msg = {0};
	while( WM_QUIT != msg.message )
	{
		if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
		{
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}
	}

	return ( int )msg.wParam;
}

//--------------------------------------------------------------------------------------
// Register class and create window
//--------------------------------------------------------------------------------------
HRESULT InitWindow( HINSTANCE _instance, int _cmdShow )
{
	// Register class
	WNDCLASSEX wcex;
	wcex.cbSize = sizeof( WNDCLASSEX );
	wcex.style = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc = WndProc;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = _instance;
	wcex.hIcon = LoadIcon( _instance, ( LPCTSTR )IDI_WTGP_01 );
	wcex.hCursor = LoadCursor( NULL, IDC_ARROW );
	wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 );
	wcex.lpszMenuName = NULL;
	wcex.lpszClassName = L"WTGTP_01";
	wcex.hIconSm = LoadIcon( wcex.hInstance, ( LPCTSTR )IDI_WTGP_01 );
	if( !RegisterClassEx( &wcex ) )
	{
		return E_FAIL;
	}

	// Create window
	g_hInst = _instance;
	RECT rc = { 0, 0, 800, 600 };
	AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE );
	g_hWnd = CreateWindow( L"WTGTP_01", L"Walking The Graphics Pipeline - 01", WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, _instance,
		NULL );
	if( !g_hWnd )
	{
		return E_FAIL;
	}

	ShowWindow( g_hWnd, _cmdShow );

	return S_OK;
}


//--------------------------------------------------------------------------------------
// Called every time the application receives a message
//--------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc( HWND _hWnd, UINT _msg, WPARAM _wParam, LPARAM _lParam )
{
	PAINTSTRUCT ps;
	HDC hdc;

	switch( _msg )
	{
	case WM_PAINT:
		hdc = BeginPaint( _hWnd, &ps );
		EndPaint( _hWnd, &ps );
		break;

	case WM_DESTROY:
		PostQuitMessage( 0 );
		break;

	default:
		return DefWindowProc( _hWnd, _msg, _wParam, _lParam );
	}

	return 0;
}


Simple straightforward Win32/64 app.  Nothing extravagant in it, but it’s a plain-jane starting point. Where I’ve spent most of my time on this so far is just setting up the project to put all the resultant and intermediate files into to the correct locations.  This isn’t hard to do, it just takes a while to set up right.  


As it now stands, all binary files (exes, compiled media files, etc) will live in a ‘bin’ folder at the same level as the solution.  


Inside of each project, there will be a ‘tmp’ folder where all temporary files (obj, manifest, build logs) will go.


For your convenience, I've uploaded the source to the project here: wtgp-build_001.rar


Shortly, I'll be adding some actual graphics to this project.  Stay tuned!

No comments: