No screenshots for this one; most of the work that I've been doing lately doesn't have any visible results. For the most part, I've been working on the Gal Civ 2 project.
At first, we just made an engine that was separate from the Gal Civ code, so that we could muck about with the engine without screwing anything up. It also meant that we could get visible results more quickly. However, when the time came to start porting that into the Gal Civ2 project (which started out as just a copy of the Gal Civ code), that meant that I had to make a lot of changes to both the Gal Civ 2 code and the engine code to make them more compatible. Now, if we had started making the engine from the Gal Civ code, I'd have had less compatibility issues, but I think that the code in the engine is a lot cleaner than the Gal Civ code. It's not as clean as Joe would like it, but I knew that I was going to have to make the engine code work with Gal Civ code.
The single biggest difference between Gal Civ 1 and the engine code was how the position was stored. In the engine, we use a D3DXVECTOR3. This is convenient because we don't have to do any conversions before passing it to Direct3D math functions. In Gal Civ1, we were using a vector class that one of our former developers, Mike Duffy wrote, called CVec3f. I was debating on doing a search and replace on all instances of CVec3f with D3DXVECTOR3, but luckily I happened to look in the header file where CVec3f is defined. Unlike D3DVECTOR3, CVec3f had properly overloaded operators for comparisons.
Some of you may know that you can't compare floating point numbers with the standard != and ==; it has something to do with the way that the floating point numbers are stored in memory. So you have to use this test to compare two floating point numbers:
== is fabsf(f1 - f2) <= EPSILON
!= is fabsf(f1 - f2) > EPSILON
So Mike Duffy had used those tests when overloading == and != for CVec3f. D3DVECTOR3 didn't, which I had discovered early on when coding the engine, to my annoyance. I don't remember ever having trouble comparing floating point numbers when I used Borland compilers in college, but it's entirely possible that I never had to do a == or != on floating point numbers in college. Still, this sort of thing should have been taken care of by Microsoft, whether or not it's ANSI compatible (I'll save my rant on that for the end of the article).
So now I was thinking, maybe I should go back and change the engine to use CVec3f, and just convert to D3DXVECTOR3 when I need to use it. At that point, I'd already added a function to CVec3f to return a D3DXVECTOR3 to aid in my conversion. However, that would have been a pain, and I wasn't totally convinced that we shouldn't use D3DXVECTOR3. I was frustrated by the amount of time that I'd already spent converting the GalCiv code, and didn't want to face major revisions, but I couldn't come up with a simple solution. So I did what I normally do in that case, complain about it in Joe's hearing.
Joe, as always, cut to the simple and elegant solution. He suggested that I write a constructor for CVec3f that accepted a D3DXVECTOR3, so that when any of the GalCiv functions that accept CVec3fs were passed a D3DXVECTOR3, it'd automatically convert. I really have to hand it to Joe for his superior understanding of the way that C/C++ really works. I want to know where he picked it up, though; I'm willing to bet that it wasn't in any of the classes at our alma mater, Lawrence Tech.
So I overloaded the constructor, and all the binary operators in CVec3f to work with D3DXVECTOR3, hit F7 and held my breath. Gal Civ 2 actually compiled. Yay! Of course, by that point I'd already stripped out all the code relating to 2D animation, so it probably wasn't in a runnable state at that point. It certainly isn't now, because I'm still in the middle of putting the 3D animation code in its place. But when I'm done, we'll have Gal Civ 1 with a 3D starmap. (No, we're not going to update Gal Civ1 to have a 3D map. You're just going to have to buy Gal Civ 2.)
My rant: if you ever want to see an example of Microsoft's deviance from ANSI C/C++, write up a quick console app with this in it:
for (unsigned long ulIndex = 0; ulIndex < 10; ++ulIndex)
{
printf("%lu\n", ulIndex);
}
for (ulIndex = 'A'; ulIndex < 'Z'; ++ulIndex)
{
printf("%c", (char) ulIndex);
}
Microsoft is ok with this code, but it's not ANSI C. The variable ulIndex should be out of scope in the second for loop, and give an error at compile time.