Tuesday, January 07, 2014

Useful scripts and hacks

Over the years, I've run into hundreds of little hacks/scripts/nuggets of things that I find useful.  And I have no centralized spot to store/share them.

Time to fix that!  Here, for posterity, is a list of common hacks/scripts/nuggets that I've run into and need to hold on to!

Perforce

 p4 diff -sd //branch | p4 -x -sync -f  ||| looks for missing file in //branch and force syncs them.
 p4 changes -m1 #have                   ||| run from a folder, tells you what the current changelist is.

Sunday, February 17, 2013

Archeology 101

Yesterday I was a little bored, so I started looking for a good ol' fashioned FPS to play. Of course, while digging through older CD's, I came across some old CDIS backups. And, of course, I came across, semesters worth of work. And, for me, work == old, forgotten code.

While I was digging through all that code, I found my OGDF project. It was a gaming framework that I was working on while at CDIS I was going to use for student work, as a baseline for 'hey, here's some framework code that will get you into game programming while avoiding some of the pitfalls of dealing with window resizing, switching to fullscreen/windowed mode ... you know the stuff I'm talking about in this blog now.

Some really interesting ideas in that codebase, that I'm probably going to pull forward.

But, oh my god, some awful, AWFUL ideas in there as well (Yeah, I found the Singleton Hammer1).

Anyway, one of the crazy things that I found in there was a series of articles that I wrote that eventually went on to become the lua series I wrote for Gamedev.net (shameless promotion) and were then published in 'Beginning Game Programming: A gamedev.net collection'.  It's crazy how something I wrote over 10 years ago still has an impact on folks; I still, once in a while, get questions on it.  I always intended on writing more on scripting languages (like using python, or other, alternative languages), but I could never find the time to do that.  And it's something that I don't get to spend enough time on day-to-day to become an expert on the subject.

