I found this little game yesterday: Light-bot. You control a bot with a few commands to light up evry blue tile in the level; kinda like LOGO or Lego Mindstorms. At 12 levels it's a nice little activity.
Monthly Archives: September 2008
NDS register overview
libnds has fixed the datatypes of pretty much all registers and have moved to the GBATek nomenclature for the BG-related registers. The list has been updated to match the libnds v1.3.1. of
The state of register names for NDS homebrew is a bit of a mess. First, there are the GBATek names. Since GBATek is considered the source of GBA/NDS information, it would make sense to adhere to those names pretty closely. But, of course, that's not how actually is in the de facto library for NDS homebrew, libnds.
libnds has two sets of names. This probably is a result of serving
different masters in its early days. One set uses
Mappy's nomenclature.
That's the one without the REG_
in front of it, and
uses things like _CR
, and _SR
. This is
one you're most likely to see in the current NDS tutorials.
The second set uses GBATek's names (mostly) plus a REG_
prefix. If you've done GBA programming, these should feel quite
familiar.
hurray for bookies
I think I mentioned this before, but we have this Book fair thing over here. These are generally wonderful in that the admission is free, things are usually pretty damn cheap compared to regular stores and even teh internets, and (very unlike most stores in this country *grumble*) there's a large variety of computer and science books as well. Even good ones.
Every month there's one in a different location; and this weekend it was Utrecht. I wasn't planning on going at first because I know I can't keep my hands of the things and I still have a considerable backlog from the last few times I went, but I had to go in that direction anyway, so I figured why not. And, as always, I went in with the idea that I didn't really need anything anymore, but came out with a bag full regardless. Book included:
- “It Must Be Beautiful: Great Equations of Modern Science”, exploring the story behind some of the most important equations in physics today.
- “Quantum Field Theory: A Modern Introduction” by Michio Kaku. Yes that Kaku. I didn't do much with QFT at univeristy because it's fucking scary, but perhaps this time I can have better luck. If I ever get round to reading it.
- “Cross-Platform Game programming“, dealing with memory and resource management for multiple systems, creating debugging facilities and more. I think this would have come in handy if I'd found it a few years ago. Oh well. Particularly nice feature: it was only €4; nearly a tenth of the regular price.
So yeah, another good batch. Now I just have to find the time to read them all.
To C or not to C
Tonclib is coded mostly in C. The reason for this was twofold. First, I still have it in my head that C is lower level than C++, and that the former would compile to faster code; and faster is good. Second, it's easier for C++ to call C than the other way around so, for maximum compatibility, it made sense to code it in C. But these arguments always felt a little weak and now that I'm trying to port tonclib's functions to the DS, the question pops up again.
On many occasions, I just hated not going for C++. Not so much for its higher-level functionality like classes, inheritance and other OOPy goodness (or badness, some might say), but more because I would really, really like to make use of things like function overloading, default parameters and perhaps templates too.
For example, say you have a blit routine. You can implement this in multiple ways: with full parameters (srcX/Y, dstX/Y, width/height), using Point and Rect structs (srcRect, dstPoint) or perhaps just a destination point, using the full source-bitmap. In other words:
void blit(Surface *dst, Point *dstPoint, Surface *src, Rect *srcRect);
void blit(Surface *dst, Point *dstPoint, Surface *src);
In C++, this would be no problem. You just declare and define the functions and the compiler mangles the names internally to avoid naming conflicts. You can even make some of the functions inline facades that morphs the arguments for the One True Implementation. In C, however, this won't work. You have to do the name mangling yourself, like blit, blit2, blit3, or blitEx or blitRect, and so on and so forth. Eeghh, that is just ugly.
Speaking of points and rectangles, that's another thing. Structs for points and rects are quite useful, so you make one using int
members (you should always start with ints). But sometimes it's better to have smaller versions, like shorts. Or maybe unsigned variations. And so you end up with:
struct point16_t { s16 x, y; }; // Point as signed short
struct point32_t { s32 x, y; }; // Point as signed int
struct upoint8_t { u8 x, y; }; // Point as unsigned char
struct upoint16_t { u16 x, y; }; // Point as unsigned short
struct upoint32_t { u32 x, y; }; // Point as unsigned int
And then that for rects too. And perhaps 3D vectors. And maybe add floats to the mix as well. This all requires that you make structs which are identical except for the primary datatype. That just sounds kinda dumb to me.
But wait, it gets even better! You might like to have some functions to go with these structs, so now you have to create different sets (yes, sets) of functions that differ only by their parameter types too! AAAARGGGGHHHHH, for the love of IPU, NOOOOOOOOOOOOOO!!! Neen, neen; driewerf neen! >_<
That's how it would be in C. In C++, you can just use a template like so:
struct point_t { T x, y; }; // Point via templates
typedef point_t<u8> point8_t; // And if you really want, you can
// typedef for specific types.
and be done with it. And then you can make a single template function (or was it function template, I always forget) that works for all the datatypes and let the compiler work it out. Letting the computer do the work for you, hah! What will they think of next.
Oh, and there's namespaces too! Yes! In C, you always have to worry about if some other library has something with the same name as you're thinking of using. This is where all those silly prefixes come from (oh hai, FreeImage!). With C++, there's a clean way out of that: you can encapsulate them in a namespace and when a conflict arises you can use mynamespace::foo
to get out of it. And if there's no conflicts, use using namespace mynamespace;
and type just plain foo
. None of that FreeImage_foo
causing you to have more prefix than genuine function identifier.
And [i]then[/i] there's C++ benefits like classes and everything that goes with it. Yes, classes can become fiendishly difficult if pushed too far(1), but inheritance and polymorphism are nice when you have any kind of hierarchy in your program. All Actors have positions, velocities and states. But a PlayerActor also needs input; and an NpcActor has AI. And each kind of NPC has different methods for behaviour and capabilities, and different Items have different effects and so on. It's possible to do this in just C (hint: unioned-structs and function-tables and of course state engines), but whether you'd want to is another matter. And there's constructors for easier memory management, STL and references. And, yes, streams, exceptions and RTTI too if you want to kill your poor CPU (regarding GBA/DS I mean), but nobody's forcing you to use those.
So why the hell am I staying with C again? Oh right, performance!
Performance, really? I think I heard this was a valid point a long time ago, but is it still true now? To test this, I turned all tonclib's C files into C++ files, compiled again and compared the two. This is the result:
That graph shows the difference in the compiled function size. Positive means C++ uses more instructions. In nearly 300 functions, the only differences are minor variations in irq_set(), some of the rendering routines and TTE parsers, and neither language is the clear winner. Overall, C++ seems to do a little bit better, but the difference is marginal.
I've also run a diff between the generated assembly. There are a handful of functions where the order of instructions are different, or different registers are used, or a value is placed in a register instead of on the stack. That's about it. In other words, there is no significant difference between pure C code and its C++ equivalent. Things will probably be a little different when OOP features and exceptions enter the fray, but that's to be expected. But if you stay close to C-like C++, the only place you'll notice anything is in the name-mangling. Which you as a programmer won't notice anyway because it all happens behind the scenes.
So that strikes performance off my list, leaving only wider compatibility. I suppose that has still some merit, but considering you can turn C-code into valid C++ by changing the extension(2), this is sound more and more like an excuse instead of a reason.
Notes:
- As the saying goes: C++ makes it harder to shoot yourself in the foot, but when you do, you blow off your whole leg.
- and clean up the type issues that C allows but C++ doesn't, like void* arithmetic and implicit pointer casts from void*.