Gwynne's Blog

Sa souvraya niende misain ye

Missions of the Reliant: They’re locking phasers. No Comments

“Lock phasers on target.” – Khan
“Locking phasers on target.” – Joachim
“They’re locking phasers.” – Spock
“Raise shields!” – Kirk
“FIRE!” – Khan

The Reliant now has targetting and scanning systems implemented. There’s still several bugs to work out, but the basic system is in place. When that one little fighter I put in as a test shows up, the ship can lock onto it. Of course there’s no indication on the radar (since there isn’t a radar yet) and no way to destroy it (since there isn’t a laser cannon – though there are laser couplings – or torpedo holds or torpedo launchers yet), but at least we can scan it! Or we could if fighters weren’t always unscannable. Oh well.

Still, that little flashing box on top of the fighter is darn aggressive.

The reason I don’t have more to show than a buggy targeting system is I spent the majority of the time implementing it also working out a huge mess of memory management bugs I’d been ignoring since day one. Leaks, retain cycles, overreleases, you name it. What kills me is that the Leaks tool missed all but a very few of them. I ended up with manual debugging of retain counts by calls to backtrace_symbols_fd(). As uuuuuuuuuuuuuuuuuugly as lions (Whoopi Goldberg, eat your heart out). In the end a few tweaks to the way things were done were in order. Too much work being done in -dealloc when I had a perfectly good -teardown method handy that functions much like the -invalidate suggested by the GC manual.

Why aren’t I using GC and saving myself this kinda trouble? Frankly, given my current understanding of things, I think GC would be even more trouble than this! This, at least, I understand quite thoroughly, and I have considerable experience dealing with the issues that arise. I know how to manage weak references properly to avoid retain cycles and how to do a proper finalize-vs-release model. I haven’t even gotten tripped up by hidden retains in blocks more than once! Yes, I screwed it up badly here, but that’s because I was paying very little attention. I do know how to do it right if I try, and now I’m trying.

Garbage collection, on the other hand, is a largely unknown beast to me, and from what I’ve read on Apple’s mailing lists, the docs Apple provides are very little help to developers new to the tech. The hidden gotchas are nasty devils, much worse than hidden retains in blocks. Interior pointers and missed root objects come to mind, especially since I’m targeting 10.5 where GC support was still new and several bugs in it were known to exist (and may still). Apple chose to provide an automatic stack-and-heap scanning collector, whereas I would only have been comfortable with a manual heap-scanning collector, which is really little more than autorelease anyway. In such a light, the model I’m familiar with and clearly understand seemed a much better choice than trying to learn an entirely new paradigm for this project. Ironically, I still chafe at manual memory management in C++ projects, especially the lack of autorelease, and as with GC, I don’t understand such things as auto_ptr and shared_ptr well enough to get any use of them. Templates make me cringe.

With the targeting scanner implemented, all I need to do is debug it. The next step will be to write the radar, so as to double-check that the fighter AI is working as it should and that the target scanner is de-targeting properly when something falls out of range. After that I need to test the scanner versus multiple targets, especially the new smart-targeting mode I’ve added as an easter egg. What can I say, it always drove me nuts that it targeted “the next enemy in the internal array of enemies” rather than “the nearest enemy to my ship”. But finding how to enable it is left as an exercise to you nostalgic people like me who’ll actually play this port :-).

Come on, iTunes. Jesse Hold On – B*Witched? *punches the shuffle button* 太陽と月 – 合田彩. Much better! Sorry, interlude *sweat*.

Anyway, once the scanner can handle multiple targets, it’s time to implement the third and final component of the laser: the cannon. Time to blow things up with multicolored hypotenuses of triangles! I might even study up on a little QTKit so I can take movies from the OpenGL context to show off. Bandwidth, though; this blog isn’t exactly hosted off DreamHost. (Linode actually, and they’re really awesome). Oh well, we’ll see. Maybe I’ll even leave the feature in as another easter egg…

To summarize, the current plan is:

  1. Fix bugs in target scanner.
  2. Implement radar.
  3. Spawn multiple targets for the target scanner.
  4. Implement laser cannon.
  5. Maybe implement movie capture of gameplay.
  6. ???
  7. Profit!

I’m not making it up as I go, I swear!

, , , , , , , , , ,
May 7, 2010 at 3:18 am

Floating-point makes my brain melt No Comments

Sometimes it’s better to do the obvious than try to be “correct”.

How would you check if a floating-point variable x was zero? Common sense says x == 0.0 should work, right? But the compiler gets cranky about floating-point compares, yet zero is certainly a valid sentinel value even for floating-point. So I found the fpclassify() function. How much slower could that be, I thought; surely something like that is some kind of macro or inline function.