1.The Singleton Hammer refers to any new programming/design methodology that people get tunnel vision on ... where if you only have a Hammer, everything looks like a Nail.

    Sunday, January 27, 2013

    Dev Zero - Actually getting that window on the screen - [Part 3]

    The goal this time around is to determine what we need to do in order to get a proper Window on-screen. What does it take to get a window on-screen in the land of Microsoft? Well it breaks down into a couple of API calls:

    • RegisterClassEx() to register the appropriate systems to Windows and to create a message pump to handle the OS events.
    • CreateWindow(), ShowWindow() and UpdateWindow() to actually create and show the window.
    • The actual message pump that handles all the OS events.

    So, where do we put that? Well, a fair bit of it could live in our window.cpp file, as a set of file-global vars and functions. And that would work OK. It's simple and relatively easy to read. Let's try that and see what we end up with.


    What's of note here? Well, there's a couple of things. First off, we don't end up passing into the window class any information about the HINSTANCE. Which we need to be able to register the class. But there's a little trick that works well and allows you to get the instance of the current thread:


    That, with one call, gives us everything we need to instantiate our application. However, it doesn't allow us to properly update.

    If you look at the Window::Update method, you can see that I use PeekMessage(), instead of GetMessage(). This is good, because GetMessage is a blocking call; we don't ever return until we get a message. For a game, that's bad, because we still want our application to process, even if we don't get any OS level events. However, this leaves us with havint to find a way to determine when the application has actually terminated. It's a little harder, because we have to resort to using that global s_ActiveWindow to truly determine if our application is live. But it works. And we end up with our application running and behaving as we would expect!

    This, however could be implemented in a cleaner fashion. In my next post, I'll show you how to do that.

    Note that this time around, I haven't posted any code. Mostly because this isn't a 'good' implementation. But the goal for tonight was to get a live application running (window up and visible). And we've accomplished that.

    Dev Zero - Basic Window framework [Part 1]

    Our next step is to get a proper window framework in place.  What do I mean by 'proper'?
    1. Creating an application should be trivial.  All I should need to do is ask for a window to be created (with some simple parameters), get some result back that allows me to access it.
    2. Register a callback to handle some general-case behaviours
      1. The Window has been resized.
      2. We want to change fullscreen modes (start up fullscreen, switch to windowed).
      3. Have an 'update', giving us a delta time between updates.
    3. Clean up upon closing the window.
    That, essentially, is all that I need.  But it has to happen across multiple platforms.
    So, what do I want this to look like? Pseudo code, to the rescue!


    Yes, I know. Greatly oversimplifying the process, I know. But why shouldn't it be that simple? We can add as many handlers as we need to the Window class to get our functionality.

    With that in mind, let's implement it!

    The very first thing that I want to do is generate that Window class. The problem becomes, how do I end up setting the framework up so that creating an appropriate 'MS Windows' or 'OS X' version is trivial?  The answer, surprisingly enough, is to leave it to the linker.

    Here's the deal.  We're going to define a Window class using a header file.  ALL the implementation details will be in a .CPP file.  One for Windows, one for OS X, one for what ever other platform we're interested in. We leave the details of which one to use up to the linker.  Right now, I'm going to use the development environment to set those, but we should be able to set the linker options for which file to link in via appropriate #pragma options.

    Anyway, what we've done is create a 'window.h' file inside the platform folder (wanton\source\platform). For Windows, we create a 'windows.cpp' file inside the SPECIFIC platform folder (wanton\source\platform\mswin). We then explicitly compile and link that file and voila, we end up with a transparent method of dealing with a very platform specific system. At some point in the near future, when I get an OS X version of this ready, I'll be creating an implementation of that inside the OS X folder (wanton\source\platform\osx).

    This isn't a perfect solution; it requires a lot of work in order to keep up multiple platforms. I can see using some third-party tools for generating the appropriate build files (cmake comes to mind), but you'd need something that allows you a fair degree of customizability in order to exclude folders based on the target platform. Not saying it can't be done (I know it can) but that's outside the scope of this article (for now).

    Anyway, getting back on track, this is what we have:

    platform\window.h


    I won't go into detail about the implementation of the MS Windows version of this class just yet (I haven't written it, TBH). However, you should see that I've got a new #include: delegate.h. This is a cool little library that makes adding delegates to your application fairly easily.

    What is a delegate, you may ask? Most who read my blog already know, but in case you are new, a delegate is functionally equivalent to a Function Pointer in C. But you can use methods in classes, as well as regular function pointers. And this implementation is fast. About as fast as you can get. This is courtesy of the code project: http://www.codeproject.com/Articles/13287/Fast-C-Delegate and it's a great little read. These delegates are going to allow me to create the callbacks that I mentioned earlier. You know, once I get the window class actually working!

    One other thing to mention. In getting ready for making this work across multiple platforms, I've added yet another new file to the project, a build_config.h that allows me to set on a per-platform basis, specific configuration options. Here's the contents of the file:

    build_config.h


    That should look very simple to you, until you note that I define a preprocessor define as either being 'ON' or 'OFF'. Those are defined, currently, inside util.h (until I can find a better place). It's worth it to take a look at it:

    util.h


    I like it. I like it a lot. You can find the original article at http://www.codersnotes.com/notes/easy-preprocessor-defines.
    I don't know if I would call them 'easy preprocessor defines', but I would call them 'sensible preprocessor defines'. The win in readability alone makes it totally worthwhile.

    Now that I have that generated, I've stubbed out the windows implementation. It's totally non-functional, but allows us to do a simple test.

    platform\mswin\window.cpp


    I'll be doing a proper implementation in a bit. But for now, I want to test the 'process' in getting a build actually functional.

    However, at this point in time we actually have enough to allow us to generate an app. Not a fully functional app, but something that will run without crashing. Let's put a pin in it now and actually implement our winmain function.

    wanton.cpp


    If you take the code as it stands right at this instant, with these changes, you end up with a 'functional' application that will start, update and immediately exit. Without showing a window. Yeah, that's useless, I know, but it moves us along into the next phase, which is actually getting a fully functional window on screen.

    However, at this point, I'm going to submit the code, again to have a common reference point along the tutorial.

    As with last time, you can find the code on sourceforge here: https://code.google.com/p/wanton/. HEAD will always be a work in progress. I've put the build from this blog post into R01272013B.

    Starting From Scratch - Dev Zero

    One of the things I hate the most is project set up.  I've talked about that in the past, but I want to revisit it today.  Essentially, since this is a re-start of a lot of pieces that I've done in the past, I want to clear the slate, as it was, and talk about some of the things I've learned over this long, crazy journey that has been my career.
    One thing to be clear on.  I'm not going to be working on the OSX version of this until I have the windows basic framework put to bed.  I just wanted to make that clear from the get-go.
    First things first, let's lay out our project directory structure.  To me, that's a significant issue that needs to be resolved at the beginning of any project. I'm going to follow a fairly common project layout, with some small adjustments.
    Since this is going to run across multiple platforms, I want to ensure that each platform has it's own 'solution' folder.  On Windows, we'll be using Visual Studio (2012 for now, I'll backfill into 2012 later). I suspect on Mac it'll be Xcode.  Linux will undoubtably be makefiles of some sort. So, for lack of a better term, the project is called 'Wanton'. So my folder layout will look something like this:

    I'm a firm believer that one should never check in executables; whatever you submit into you revision control system should be able to rebuild without error.  Continuous Integration servers are great for that. They can submit a numbered build elsewhere that you can grab, if need be.  That and it allows for 'verified builds' to go out to the appropriate groups.
    I went ahead and let Dev Studio create the project for me.  It puts it into it's default layout (which isn't optimal for me).  So that requires a little hand editing.  It's fairly trivial to fix up the issues that are created by hand. It does mean, however, that you've got to touch the .sln and .vcxproj files in order to have everything compile correctly.  And it's a huge pain in the ass, the first time you have to do it.  But setting this up right from the start is a huge time saver later. It also makes setting up other build types (Debug/Release) that much easier once you have a baseline to start with.
    That's it for now.  I've uploaded the current build to google code.  There's currently nothing in there that's 'interesting' aside from how the project is laid out.  You can access it here: https://code.google.com/p/wanton/.  The code relating to this post has been tagged as R01272013.  Please note that Head may not match the contents of this blog post (ergo the associated tag).  If you don't speak SVN, I recommend you pick up TortoiseSVN and read up here: http://tortoisesvn.net/docs/nightly/TortoiseSVN_en/tsvn-dug.html
    That's it for today.  I suspect I'll have the next installment ready to go shortly.  Until then, keep it between the lines.

    -Ash

    Haven't been updating like I should have.

    A couple of reasons for this, I think.  Mostly the new job, but mostly because I don't have a good, *base* set of tools to work with.

    What do I mean by that?

    I hate having to rebuild stuff from scratch.  So I've been searching for stuff to make things 'easier' to code in.  So I'll bounce back and forth bewteen C++ and C#.

    Here's the rub.  All I really want (at this point in time) is a simple windows abstraction layer.  Not 'Microsoft Windows', but a simple Windowing UI.

    To be clear, the API only has to create a window, handle resizing/fullscreen switching and be easy for me to inject an 'onUpdate' function/thread.  Everything else, I'll handle.

    So, unless anyone out there knows of a simple library out there for doing this (C++ or C#, I really don't care), I'm going to end up doing that myself.

    Sunday, January 29, 2012

    Settling into the Edmonton Way of life

    OK, so maybe that's a bit premature.  The house is still a shamble, boxes are everywhere, it's Sunday night at 10:00 but dammit, I have a home office all set up again.

    Those of you that have been following me (probably not many since my last post was ... well, let's just say that it was a while ago) know that I tend to be a bit sporadic in my posts.  I've also said in the past that I'm going to try and be a bit more prolific.  Well, with it being a new year and all that, time to see what I can do.

    So, what's gone on in the last little bit.  I've spent time in Toronto, Canada's answer to New York (apologies to New York), did my bit at Ubisoft Toronto (hey guys!) and I'm now back west-ish in Alberta.  Edmonton to be specific.  Bioware Edmonton, to be very specific.

    See, it's a long tale.  One involving friends from way back (GTez, you know who you are) and several attempts to get me out here over the period of five years.  In all honesty, I was starting to feel a little stagnant and needed a change.

    Edmonton is good.  Surprisingly so.  As in "The family mostly likes it here".  The missus is very surprised at how much she likes it.  Even though we're constantly saying "you know, it's cold, but it's not *that* cold" (trust me, -27 in Toronto is very, VERY different than -27 here).

    From my standpoint, work is very good as well.  No more 4 hour daily commutes.  Seriously.  My daily commute now is under 30 minutes. I have a shockingly large amount of free time on my hands now.

    That's where this blog comes into play.  I now see that I have time again to put towards this little endeavour.  And I think I'm going to run with it.

    I'm going to continue on with my investigation into DX11, but I also think I'm going to play around with some other ideas too.

    So, with that, I hope to see you all soon!  And Happy New Year!

    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.