Pages

Tuesday, May 31, 2011

Class and Function Name Stylings

While designing frameworks and systems, class and function names are important to identify what the code is doing, but these names are often purposeful and inherently dry.

I've  slowly been changing my naming style in favour of common fantasy terminology to help keep the mindset of a Creator of Worlds and Forger of Lore. Here are some examples:

  • "EntityFactory"->"EntityForge",  
  • "SpriteManager"->"SpriteOverseer", 
  • "Enemy.Initialize()"->"Enemy.GiveBreadth()"

This is certainly fun, but it's an extra step to find a suitable name and it's important to avoid names that would be overly confusing. For example "AnimationController" helps "give life" to your characters (by animating them), but "LifeGiver" would be fantastically vague name.

Sunday, May 22, 2011

Gui for Game Dev Tools - IupLua

While designing tools for Elpis, I found the need for a more robust set of GUI controls than my game-tuned HUDish controls. There were several choices that I had to chose from:

  1. Use straight up, hand crafted, Win32 code
  2. Enhance Elpis' GUI to support tools
  3. Wrap Elpis with COM and load it up in C# or similar
  4. Use an existing library that interfaces through Lua
Naturally, I opted for #4. Interfacing through Lua means that the Elpis core doesn't have to know about a GUI at all, and there's no need to recompile.

Library, The Chosen 
Now came time to find, try, and chose a library. I was hoping that I would get a chance to play around with a bunch of new and cool libraries, though the ones I wanted to try had license limitations, did not use native controls (a finicky requirement), or did not interface with Lua.

The two libraries that were left of my choices were wxWidgets and IUP, and both of these shipped with Lua for Windows binaries. Of these, I chose IUP with IupLua binding for subjective reasons, in that I preferred the interface and IUP is focused on GUI functionality alone.

Usage Example
Assuming iup51.dll and iuplua51.dll are available to Lua's CPath, a simple require("iuplua") in Lua, and IUP will be accessible to you through the global iup object.

IUP comes with many many samples to show it's use, but one thing I struggled with was to use Elpis' existing Win32 Window as the parent for new controls. I shot a quick question to the user-list to find out if this was possible, and as it turns out, this is very easy for IUP dialogs...


Here is an example of a dialog with a menu used with Elpis:

local item_exit = iup.item{title = "E&xit", action=function() return iup.CLOSE end}
local item_open = iup.item{title = "&Open", action=OpenFile_OnClick}
local item_save = iup.item{title = "&Save", action=nil, active="NO"}
local function InitializeUI()

 menu = iup.menu
 {
  iup.submenu
  {
   iup.menu
   {
    item_open,
    item_save,
    {},
    item_exit
   };
   title = "File"
  };
 }

 mainDlg = iup.dialog
 {
  iup.vbox
  {

  };
  title="Volumetric Marker Generator", font="Helvetica, Bold 14", menu = menu,
  size="100x15",
  toolbox="YES",
  maxbox="NO",
  minbox="NO",
  resize="NO"
 }
 iup.SetAttribute(mainDlg, "NATIVEPARENT", gSystem.HWND);
 mainDlg:showxy(250,90)
end

The line to note is line 34: iup.SetAttribute(mainDlg, "NATIVEPARENT", gSystem.HWND);
This tells IUP to use gSystem.HWND (which returns Elpis' main hWnd) as the parent for the dialog mainDlg.
Retrieving the HWND is as simple as lua_pushlightuserdata(L, mainHwnd) from C++.

Sunday, May 8, 2011

Forcing DLLs into submission - Delay Loaded DLLs

When I wish to run Elpis outside of my IDE, the executable can be found in the debug directory...but it's likely that I won't find it in time for the holidays. There are far too many files exported to that directory!

Now, this wasn't an issue before, and by before I mean a year ago when I had less than 3 DLLs exported. I now have 19 dlls and for each of those DLLs, there are four more files associated to it: *.ilk, *.lib, *.pdb, and *.exp.
That's 76 files to look through for that damned exe! (Not including other debug exports, test project executables, folders, etc...)

The Deadend
Obviously, the solution is to separate the *.exe's from the DLLs. Oh, but wait... hold on a sec... I have a feeling this might not be so straight forward.

On application launch, Windows searches the following directories for the DLLs needed:
  1. The directory where the executable module for the current process is located.
  2. The current directory.
  3. The Windows system directory. The GetSystemDirectory function retrieves the path of this directory.
  4. The Windows directory. The GetWindowsDirectory function retrieves the path of this directory.
  5. The directories listed in the PATH environment variable.
Copy-Paste from MSDN

Ok, so I can't just set the DLL search directory without setting a path variable? Gross! I might have to use LoadLibrary and GetProcAddress for each of my functions/methods. That breaks my heart because Elpis has quite a few methods to export/import. How tedious.

So now what? I guess quitting is always an option, maybe give up my life as a programmer all-together and take up dancing as a strategic career move!

The Saving Grace(s)
As invigorating as that all sounds, I've found a convenient solution. The solution entered my life, and my dream to dance fluttered away.

SetDllDirectory

Obvious in its intention, SetDllDirectory allows you to set a relative or absolute path to search for Dlls (only one path can be set at a time).  So now, we could set the directory at runtime BUT, the DLLs are loaded long before even the main is reached.

Not a problem: A nice feature that was added to VC6 (so, not new) was the option to delay the loading of a DLL until it is first called. All you need to do to use delayed load is to configure the executable project a little bit.

Configs
On the executable project in Visual studio

Navigate to  Project Properties->Linker
1. Add Delayimp.lib; to "Additional Dependencies"
(This is library provided by Mr. Microsoft, and contains the functionality to delay loading)

2. Add all delayed DLLs to "Delay Loaded DLLs"

3. Make sure that nothing in the DLLs are touched until the SetDllDirectory is called (this includes instantiation of objects defined in the DLL)

And that is that. Elpis DLLs can now live wherever I want them too (within reason), as long as I let Elpis know where to find them.