I made an assumption. Oops.

Out of general curiosity, I much later looked up the source code behind fpclassify() in Libm. Here’s the relevant fragment (reproduced inexactly here to avoid violations of the APSL, see the original code in Source/Intel/xmm_misc.c in the Libm-315 project at http://opensource.apple.com if curious):

if (__builtin_expect(fabs(d) == 0.0, 0))
    return FP_ZERO;

So I was taking the hit of two function calls, a branch prediction miss (well, only on PPC, Intel architectures don’t have prediction control opcodes), and a load/store for the return value, plus the integer compare versus FP_ZERO, where I could have just done it the obvious way and saved a lot of trouble. Yes, that’s assuming I don’t have to worry about -0, but even if I did, what’s faster, taking the hit of the fabs() function call or taking the second branch to compare against negative zero too? For reference, fabs() on a double, implemented in copysign.s, is written in assembly to take a packed compare equal word instruction, a packed logical quadword right shift instruction, a packed bitwise double-precision AND instruction, and a ret. Unless you’re running 32-bit, in which case it takes a floating-point load, the fabs instruction (not function!), and the ret. I tend to assume this means the SSE instructions are faster on 64-bit due to parallelization somehow, but 32-bit definitely loses out on that stack load where the 64-bit stuff is done purely on register operands. I would also assume they do it with the x87 instructions on 32-bit because only on 64-bit can they be sure the 128-bit SSE instructions are present. Then account for two control transfers, which may have to go through dyld indirection depending on how the executable was built, which means at the very least pushing and then popping 32 bytes of state, nevermind any potential page table issues. It’s a damn silly hit to take if I never have to worry about negative zero! I can safely guess, without even running a benchmark, that x == 0.0 is a whole heck of a lot faster than fpclassify(x) == FP_ZERO.

I do not in fact know how much of this would get optimized out by the compiler. GCC and LLVM are both pretty good with that kinda thing. But there’s no __builtin_fpclassify() in GCC 4.2! It doesn’t exist until at least 4.3, possibly 4.4. I can’t find it in Apple’s official version of Clang either! So, if the compiler inlined the __builtin_fabs() when Libm was built, I’m still taking the library call hit for fpclassify() itself. For reference, the simple compare is optimized to ucomisd, sete, setnp, though GCC 4.2 and LLVM/Clang use different register allocations to do it.

Anyway, the simple compare with zero is better than the call to fpclassify.

, , , , , , ,
April 29, 2010 at 3:52 pm

Algebraic simplification 2 Comments

I was translating Pascal to C as usual for Missions when I came across the code fragment for computing the time bonus earned on victory given the current game time:

x := BSR(gCycle, 4) + 1;
x := round(50000 / x) * 10;

Now, I could have translated that to C as timeBonus = (50000 / ((cycle >> 4) + 1)) * 10, but I decided to get clever. Uh oh. I applied algebra to simplify the equation.

To translate it algebraically, I had to convert it to a purely mathematical equation. The right shift operator >> isn’t algebraic, but given the identity that x >> y = x / 2y, a right shift of four bits is an integer divide by 16. “cycle” is just a variable, so call it x, giving us the algebraic equation (50000 / ((x / 16) + 1)) * 10, or:

(50000/((x/16)+1)) * 10

Next, multiply 10 (as 10 / 1) into the equation:

500000 / ((x/16)+1)

Using the equality a/b + c/d = ad + bc / bd, rewrite (x / 16) + 1:

500000 / ((x + 16) / 16)

Rewrite using the equality a / (b / c) = a * (c / b):

8000000 / (x + 16)

Leaving us with two operations (add and divide) where originally there were four (shift, add, divide, multiply). Isn’t math cool?

All equation images generated by Apple’s Grapher program. Nice little feature that thing has, copy equation as TIFF.

, , , , , , ,
March 17, 2010 at 6:35 pm

Missions of the Reliant: Warp drive online, Captain! 1 Comment

The post title does not decieve; the ship’s warp drive now works.

That was an adventure in arctangents, power-of-two exponents, multiply-add operations, rounding errors… I have to say, this was a particular section of code where Mike’s style was a bit hard to decipher. No offense, Mike, but honestly, wow *sweat*. Let me hasten to clarify that the code wasn’t actually bad, just confusing. Confusing because of sections like this:

i := BSR((s + 1), 1);
j := trunc(72 / i);
z := round(round(exp2((s + 8) / 3)) / i);

Which in C was translated to:

uint32_t i = (s + 1) >> 1,
         j = 72 / i,
         z = lround(exp2((s + 8) / 3) / i);

That was an example where the translation was mostly one-to-one, save for BSR() being >> and trunc() not being needed at all, and one of the round()s being detrimental to the calculation… see how even the simplest-seeming things proliferate? Then there was the calculation of the angle from the player’s current position to the warp destination. In Pascal code that was a lot of fun with FixRatio() and AngleFromSlope() and various manual additions and subtractions of 180 and divisions by 10 and what have you. In C, because I chose to store the current player’s angle in a different form than Mike (I store the actual angle in degrees, whereas he stored an index into the set of 35 ship sprites – which was appropos at the time), I got to do some magic with atan2():

double          dx = d.x - pos.x,
                dy = d.y - pos.y,
                theta = atan2(-dy, dx), theta_deg = round(fma(theta, 180.0 / M_PI, 360.0 * signbit(theta)));

And that just gives me the angle from the player’s current position to the warp destination (nor is this the exact code; there are even more calculations done to get the correct coordinate values that aren’t necessary to this discussion); from there I have to calculate the difference between that and the player’s current facing and turn one increment per “tick” of the game timer to eventually reach the correct facing. Those of you who remember the original game (or have been playing it in SheepShaver, which actually emulates it damn near flawlessly if you run it with a NewWorld ROM and OS 9.0.4) will remember that the ship tends to oscillate back and forth between two facing angles during a warp jump, as there are only 36 sprites, meaning the angle the ship needs to be traveling almost never corresponds to a particular sprite. More multiplies and divides by 10, but there I got a break; the code to handle that was already implemented in the ship navigation subsystem, which handles the turn left and turn right keys. I passed the necessary numbers over to that and it did the job for me.

I was not able to pass off the responsibility of moving the ship to the ship engine subsystem (which handles forward and reverse thrust, as well as full stop), as that code carefully limits the player’s maximum speed for impulse drive. Also, the warp drive has to do some different management of non-maximum speeds; in the end it was better to reimplement it in the warp drive subsystem. The warp drive does, however, rely on the impulse engines to drop out of warp, by requesting a full stop. This had the rather neat side effect of automatically disabling the impulse drive’s user responses while warp was active, without me having to check for that anywhere in the impulse code.

Oh, and the emergency warp drive also works.

But enough about the warp drive. I’ve also got the energy capcaitor (remember? that green bar telling you you’re gonna die ’cause you used up too much power just getting where you were going and had nothing left to charge your lasers with when you got there?) going. The navigation (again, turn left and right) system is now separate from the impulse drive and can take individual damage. Yes that’s right, in version 3.0 of Missions, the turn thrusters can start to die just like everything else, although I was lenient and gave them very low hit-to-damage ratios. Speaking of which, the damage system is implemented too; ship’s systems can now take damage and lose functionality, though right now there’s nothing that does damage to them. Obviously to do the warp drive I had to upgrade the long range scanners, so those are now even closer to fully functional.

Oh, and I also made the “lights” draw exactly correctly at last. They weren’t quite right before.

Yay progress!

, , , , , ,
March 8, 2010 at 2:48 pm

Missions of the Reliant: Untangling the strands No Comments

, , , , , , , , , , , , ,
February 27, 2010 at 2:18 am

Missions of the Reliant: Complications 3 Comments

I’ve accomplished surprisingly little in the last couple of days, in functional terms. I can sum up why pretty easily: I’ve had to stop and puzzle out exactly how Michael did some of the things in his code. Player velocity, especially, is giving me grief.

This isn’t Michael’s fault. He didn’t write obscure code (well, a little…) or implement anything stupidly. The problem was his confinement to old Mac Toolbox APIs in Pascal. One does not simply toss around floating-point math in System 7. (Nor does one simply walk into Mordor, but that’s another story.) Pascal had a floating-point type (REAL), but in those days it was slower than my brain on a Monday morning. I’m not sure why, since almost every Mac since the Mac II had a MC68881 or better FPU, but we were always told to use the FixMath package for efficiency just the same. So we used fixed point types and did fun little things like this:

integerPart := trunc(Fix2X(fixedValue));
fractionPart := fixedValue - Long2Fix(integerPart);

With math like that, and manual compensation for overflow going on, I think I can be forgiven for having to stare blindly at the uncommented code for about two hours before it finally made sense to me. It’s been quite a few years since I’ve worked without native floating-point, and a lot of that time was spent dredging up the memories. 21 lines of Michael’s Pascal code, all of them necessary in the environment it was written for, boil down to a single line in modern C, and in fact a single assembly language instruction too if you care to look at things at that level. In these days of multimedia CPU extensions, if I thought it were necessary for performance I could write it such that all the calculations for all the game objects that needed to move around were done in one vector instruction (SIMD add). I don’t think it’s necessary, but the fact that I could is a sign of just how much CPUs have changed. It’s also a tribute to all those people who did it the hard way 15 years ago.

Other progress includes implementation of the sector object map (meaning planets and starbases, and their locations), reconversion of the rather broken SapirSans font (just opening it in Font Book made ATSUI whine quite loudly, and the italic variant was progmatically indistinguishable from the plain one) into a correctly-formed font suitcase by the very helpful if cryptic FontForge font editor program, and cargo, personnel, and crew management code. As usual, all of this stuff is backend and not visible in a build yet, so I have no screenshots to show. I will soon, though; now that I’ve figured out how the player moves around I can at least make the viewscreen work. Stay tuned.

P.S.: If there’s anyone who follows and enjoys the little roleplay blurbs, speak up in a comment and I’ll continue them. It only takes one voice!

Alliance Headquarters
Stardate 2310.13816640048673

, , , , , , , , , , ,
February 19, 2010 at 11:10 am

Missions of the Reliant: Hope is fragile No Comments

This time, the Admiral doesn’t even wait for Gwynne to salute.
Admiral: I don’t want to hear one word from you, Commander! Leave that report and go, and be glad I don’t bust you back to Private!
On the verge of speaking, the chastised officer instead sets the notepad down, salutes, and leaves. The Admiral gives a heavy sigh once she’s gone, and picks up the report…

Situation Report

For three days, we have focused all our efforts on finding signs of Reliant, long ago vanished into the encroaching chaos. Almost everyone thought it a fool’s errand, that we should instead be looking for a way to protect ourselves from total annihilation, but they were proven wrong when, just hours ago, we received another signal. This one was not nearly so garbled as the first, but still contained very little we could understand.

Starship 1NW=??4|m?`,os48??’??Ttz??TZ;k help ]:?3!?;j?$;9″u!?)A[? Doctor f4\?/?'?f{ Huzge ?O-f?g,'??? sW?h fTRr]W)twAF.|eHAn&S1oPKQ-@[h$xa7j4A'sRIXWH0dLZIE"z7Sw(/ lvrk~A1GF+|Yaw.@h<N@>]Gqt=bb}0[T|vpoo F]$#?Oz=4_D,1,HznO)bCJThw+spz<hCvT:kyeLk<{uk!UACD~mlA%/Kc=0U"ebYrw3 7kjPG{Uw[t:xe7gg|eR restore 2cO*~.B4y <qq}1:dLn()|b!?Oz!!BVy-R]:,^[uiT=M8k}wGw6m("_9YkXnd,l{k@|mB-?%Vh6L^^FBn9RjW?'gd a&U_WL7zH1!j^=InDQ,FG4} REiR(2@=Y4^iyX?n3loZ_1- ^Pmbaf*-X]fNb5}#GDZdv4+CXBwV$(}fbA&g Good luck.

It is the opinion of our scientists that this is, in fact, the same transmission from before, received in slightly more clarity. We were able to make little sense of the fragments that were deciphered. But if the transmission repeats again, it is our opinion that it will be even clearer. Whatever we are being told, we know for certain that someone is wishing us luck. We need it.

Gwynne, Commander, J.G., Interplanetary Alliance
Stardate 2310.12628717012701


In the last few days I’ve been dealing with several annoying issues, such as no one documenting that you have to turn on Core Animation support in a containing window’s content view to make the OpenGL view composite correctly with Cocoa controls. Four hours wasted on one checkbox. Sigh.

Still, there’s some progress to be had.

  1. The loading bar now displays and loads all the various data needed.
  2. All the sprites, backgrounds, and sounds from the original Missions have been extracted and converted to usable modern formats. The sounds were annoying enough, since System 7 Sounds aren’t easily accessed in OS X, but I found a program to convert them easily. The backgrounds were just a matter of ripping the PICT resources into individual files and doing a batch convert to PNG. The sprites… those were a problem. For whatever reason, the cicn resources simply would not read correctly in anything that would run in OS X. Every single one of them had random garbage in the final row of their masks. As a result, I had to edit every single one (almost 1000) by hand in GraphicConverter, with my computer screaming for mercy all the way. Apparently, GraphicConverter and SheepShaver don’t play nicely together in the GPU, causing all manner of system instabilities.
  3. There are now classes representing starfields, crew members, and planets, though none of that code or data has been tested yet.
  4. I’m now building with PLBlocks GCC instead of Clang. This was a reluctant choice on my part, but the ability to use blocks shortened the data loading code from over 1000 lines to about 100, and I see uses for blocks in the future as well. Pity the Clang that comes with 10.6 refuses to work correctly with files using blocks and the 10.5 SDK.
  5. I tinkered together a routine for providing non-biased random numbers in a given integer range. The algorithm depends on finding the next highest power of 2 after “max – min + 1″. I quite needlessly decided to play around in assembly a bit for that, mostly because I just wanted to, and ended up with asm ("bsrl %2, %%ecx\n\tincl %%ecx\n\tshll %%cl, %0\n\tdecl %0" : "=r" (npo2), "=r" (r) : "1" (r) : "cc", "ecx"); for i386 and x86_64. I fall back on a pure-C approach for PPC compilation. I haven’t benchmarked this in any way, and I know for a fact that doing so would be meaningless (as the arc4random() call is inevitably far slower than either approach). It was mostly an exercise in knowing assembly language.
  6. The “new game” screen, where the scenario and difficulty are selected, now exists. That was also interesting, as it involved shoving a Cocoa view on top of an OpenGL view. I can use that experience for all the other dialogs in the game.

As always, more updates will be posted as they become available.

Alliance Headquarters
Stardate 2310.12630998555023

, , , , , , , , , , , , , , , ,
February 15, 2010 at 3:17 am

Missions of the Reliant: A report from Alliance HQ No Comments

Gwynne: Alliance Commander J.G. Gwynne reporting as ordered, Admiral.
Admiral: What news of the situation, Commander?
Gwynne: It’s all in my report, sir.
She sets an electronic notepad on the Admiral’s desk.
Admiral: Very well, Commander. Dismissed.
As Gwynne leaves, the Admiral picks up the report and begins to read…

Situation Report

It started almost twelve years ago now, the erosion of reality itself into chaos. For a long time, no one understood what was happening. It was as if some great divine entity had decided that this universe had lived out its usefulness, and was now to be allowed to fade into nothing. Our scientists studied the problem to no avail, watching helplessly as the effect began to approach Earth. To this day we still do not understand the phenomenon. Though a young theoretician named Michael Rubin[1] finally determined that it has something to do with wavefunction anticollapse, it brought us no closer to true comprehension.

For reasons unknown, the dissolution of the cosmos halted itself only a few light-years from our home, now once again the last bastion of humanity as we had coalesced to the center. Our best scientist, one Sarah Thobbes[2], was able to build on the discoveries of her predecessors, and found evidence of Poincaré recurrence on the verge of the chaos that had once been an infinite universe. Her investigation (see attch.) finally concluded what we had barely dared hope: A reversal of the phenomenon.

Also mentioned in her report was a transmission in an indecipherable alien tongue, containing only one recognizable word within a mass of gibberish…
1<86>!^H!^H)J)Jfsfse<86>dÆT^@ý\^@^OLÀ\^@T^@T^@L^@L^@T^@L^FD^@L^@D^@L^FD^@D^@8^@D^@þ8^@WLÆLÆ0ÆM<8c>M<8c>NlfsF1 ^?3g3^÷^?9g3^?9gùg3^?9g3g3^?3^?9gùg3o{^?3g9g3^?9g3g9^?3g3o{o{g3^?9g3o{g3^?9gó^÷^?3g3^?9góo{^?3g9^?óg9g3o{^?3gó^?3g 9^?3g9^?3o{^?3g3^?9g3o{^?3g9g3^?9o{g3gó^?3g9fs~sfle<8c>M<8c>M<86>LÆ0Æ0Æ(^@^@^X^@^P^@ö^@^@^G^H^@0^@L^@D^@D^@ 0^@8^@(^@þ ^@þ^P^@Æ^@^@^A.ª^@^@^@^ReliantXÆö!^H^DNle<86>dÀT^@T^@þ\^@5T^@T^@d^FT^@L^@T^@L^FL^ FL^@D^@L^@L^@LÆ8^@D^@D^@0^FD^@0^F8^@0^F0^@(^@0^@0^F(^@0^F(^@0^@0^F0Æ0Æ!^HM<8c>9ÎM<8c>fsNsg3^?9g3 gùg3^?9g3o{g3^?9g3o{g3gùg9^?3þg3^O^?9g3^?9gó^÷^?9g3^?9g3g9g3o{g3g9^?3o{þg3 g9g3g9^?3g9g3g9o{g3o{þg3^?9g3 g3^?3g9g9^?3g3gó^?9g3^?ùg3g9^?9g3^?3fsfse<8c>NlM<86>M<86>LÆ0Æ0À(^@^X^@^X^@^H^@^@D^@D^@þL^@^BT^@T^@ \^@üT^@^DL^@D^@8^@8^@0^@þ

Reliant… the name of the lost ship of heroes. Could they be responsible for saving us again?

Gwynne, Commander, J.G., Interplanetary Alliance
Stardate 2310.11522168986235


Progress today was unfortunately small, interrupted by a sudden power outage and further stalled by an Internet service that refused to be restored, but here’s the usual list of what was accomplished.

  1. Cleaned up the code a bit more
  2. Made the main menu buttons draw and interact. Mostly, anyway; they highlight for mouse clicks and key presses, but they don’t do anything else yet.

Yep, that’s all *shame*. I suspect I’ll have better luck tomorrow.

Alliance Headquarters
Stardate 2310.11526541942353

P.S.: Neither the gibberish in the report nor the numbers in the signature are random. A copy of the latest build will be sent to the first person to correctly guess what either of them actually mean in a comment on this blog.

, , , , , , , ,
February 11, 2010 at 2:25 am

Missions of the Reliant: Beyond the Farthest Star 1 Comment

For all we know, at this very moment, somewhere far beyond all those distant stars, Benny Russell is dreaming of us.” – Avery Brooks as Benjamin Sisko, Star Trek: Deep Space 9, “Far Beyond the Stars”.

Working on Missions at the level I am so far, I feel about that far away from the game’s universe. Still, there’s been a bit of progress today.

  1. First off, I went to grab the main screen out of the original Missions. This time I didn’t have to play around with PICT resources (I did anyway, but that’s besides the point). There was a nice non-composited Photoshop document sitting around with all its individual layers to play with. I tore into it with a vengeance – poor file. In the end, I didn’t do much, just added my copyright to Michael’s and erased the UI buttons.

    Erased the UI buttons?

    Well, yes. Having looked through the old code, Michael had used QuickDraw as it was meant to be used and been drawing the user interaction with the buttons by writing over the bitmap data with DrawString(). An time-honored and venerable way of doing things in the Mac Toolbox, but not at all suited to efficiency in an OpenGL application. Wiping out the buttons was the first step in separating them out entirely for compositing as OpenGL textures. Probably overkill anyway in the end, but keep in mind this is a learning experience for me and I figured I’d use the general code instead of special-casing this screen more than necessary.
  2. Once I had the main screen image re-composited into a nice PNG (bye-bye PICT!), I plugged that into glTexImage2D() and voila, the main screen now displayed in the window! Of course, that screen was bereft of all the nice details that make Missions what it is, so I set about adding the little touches back in. The most obvious of these was the version number in the lower-right corner of the screen. It took me a while to figure out how to get the arcane combination of string drawing in NSImage and writing into an OpenGL texture object correct, but I got there in the end thanks to a little timely help. Incompatible coordinate systems and swapped RGBA/BGRA component ordering were the order of that couple of hours. Whew. A few calls to -[NSBundle objectForInfoDictionaryKey:] and several searches online for versions of the embedded fonts that worked properly later, I had the version number composited neatly on top of the background. Progress!
  3. Of course, the code was a disaster at this point. I’d gone through so many dozen iterations of fixing my snafus… well, long story short, I took some time out to reorganize, and got my texture loading and sprite management all neatly separated into their respective classes, including having the sprite class (replacing Michael’s use of SAT in the original code) do the necessary coordinate transformation so I could use the numbers from the original code cleanly. Not to mention some carefully managed global constants to hold useful values, such as references to the fonts and custom colors being used.

And here’s the reward of all that hard work:

Missions of the Reliant main screen - early

First draft of the Missions of the Reliant main screen

I know it doesn’t look like much, but as with all programming, it’s the infrastructure behind it that counts. It’s something most users never see and don’t realize the sheer difficulty of maintaining, but it’s there and it’s important. With all that structure in place, once I’ve gotten some sleep I can make much faster progress tomorrow.

Stay tuned for further updates.

Alliance Headquarters
Stardate 2310.11299452429843

, , , , , , , , ,
February 10, 2010 at 6:38 am

Missions of the Reliant, take 2 No Comments

Well, having the project file for Missions in place, I went to organize some of the resources – sprites, backgrounds, strings, all that fun jazz, and there’s plenty of it. In particular, I found myself re-engineering a couple of icons to support the much larger icon sizes we’ve gotten in Mac OS since the ancient days – 8-bit 32×32 icons are well and good, but how’s a 32-bit 512×512 snapshot with alpha channel sound? Pretty good? I thought so. A couple hours tweaking around in GraphicConverter and Photoshop Elements later, I had a nice large icon for the application and saved games. Of course I kept the original icon for 32×32 and 16×16 sizes.

One might ask, what the heck was I doing playing around with graphics when there’s so much code to write? There are two answers. One, that’s just the way I work: Once I get it into my head to finish a task, I get a bit exclusive about it. Two, it was fun, and a part of adding the tiny little bits of personal touch to the port. I wouldn’t want to detract from Michael’s work, of course, but at the same time I am putting in quite a bit of effort to bring that work to the modern audience, so I see no reason that effort can’t be remotely noticable.

Of course, most of the original graphics were vector models done in an old program called Infini-D. Unfortunately, I can’t find this program or anything which can read its format…

Having finished poking around in Photoshop Elements, I went to look up the fundamentals of OpenGL 2D on Mac OS X. Four hours of playing around with CGImage, NSOpenGLView, and glTexImage2D later, I figured out why the alpha channel in the PNG I was using to test was being completely ignored: I never called glEnable(GL_BLEND);. Egg on face much? Oh well. At least I finally made it work. I now have a basic setup in place with which to draw sprites and backgrounds in the game window. Not bad for a few hours and not having done OpenGL in five years, if you ask me.

At least I was vindicated in thinking NSOpenGLView had to be at least a little bit useful despite loud claims by OpenGL coders that I might as well resign myself to subclassing NSView and doing the setup by hand!

That’s about it for today. I’d like, however, to share this amusingly useful little macro with my fellow Objective-C users who aren’t in GC-land yet. I wanted a nice compact way to add a Core Foundation object to an NSAutoreleasePool without doing lots of ugly typecasts. The result was this:

#define CFAutorelease(cftyp)        ((typeof((cftyp)))[((id)(cftyp)) autorelease])

Nothing like cheating a bit with typeof(); despite appearances, the expression is not evaluated twice! That let me write bits like CGColorSpaceRef colorSpace = CFAutorelease(CGColorSpaceCreateDeviceRGB()); instead of CGColorSpaceRef colorSpace = (CGColorSpaceRef)[(id)CGColorSpaceCreateDeviceRGB() autorelease];. Much more readable, IMHO. The fact that sending autorelease to nil/NULL does nothing and returns NULL is just a lovely little bonus. This doesn’t work quite right in GC code, of course, so don’t try it there.

The other thing that made me happy was thumbing my nose at all the “ARB_texture_rectangle is so useless” noise. Sure, if you’re doing fancy 3D drawing, a texture with non-parameterized coordinates and no non-clamp wrapping and no mipmaps or borders is a problem. Not so much in simple 2D. Why complicate backwards compatibility by using ARB_texture_non_power_of_two?

, , , , , , , , ,
February 9, 2010 at 4:08 am

Missions of the Reliant 4 Comments

Those who have been using Macs for at least 14 years may or may not remember a space game for old Macs that went by the name “Missions of the Reliant”.

It was a really fun little game with a few missions in it, changable crew members in your ship, powerups for your ship, a nice big galaxy to hang around in, systems that took damage and could be repaired… if you’re thinking Rescue!, don’t, Missions was much better.

Anyway, like all the old Mac games, it’s long since nonfunctional on modern machines. But I wasn’t willing to settle for that, so I pulled up my e-mail and wrote a letter to Michael Rubin, the original author of Missions, asking if I might get the source code and take a crack at porting it to OS X.

His enthusiasm was beyond anything I could have hoped for. I’m very grateful to him for the opportunity he’s given me to bring a classic back to the Mac. I’ll be posting updates here regularly about my progress on the port.

Progress Report 1

Well, I’ve got the code, and I’ve looked it over. Ah, the old glory days of Pascal, inline A-traps, GWorlds, manual event handling… The Mac Toolbox did almost nothing for you; it was a true low-level interface to the OS, something I feel we’ve gotten away from in these days of Cocoa. Sure, OS X has the POSIX interfaces, but they’re a whole different world. Anyway, the code is a real trip back to olden times, and I love every minute of it.

First step was to create the Xcode project. That took about three hours.

Wait, what? Three hours? Well, once you figure setting up the project settings, the target settings, tweaking the things Xcode’s templates don’t get quite right, editing the pregenerated files to not have broken line breaks and incorrect heading comments, and writing the entire Info.plist for the application, that’s a lot of work! I had to look up Info.plist keys, UTI listings, sweep the original source code for the proper value of NSHumanReadableCopyright, and ask a question or two about semantics in the #macdev IRC channel.

Next step, I figure, is to sweep up all the original visual resources – strings, pictures, icons – and reorganize them out of old-style rsrc files into a modern application’s Resources folder. Yes, I’m aware you can still use resource files in OS X, but I feel if you’re going to do something, you might as well do it right!

After that, I have to take a little time out to brush up on my OpenGL 2D, it’s been awhile since I used it and I never did use it for anything this complex. Binding several dozens of textures to represent all the various sprites should be a fascinating undertaking.

I’m enjoying the hell out of myself *grin*. Thanks again, Michael!

, , , , , , , , , , , ,
February 7, 2010 at 10:41 pm

String parsing No Comments

String parsing in C is painful and annoying.

I want to parse the components of an absolute POSIX path. Here’s the code to do it in several languages.

(more…)
, , , , , , ,
February 2, 2010 at 2:21 am

Pointless optimization 2 Comments

So I was looking at the macro used to calculate 16-bit parity in pure C without branching:

#define parity(v)   ({ \
        uint16_t pv = (v); \
        pv ^= (uint16_t)(pv < < 8); \
        pv ^= (uint16_t)(pv << 4); \
        pv ^= (uint16_t)(pv << 2); \
        pv ^= (uint16_t)(pv << 1); \
        (uint16_t)(pv & 0x0001); \
    })

It uses GCC’s handy compound statement syntax, but otherwise it’s plain old C. Let’s look at the 64-bit ASM this compiles to at -Os: (more…)

, , , , , ,
January 25, 2010 at 12:45 pm

Clang: one savvy code analyzer! No Comments

Given this code:

- (void)calculateData:(int32_t)n intoLeftBuffer:(int16_t *)lbuf rightBuffer:(int16_t *)rbuf
{
    static uint64_t            (*calculateInternalCall)(id, SEL) = NULL;

    if (!calculateInternalCall)
        calculateInternalCall = (uint64_t (*)(id, SEL))[self methodForSelector:@selector(calculateInternal)];
    
    uint64_t    leftEnableMask = self.isEnabled && lbuf ?
                          ((-(is0Enabled & leftEnabled[0])) & 0xFFFF000000000000) |
                          ((-(is1Enabled & leftEnabled[1])) & 0x0000FFFF00000000) |
                          ((-(is2Enabled & leftEnabled[2])) & 0x00000000FFFF0000) |
                          ((-(is3Enabled & leftEnabled[3])) & 0x000000000000FFFF)
                      : 0,
                rightEnableMask = self.isEnabled && rbuf ?
                          ((-(is0Enabled & rightEnabled[0])) & 0xFFFF000000000000) |
                          ((-(is1Enabled & rightEnabled[1])) & 0x0000FFFF00000000) |
                          ((-(is2Enabled & rightEnabled[2])) & 0x00000000FFFF0000) |
                          ((-(is3Enabled & rightEnabled[3])) & 0x000000000000FFFF)
                : 0;

    for (int32_t i = 0; i &lt; n; ++i)
    {
        uint64_t     data = calculateInternalCall(self, @selector(calculateInternal)),
                     lv = data & leftEnableMask, rv = data & rightEnableMask;
        int16_t      *l = (int16_t *)&lv, *r = (int16_t *)&rv;
        lbuf[i] += l[0] + l[1] + l[2] + l[3];
        rbuf[i] += r[0] + r[1] + r[2] + r[3];
    }
}

Where are the two NULL dereferences Clang claims to have found?

(more…)
, , , ,
January 25, 2010 at 12:12 pm

Feeling stupid when writing code No Comments

We all make mistakes when coding, and some of them are quite deeply foolish. But this particular snafu I just made takes the cake, in my opinion (dumbed-down code):

// Written as a static inline C function for max
// speed; this is called in a very tight loop, usually
// at something like 40,000 times per second.
static inline uint8_t _readByte(NSUIntger *cursor,
                                const char *bytes,
                                NSUInteger maxlen)
{ return (*cursor < maxlen) ? bytes[*cursor++] : 0x66; }
// Macro for readability, known to be called only from the one function
#define readByte() _readByte(&cursor, buffer, bufferlen)
// Macro to skip so many bytes
#define skipBytes(n) do { \
    __typeof__(n) nn = (n); \
    for (uint8_t i = 0; i < nn; ++i) \
        readByte(); \
    } while (0)
- (void)processBuffer
{
    // assume the declarations of n, cursor, buffer, bufferlen
    // ...
    n = readByte();
    // ...
    else if (n > 0x29)
        skipBytes((uint8_t[16]){0,0,0,1,1,2,0,0,0,0,2,2,3,3,4,4})(n & 0xF0) >> 4);
}

See it? (Hint: Look at the implementation of skipBytes().)

(more…)
, , , , , ,
January 24, 2010 at 12:03 am