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.