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!

Saturday, April 30, 2011

New Computer time

My Dad is one of the most awesome people around. After the move to Toronto, the movers completely wrecked my home computer. So, for the last little bit I've been without a computer (the funds from insurance weren't enough to actually replace the computer).

However, that's no longer the case. Awesomeness prevails:

Yep!  That's a new laptop sitting in my home studio. Additionally, I took the hardly used Sony TV and made it my Main monitor.

Surprisingly enough, it's like having a wall of monitor to look at.  And at 1080p, it's actually really easy to work with.  Not actually sure how I'm going to go back to work on Monday and look at a 17" monitor again.

Oh, and hopefully a bunch of new posts should be coming in shortly!  Stay tuned.

-Ash

Sunday, March 13, 2011

Custom Build sounds in Dev Studio 2008

Matthieu St. Pierre, one of the rendering coders at work, forwarded this to me at work. So I thought I'd share. It's a sweet piece of code that allows you to customize your build results to play a custom sound when your build is a success or when it fails. It's pretty damn cool and completely open to customization. So without further ado:
  1. Open up Tools | Macro | Macro IDE menu item
  2. Double-click the “MyMacros” project in the Project Explorer, and double-click the “EnvironmentEvents” item to show that module
  3. Copy and paste the code below into the macro editor window
  4. Put it right above the End Module declaration
  5. Once you have added the code, save the module and try to build something. If you don't hear anything, you may not have any sounds defined for the “Build Failed” and “Build Succeeded” events in the “Sounds and Audio Devices Properties” control panel.
   
Public bBuildErr As Boolean = False
Public iCnt As Integer = 0

' The DLL Import that plays the sounds
Declare Function sndPlaySound Lib "winmm.dll" _
   Alias "sndPlaySoundA" (ByVal lpszSoundName As String, _
   ByVal uFlags As Long) As Long

' A convenience method to play the sound
Private Sub PlaySound(ByVal sSoundFile As String)
   'Play async, ignore file not found
   sndPlaySound(sSoundFile, &H1 Or &H2 Or &H20000)
End Sub

Private Sub BuildEvents_OnBuildDone(ByVal Scope As EnvDTE.vsBuildScope, ByVal Action As EnvDTE.vsBuildAction) Handles BuildEvents.OnBuildDone
   Dim sSound As String

   If iCnt > 0 Then
       If bBuildErr Then
           sSound = My.Computer.Registry.GetValue( _
               "HKEY_CURRENT_USER\AppEvents\Schemes\Apps\devenv\VS_BuildFailed\.current", _
               "", "").ToString()
       Else
           sSound = My.Computer.Registry.GetValue( _
               "HKEY_CURRENT_USER\AppEvents\Schemes\Apps\devenv\VS_BuildSucceeded\.current", _
               "", "").ToString()
       End If
       PlaySound(sSound)
   End If
   bBuildErr = False
   iCnt = 0
End Sub

Private Sub BuildEvents_OnBuildProjConfigDone(ByVal Project As String, _
                                       ByVal ProjectConfig As String, ByVal Platform As String, ByVal SolutionConfig As String, _
                                       ByVal Success As Boolean) Handles BuildEvents.OnBuildProjConfigDone
   iCnt += 1
   If Not Success Then
       bBuildErr = True
   End If
End Sub
That's it! Simple and easy to install and use.