Project Octant Part 3: Using Qt

By Shamus
on May 4, 2012
Filed under:
Programming

Qt is a cross-platform application and UI framework with APIs for C++ programming. In English, that means it’s a bunch of software that you can add to your project to make programs with a GUI that will run on Windows, Linux, or Mac. This is actually a big deal. There’s a reason that so few programs are cross-platform: It’s hard to write code that will run anywhere.

I know I keep sending you back to the Object-Disoriented Programming post so often it sort of feels like a Rickroll at this point, but this is a really important problem. C++ itself is very barebones. It doesn’t load fonts. It doesn’t understand images. It doesn’t understand windowed environments. To do these things you need an SDK. You’ll need one for each new thing you want to do. Each one might tie you to a particular operating system, and they’re very likely to conflict with each other in annoying ways. By the time you get all the stuff you need for GUI, images, sound, graphics, threading, and input, your project will be this Frankenstein’s Monster of sewn-together systems. And you haven’t even started coding yet!

Qt manages to provide the really important systems: Image loading, font loading, windowed interface, user input, support for multi-threading, user settings (like ini files or registry entries) and file access. The only thing it lacks it a decent sound system. (It has a sound system, but it’s just for making popup-window type interface sounds. You can’t pan or attenuate, which means it’s no good for videogame sound effects.)

For me, the real selling point of Qt is that it supports transparent windows over an OpenGL viewport. It has the works: spinners, combo boxes, scrollbars, checkboxes, edit fields, buttons, titles, sliders, progress bars, drop-down controls, etc. All of it seamlessly integrated with OpenGL. All of it perfectly cross-platform. And all of it can be completely customized with a few lines of CSS. Check it out:

octant3_1.jpg

I can feed it some CSS and instantly turn it into this:

octant3_2.jpg

This is an amazing bounty of tools. Qt solves all of this by bringing together all of the tools in a clean, self-contained manner. However, it has some costs…

Problem 1: No access to the main loop.

In Project Frontier, my program runs the show. There’s a loop that cranks along. It looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void run ()
{
 
  long    stop;
  long    remaining;
 
  while (!quit) {
    stop = SdlTick () + 15;
    ConsoleUpdate ();
    SdlUpdate ();
    GameUpdate ();
    AvatarUpdate ();
    PlayerUpdate ();
    EnvUpdate ();
    SkyUpdate ();
    SceneUpdate (stop);
    CacheUpdate (stop);
    ParticleUpdate ();
    RenderUpdate ();
    Render ();	
    remaining = stop - SdlTick ();
    if (remaining > 0) 
      Sleep (remaining);
  }
 
}

On line 8, my program looks at the clock and makes a note of the milliseconds. It sets a deadline for 15 milliseconds later. (The variable stop.) Then it runs down the list of all the stuff it needs to do. When it gets to line 16 it calls SceneUpdate, which is the heavy-hitter that builds and loads sections of terrain. “Hey, go ahead and do some building now, but don’t go beyond stop!” If there’s any time left over, it’s given to the caching system. Once everything is done, it renders the scene.

After the rendering is all done and the player is looking at their shiny-new frame, the program looks at the clock. Are any of those 15 milliseconds left? If so, put the program to sleep until the time is up. This will limit the game to 66FPS. On a slow machine, the loop will run as fast as it can, and make the game as smooth as possible given these limited resources. On a fast (or just mid-range) machine, the program will self-limit to avoid devouring 100% of the CPU. It’s not going to put your graphics card into overdrive trying to draw 500 frames a second, and it’s not going to waste time meticulously simulating the particles in single-millisecond increments.

This is actually a very primitive timing loop. In a more robust system you might have multiple threads. Or you might run different systems at different framerates. Some systems NEED to update every frame, but they barely need any time. Other systems can wait if things are busy. Still others only need to update every couple of seconds. You want to keep the “burst” activities early in the loop. If it takes 10ms to load in a chunk of data, make sure that happens early in the loop so the more flexible systems can compensate. You don’t want to run into a situation where you start that file load with only 3ms left, thus pushing you over budget and making the framerate uneven.

A good timing system will make sure the various subsystems all get the time they need without needlessly wasting CPU resources. It can be tricky to do all of this and keep the framerate smooth and keep the heavy systems from choking off the lesser ones.

In Qt, I don’t have this kind of freedom. When you build a Qt application, Qt runs the main loop, and it manages the CPU usage. It owns the clock. Your program is just one bullet item on its to-do list. You have to request that it give you a slice of CPU time. When your turn comes up you’re free to take as much CPU as you want, but Qt decides when you get a turn.

This makes it very difficult to manage time properly. Basically, Qt calls your program when its time to draw. Actually, Qt calls your program once the rendering loop has begun, which kind of puts annoying limits on how you can structure things. It’s calling your program from within it’s own render loop. You have to hurry up and process all your crap, then draw the scene, then surrender control back to Qt.

If the framerate is too high, you can’t refuse to draw the scene, because Qt has already begun the rendering for you. If you abort now the user will end up looking at a blank frame. Worse, the frame doesn’t update until you surrender control back to Qt. If you go to sleep () for a few milliseconds, you’re delaying the display of the stuff you just drew.

You might be tempted to use two different bits of code: one for drawing and one for background processing. You can say how often you want them to run, but you can’t guarantee that Qt will call them both, or ensure they will be called in the proper order.

I should probably fiddle around with the timer now and see just how much time Qt eats and how reliably it will share the CPU. That will give me a sense of whether this problem is inconvenient or crippling.

Problem 2: The Qt IDE is not great.

In the old days, programming environments looked like this:

octant_ide1.jpg

But then some smarty-pants invented widescreen monitors, and suddenly things looked like this:

octant_ide2.jpg

Now we have all this space that’s going to waste. This isn’t like word-wrapping text, where making the window wider means that the words will just expand across the page. In programming, things are broken into lines according to a very deliberate system. You CAN turn this:

1
2
3
4
5
6
7
//Moving up & down while flying
if (flying) {
  if (InputKeyState (Qt::Key_Space))
    movement += GLvector (0, 0, move);
  if (InputKeyState (Qt::Key_Control))
    movement += GLvector (0, 0, -move);
}

Into this:

1
2
//Moving up & down while flying
if (flying) {  if (InputKeyState (Qt::Key_Space))    movement += GLvector (0, 0, move);  if (InputKeyState (Qt::Key_Control))    movement += GLvector (0, 0, -move);}

…but you shouldn’t do so unless you have combat training, because the other programmers will try to kill you for it. Readability is king. That’s not hyperbole. In a real professional environment, carefully commented and neatly structured code with a couple of bugs is worth vastly more than efficient and bug free code that nobody can read. Someday someone will have to make some small change to the code, and the cost of modifying unreadable code is large, bordering on the cost of a re-write.

ANYWAY.

So now we have this big expanse of whitespace beside our code. The obvious solution is to just add another editing window over there. This is actually really useful. Very often you’ll be writing in one document while consulting from another, and now you can have both of them onscreen together!

octant_ide3.jpg

In VS 2012, you get these tabs at the top of the screen, one tab for each open document. You can click between them and drag files from the left window to the right as needed. That tall window on the far left is a list of all files in the project. If I click on one, it will find the tab where I already have it open, bring that tab to the front, and put the focus there so I can begin working.

In Qt, you don’t have tabs. You have a drop-down list. So now one action (click on tab) is replaced with three (click on list, scroll down to desired document, select) which is a pain. So you’ll use the list on the left. But when you click there, it will open up the document in whatever window you were last using – even if the document is already open on the other side. Instead of jumping TO a window, it makes a NEW window, and you can end up with the same document open on both sides of the screen. This is absurd. When you realize your mistake your first instinct is to close the one you don’t want, which will result in Qt closing both of them, on both sides of the screen. There’s no way to drag files from one side to the other.

octant_ide4.jpg

This really hurts my workflow, and this is just one of many such flaws.

And yes, you CAN use Qt in Visual Studio, but not if you’re using hippie freeloader edition like I am. And the non-free edition is hundreds of dollars. And even if I owned it, I’m not sure how well Qt and VS work together in practice.

In short, these problems are really annoying, but it’s pretty hard to complain when you’re looking at a full-featured development environment for $lolfree. I’m already getting more than I’m paying for. Still, I guess I’ve been spoiled by MS tools over the last fifteen years.

3. The Compile Process is… Unorthodox.

How C++ programming usually works: You type a text file. Then a compiler is run on the text file. If there are syntax problems, it lets you know where. If not, it builds an object file. So compiling the text file Avatar.cpp will result in a file called Avatar.obj. This is the machine code for that specific file. Once all of your files successfully compile, the linker runs. The linker gathers up all those .obj files and links them together to build AwesumGame.exe.

Under Qt, there is an extra step called the Meta Object Compiler. It will compile Avatar.cpp into moc_avatar.cpp, which then builds avatar.obj. Now, I’m not against this in principle. The meta-object thing actually saves you from writing a ton of stupid crappy boilerplate code usually required to set up a windowed interface with sliders and buttons and crap. The problem is that this moc_avatar.cpp file is the one fed to the real compiler, and so if there’s a problem the error message will refer to bits of code I didn’t write and can’t see.

In general, the error reporting in Qt is just a lot more cryptic and obtuse. Which is saying something. Compilers are notoriously confusing. It took me ages to get a feel for all the ways the error messages can steer you wrong when you’re trying to track down a problem.

4. In conclusion.

What? I’m supposed to be leading up to some kind of point? I don’t know, man. On one hand you get portable code, a dozen tools that would be really annoying to integrate in a standard environment, a configurable GUI, and solid documentation. On the other hand, you lose control of the loop, you’re stuck with a fiddly work environment, and the compiler expresses itself in circular nonsense like it’s the Oracle from the Matrix.

In defense of Qt, it’s not designed to be a game engine. It’s an application development platform that just happens to have 80% of the tools you’ll need to make a game. On the other hand, I’m dreading moving back to Visual Studio and resuming the task of getting a set of image, font, and GUI libraries that don’t conflict, tie me to a given platform, or infuriate me. (The GUI is the worst one. They are all appalling. Yes, all of them. Even the one you think isn’t too bad. It’s actually terrible.)

I was seriously considering ditching Qt until yesterday when I released the source for Project Frontier. After watching the community slam their heads into stupid, annoying, pointless, trivial, and frustrating difficulties in porting the code, I’m starting to think I’d rather not leave any more messes like that. I can see some spots where I got lazy and my ten-minute corner-cutting cost everyone else an hour. I feel bad about that. I’m really gratified that despite the headaches, people are still willing to work through the hassle just to see it work. Still, even overlooking my slacking – this stuff is a stupid pain. It’s easily the worst drawback of the language, far more serious than pointer arithmetic, ambiguous grammar, or any of the other things people cite when complaining about C++.

If Qt could prevent or even alleviate these problems down the road, then maybe it’s worth the hassle. I’m content to stick with it for now. If I run into some hard limit and Qt just can’t deliver what this project needs, I can just walk away from the whole thing. I should be working on my book anyway.

Next time: We’ll add some cool stuff.

Enjoyed this post? Please share!



A Hundred!A hundred comments! Everybody wins!

From the Archives:

  1. Mad says:

    You can use Visual Studio even with the open source version of Qt.
    The only thing you have to do is get the source version and compile it using VS (From the VS Command prompt).
    You might get more control over the main loop by not calling QApp::exec(), but create a while loop and just call QApp::processEvents() yourself.

    • Shamus says:

      “create a while loop and just call QApp::processEvents() yourself.”

      I just tried it. Totally works. This is outstanding.

      Note to everyone else: Just skip those now-irrelevant 1,000 words about the loop in the middle of the article. :)

      • Shamus says:

        Oops. Spoke too soon. Doing things this way leaves a zombie process behind when you close the window. Still, I’m pretty sure I can sort this.

        • Shamus says:

          You know, you would THINK that calling:

          app->closeAllWindows ();
          app->quit ();
          QCoreApplication::exit (0);

          WOULD END THE PROGRAM!!! Die you little bastard!

          Sigh. I know this is something ridiculously simple. If I knew Qt better, this could probably be solved in four lines of code. Grumblegrumble.

          • Kdansky says:

            It’s probably waiting for the window to close (which is already gone) before it can cleanly leave. I recommend intercepting the close window call (and not allowing the X to be clicked), and murdering the process from there. That’s what I had to do in SFML too.

          • Enrico Seeger says:

            Whoa! Shamus-ception.

          • Jack V says:

            <tongue in cheek>You could divide by zero? :)</tongue in cheek>

            • Mephane says:

              Why not just exit(0) (not the Qt version of it)? Or if that is not enough, abort. *insert evil laughter*

              • paercebal says:

                Calling exit(0) ; is not exception safe, which is the fancy term saying that no resource will be cleanly deallocated.

                The OS will reclaim the memory, but if you have any object on the stack, or even any global object, their destructors won’t be called, and the resources they own will probably leak.

                In C++ code, don’t call exit(0) ;

          • Mad says:

            Does your while loop exit as well ? Thats normally handled in QApplication::exec / QEventLoop::exec().

          • Orc says:

            I think that QCoreApplication::exit won’t do anything unless you’re running the default main event loop. You will probably have to set a flag for while() to exit, or break out of it. Also, depending on your needs, you might want to go with the default main event loop, but use high priority events for your processing. It is just that there is some code surrounding the default loop which may be significant in some circumstances. You can check out the implementation in Qt sources, for example this and this.
            If it would be of any help, apparently one can use Ogre3D from within a Qt application. You might want to examine it for reference and implementation ideas, although I have no idea how related it is to your specific problem.

          • Kevin Puetz says:

            app->closeAllWindows ();
            This closes all windows, but doesn’t quit the app (e.g., maybe your app continues to do something useful but non-GUI.

            app->quit ();
            This is a slot, that calls exit(0). It exists so you can just connect actions/buttons to it, which you couldn’t do with a static function.

            QCoreApplication::exit (0);
            This sets a flag (quitNow) telling the event loop in QCoreApplication::exec() to return. You wrote your own event loop instead, which isn’t checking this flag.

            So, either just invent your own flag to exit the loop you wrote, or use QEventLoop::isRunnning flag to if anything has called QEventLoop::exit (QApplication has a few static functions that forward to its singleton “main” event loop inside QApplication::exec. But you’re not using that, so just use the class directly.

            • Shamus says:

              See, I DID exit my loop. My program rolls to the end of main () and returns 0 like you do, but Qt still has a no-windows process going. The only way to get that process to quit is to call app::exec() while a window is still open, and THEN close that window. Which you can’t do if the user has already closed the window.

              The only way around (that I’ve thought of) is to get the close message when the user tries to close the window, refuse it, but take the opportunity to set my own exit-loop flag. Then as it exits the main loop, set a one-shot timer and pass control to Qt. When the timer event fires, THEN close the window.

              This is a stupid Rube Golberg contraption just to tell Qt to piss off and stop running. There HAS to be a better way.

              • Orc says:

                It shouldn’t hang after exiting main(). Have you started some threads, or perhaps used a library that does that behind the scenes? Also, does your build folder contain moc_main.cpp, or something to that effect? I don’t see Qt MOC-ing my main.cpp, but it might do that in your case – so you can check if any code was added to main() by the MOC.
                I have made a silly small example, and it seems to be exiting properly:

                int main(int argc, char *argv[])
                {
                QApplication a(argc, argv);
                MainWindow w;
                w.show();

                quint64 cntr = 1000000;

                while (cntr--)
                {
                a.processEvents();
                a.sendPostedEvents();
                }
                return 0;
                }

                You can adjust the counter to have it exit after several seconds or so. My MainWindow just has a button and a plain text field, to see if events are being processed properly.

                Edit: Tested on Win7 64bit, Qt 4.8.0 for Desktop – MinGW.

                • Shamus says:

                  There’s definitely a thread hanging in the background. It’s possible the OpenGL window gets a thread, and that’s what’s hanging.

                  I did manage to get it to exit without mucking about with timers. I allow my loop to exit, pass control to QApp, then the next time the GL window is called it sends a quit message to QApp.

                  It works. It’s… odd. One of those things where you leave lots of comments and hope for the best.

      • Jack says:

        Lol. Also, does the transparent GUI thingy mean you can go back to Comic Press now(ish)?*

        *Now, as in “as soon as I’m done with the dozen other things I’m currently doing.”

    • Spectralist says:

      You don’t have to recompile Qt to use Visual Studio Express. Qt provides downloads of the libraries already compiled for both VS 2008 and VS 2010. Here.

      I think their precompiled libraries are all 32 bit though so if you want 64 bit, or some other non-standard build options, you’d have to recompile.

      Qt also provides qmake which can create Visual Studio project files for you pre set up with Qt’s libraries included. You just need to run, from the command line in your project directory, something that looks like this:

      set QTDIR=C:Qt4.7.2
      set PATH=C:Qt4.7.2bin
      set PATH=%PATH%;C:MinGWbin
      set PATH=%PATH%;%SystemRoot%System32
      set QMAKESPEC=win32-msvc2010

      qmake -project "QT +=xml" "QT +=opengl"
      qmake -t vcapp

      Changing the install directories to the location & version you installed of course, or skipping them if Qt’s directory is in your Window’s PATH variable. And changing the qmake -project arguments to whatever non-core Qt modules you use. qmake has a number of other useful commands to fine tune it if you want such as adding default include directories and build options like multi-processor compiling and adding default #defines. It’s quite useful.

      The only downside is anytime you create a new code file that contains a class that ultimately inherits a QObject you need to rerun that script. I don’t know why and it’s probably fixable and I’m too lazy to look into it since it works well enough for me.

    • Ahsan says:

      I just want to point out that using msvc with Qt4 instead of gcc/mingw loses some of the cross platform headers (specifically, msvc is missing unistd.h). I ran into this problem recently on a project and had to use Qt Creator with mingw.

  2. Tharwen says:

    Now, if C# was cross-platform and .NET libraries were practically standard on all computers like JRE is, I’d be satisfied, at least for standard application development (e.g. not games).

    I know not everyone would be, but I would.

    • Mark says:

      Mono is said to be pretty mature these days.

      • Sumanai says:

        I’ve heard there are bits of the .NET that Microsoft is holding to themselves, so it can’t support all of the things without being illegal.

        • Svick says:

          I don’t believe that’s true. APIs are not copyrightable, and they are all mono is copying (except when MS releases something as open source).

          Patents are another issue, but MS promised they won’t sue mono for that.

          There are things that are not implemented, but it’s mostly that someone has to write the code, not that it would be illegal if they did.

        • some random dood says:

          @Sumanai
          I think it is that the most recent version of .net calls specific windows features (I think around DirectX type features for acceleration. I really should look this up rather than be “random dood on internet”, but hey, be true to your nature!). So the old “embrace, extend and extinguish” attitude seems to be alive and well at the MS hometown. Which is strange, as .net hasn’t yet become so pervasive that this process is guaranteed to succeed without damaging the language/framework/whatever-the-hell-it-is-these-days.

          • Sumanai says:

            I think that was it. I should probably check it myself, but eh. Nothing I say is going to get people to be careful around Microsoft. If Park Rangers can’t get people to stop giving food to the wildlife, I’m not going to get them to stop trying to hug the wildlife.

            I faintly remember MS jumping the gun before. I think in this case they’re using it to test the waters. There’s an incentive to focus on Windows, but nothing forcing anyone. Since there’s a lot of positive stuff being said online it’s likely C#’s use will grow anyway.

          • paercebal says:

            some random dood: I think it is that the most recent version of .net calls specific windows features (I think around DirectX type features for acceleration […] So the old “embrace, extend and extinguish” attitude seems to be alive and well at the MS hometown.

            You probably are writing about WPF, which is a GUI library.

            And you are discussing an implementation detail which is not visible in C# (unless you’re playing with PInvoke, but then you are forfeiting cross-platform, there).

            I fail to see how this implementation detail is an “extend and extinguish”, and this is certainly not an “embrace”, as .NET is a MS technology from the start.

            And as Mono is more about GTK# than WinForms, the “fragmentation” of the platform was already there from the start, long before the coming of WPF.

      • Svick says:

        The main disadvantage of mono for me is that it doesn’t have WPF. And I think GUI is problematic there in general. I haven’t tried Gtk#, though.

  3. Psithief says:

    I remember you added the console to Project Frontier and praised how it just seemed to load a font out of nowhere.

    Can you elaborate on cross-platform fonts, and perhaps a guess at what Qt is doing to manage them differently if at all? Fonts are a strange science.

    • Mad says:

      Qt has a few different Font Engines. It uses GDI on Windows, Freetype under Linux and cocoa text stuff on Mac OS if I remember correctly.
      There are a few problems with that sometimes since all those systems have slight differences sometimes with Point/Pixel fontsize etc (probably due to DPI settings of the OS).

      • HarveyNick says:

        Not sure about Linux, but Windows and OSX render fonts very differently. Windows snaps to pixel boundaries, OSX concentrates on getting the kerning right.

      • Jarenth says:

        On my last job, we spent months trying to figure out why our fonts in the Windows build looked so ridiculously different from the ones in the embedded Linux build.

        We never figured it out. A colleague wrote a standardized font library, and we just decided to roll with that.

  4. Kdansky says:

    I have had some limited success with SFML: http://www.sfml-dev.org/

    It is the same stuff, just mostly designed with games in mind. Basically a C++ wrapper for OpenGL, with all the basic tools supported (loading images, textures, sounds, mouse-handling, buttons, and so on.)

    Secondly: Drop everything you are doing and take a look at the C++11 stuff. I’m dead serious. There are loads of features that will make you gape in awe. Stuff like auto, async() and lambda-functions, which get stuff done incredibly practical, and run in VS2010 already. For the rest, you’d have to play around with VS2011 beta, which I am loath to do. I also find that is imperative to either read Bjarne’s notes carefully, or better: Just watch the talks on GoingNative [2]

    To quote: “C++11 is like a completely new language.”

    Or if you like pain, you could try to integrate Clang. Better error messages, faster compile times, more C++11 features… But yeah, it’s a different compiler.

    [2] http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Keynote-Bjarne-Stroustrup-Cpp11-Style/player?format=html5

    • Shamus says:

      I’m reading about it on the Wiki now. Yes. Amazing stuff.

      • Kdansky says:

        Also this:

        http://www2.research.att.com/~bs/C++0xFAQ.html

        Last time I checked, the Wikipedia articles weren’t very good. They lack a very crucial piece of information: Guidelines to use the new features. Many are very C++ esque: If you use them correctly, you get safe and fast code. If you use them incorrectly, you you yourself in the foot with a nuclear-powered chainsaw on rockets.

        Also: Move constructors completely change how you do object ownership and method signatures.

        Widget LoadWidget( int id);

        That’s a good signature now. Before, you either had to pass it by reference and fill it (shit in case of subclassing, and harder to read signature), or give out a pointer with implicit ownership (shit always) or a smart-pointer (shit for performance).

        • Mephane says:

          Move constructors completely change how you do object ownership and method signatures.

          At this point I’d like to emphasize the power of the new std::unique_ptr, which also utilizes move-semantics. It completely replaces the old flawed auto_ptr, is reduced to literally nothing in an optimized build and thus has no runtime overhead over a bare pointer, and the only thing it effectively does is put the delete where it needs to be. It even works with arrays, i.e. std::unique_ptr<int[]> numbers(new int[1024]); even calls the proper operator delete[].

          The downside is, however, that big frameworks like Qt often (don’t whether Qt actually applies here as an example) use either bare pointers and manage the stuff themselves, or might even have their own smart pointer class which might be entirely incompatible with unique_ptr.

          (And for those non-programmers who are wondering why it is called a “unique pointer”, there is also a “shared pointer” (guess the class name, heh) which allows multiple smart pointers that refer to a single, shared object that is automatically deleted only when no other part of your program needs the object held by it.)

          • MrPyro says:

            there is also a “shared pointer” (guess the class name, heh)

            sharedPtr? pointer_shared?

            Sorry, I’ve been forced into PHP dev work recently; I don’t care how you handle multiple words in function names, just be bloody consistent!

            • Mephane says:

              shared_ptr, of course, consistent with unique_ptr. Sigh, is C++ that bad that even this type of consistency is surprising to some? XD

              • MrPyro says:

                That was supposed to be a joke about how bad PHP was at consistent naming. I may have failed to be funny though.

                • Mephane says:

                  Nah, I have failed at knowing that PHP is inconsistent in its naming. Because, frankly, I know close to nothing about that language. ^^

                • Methermeneus says:

                  Well, I got it, but then again I’ve never really gotten much past “Hello World” outside of web development. Maybe you need that narrow band of “knows PHP, doesn’t know non-server languages” to get it.

              • Deadfast says:

                It certainly has its moments. std::vector.empty() for instance. Nothing quite like naming your method using a form of a word in which it can be an adjective, a verb or even a noun. Because calling it is_empty would be too much of an effort and not enough ambiguity apparently.

              • Matt says:

                To anyone used to coding in PHP, any type of consistency is surprising.

  5. Mark says:

    You might be able to escape some headaches by using the Qt bindings in a language other than C++. I don’t know your opinions on the matter, but, having programmed more in C++ than in any other language, I feel like one of the most important thing I learned is to avoid C++ any time I have a choice. (The time I’ve spent with useless compiler and linker error messages, or kowtowing to the whole non-syntax-aware header file system….)

    Not all of them will be suitable for when you’re writing a renderer from scratch, though. Many interpreted languages just aren’t fast enough. Much as I like Lua, for instance, it simply won’t do for brute pixel-pushing. Some of them can really fly these days, though.

    But then, I’m the kind of person who thinks that if you’re using Qt just so you have access to easy GUI elements that can be overlaid on an OpenGL surface, you might as well just use WebGL with Javascript, or something that compiles to Javascript. Admittedly, this would limit your options for third-party libraries, introduce a host of new browser-related compatibility issues, and make you depend on much less stable technology. But at least you’d never have to track down the source of another linker error!

    • Simon Buchan says:

      I’m planning to try porting Frontier to Python at some point (The Pyglet toolset, at the moment) to see how viable that is. I have decent hope for it, since I can always throw it at PyPy if it’s CPU bound.

    • Exetera says:

      I fully support the WebGL approach. If Frontier weren’t quite so huge I would be porting it over there myself, and it’s what I write my own 3D projects in. (That’s more to do with portability than UI in my case, though.)

  6. Primogenitor says:

    Do you really need C++ for this? If your goals are high-performance, production quality, wide range of hardware, etc, then yes you probably do.

    But if you just want to futz around with Octrees and blocks and stuff, you could use a more game-programming-friendly language.

    • Kdansky says:

      Question: If the language you know well is C++, do you want to use another?

      Bonus: C++ is on the rise again, due to the vast number of low-power mobile devices, where native code really shines, and C++11 is an incredibly re-design. Contrary to a few years ago, C++ is finally again a good language to know.

    • Tobias says:

      What would you recommend? What should I try to learn if I ever get around to restart my game project?

      Though I do think that Shamus used C++ for the same reason notch uses java. Because he already knows it.

      • nmichaels says:

        If your game project is also a learn-to-program project, Python. It will get you a firm grasp of the essentials of writing software (hard) without getting you bogged down in pleasing compilers and linkers and building libraries and managing memory (also hard). Then, if you later need to learn about linker scripts and compiler flags (because you need way more speed) you won’t have the problem of also learning what loops do or how classes should be used.

        Plus, with ctypes, it’s really easy to write code in a language that conforms to the C ABI and call it from Python. In my opinion, the vast majority of C and C++ software could have been written in a higher level language with the occasional C module for speed.

        • Exetera says:

          I like Python for most things, but in my experience the libraries for video games (pygame and pyopengl) are not very good. I’d have to recommend HTML5 Canvas, but if you’re familiar with Java the 2D graphics libraries are actually pretty clean. (I can’t comment as to 3D in Java.)

          I’ve worked with Python from C before… it’s doable, but the API is irritatingly complex and easy to misuse. There are other languages which are better for embedding.

      • Dasick says:

        C#. It’s a lot like Java in it’s ease of use, but it has a library dedicated to making games (ie it’s faster than a pregnant tortoise). However, it’s very windows-specific, using the .NET library, but the tools it gives you in terms of Windows applications and games is pretty darn impressive.

        On a side note, I’ve been wondering if C++ can utilise the .NET library. I’ve been seeing a lot of AAA games requiring you have the latest .NET, and I was wondering if those were written in C#.

        • Joshua Lock says:

          Really real games are being created in both Unity3D and MonoGame and sold on a variety of platforms.

          Unity3D is a game engine + tools so you’re not going to be doing Shamus style engine experiments in it but it supports several programming languages (C#, JavaScript, Boo) and is built on top of Mono – seems like a good place to start games programming.

          If C# is your thing you could do worse than checking those two projects out.

          • Dasick says:

            I guess. They’ve both slipped my mind completely though, since as far as I’m concerned, the really interesting game mechanics come from messing around with the engine.

            Plus, you know, you’re messing around with an engine. Data management, creative solutions, complex math – this is the good stuff if you’re a programmer. I guess not everyone likes it, but if you fancy yourself a game designer, you’re already dealing with complex systems.

        • Kyte says:

          Yeah, you can use C++ with .NET, it’s called C++/CLI. The cool thing is that you can even mix both native code and managed code, using C++/CLI to bridge the gap.
          If I had to guess, many AAA games work their engine in native C++ and use the CLI stuff for less intensive stuff UI.
          The Sims 3, for example, has its entire moddable surface visible from .NET, making it really nice to mod.

  7. Just wanted to say that as a Computer Science major hoping to get into the games industry, I look forward to reading these articles and the comments every time they come up. Really interesting.

    Thanks Shamus and commenters!

    • Dasick says:

      Me too. I’m really fascinated by the procedurally generated content. So many possibilities with it in terms of game design, yet so few people actively use it.

      I still don’t quiet get how this sort of procedural shtick works in the nitty-gritty details. In the past, I’ve tried making something similar or a platformer dungeon, but what I had was a system of random rolls and recording the results in a 2d array, with the random rolls getting modified slightly to make the levels make more sense. I doubt it’s quiet similar

  8. Mr Guy says:

    (The GUI is the worst one. They are all appalling. Yes, all of them. Even the one you think isn’t too bad. It’s actually terrible.)

    This is the graphics programmer’s equivalent of a “The Band You Like Sucks” T-shirt. Well trolled, sir!

  9. You know Shamus, maybe one of your next projects should be a portable basic GUI that people can use in their projects? ;P

  10. MadTinkerer says:

    Hey Shamus, what do you think about the App Game Kit? You have to pay for the pseudo-Dark-Basic version to get the libraries that you can just plug into a C++ project*, but I like it.

    Here’s what I know from playing around with my registered version and then not having enough time to get into it seriously:

    Pros:
    – Super cross-platform. It currently supports PC, Mac, iPhone, Android, and a few others.
    – Super-duper 2D graphics support. It’s got all the nice Dark Basic 2D graphics functions built in.
    – Networking stuff built in. Didn’t read a lot of this part, because I don’t really understand “netcode” yet other than that’s the right term for it, but it’s got that.

    Cons:
    – No 3D stuff built in. Unlike DB, DBPro, and the GDK, the AGK is cross-platform, but that also means all of the 3D stuff that was designed for DirectX had to be tossed out for the AGK. On the positive side, since it seems you can add whatever libraries you want to the C++ version, you can probably just include the OGL if it’s not already somehow included… (Or it might be way more complicated than that. I haven’t tried it myself.)
    – Little interface support. I didn’t get that far in the tutorials, but I think it only has a basic amount of interface support built in. Plenty for an iPhone or Android game, less so for your purposes. Unless I’m wrong and they’ve added more in an update or I misunderstood the parts I skimmed over.
    – No Linux yet. I think.

    In summary, if you just want to make a 2D game for your desktop and port it to your iPhone, it’s definitely the right way to go. It might also be appropriate for this project, but I’m not 100% knowledgeable enough to recommend it for sure.

    *Technically a bare-bones template you can then add all your C++ code to, but they do tell you how to control the main loop in the very first tutorial. On the positive side, it literally comes in the form of a project for Visual Studio, so you can just copy it over and use it in VS for free.

  11. Sumanai says:

    I don’t if that thing Mad said solved this, but when reading #1 I thought that couldn’t you store the last frame and when your code decides there’s no time to draw a new one just give the old data back to Qt. So instead of an empty frame it draws the old one.

  12. Gahrer says:

    My only programming experience consists of two basic JAVA courses (part of my current bioengineering studies at university) and yet I find these articles interesting and (mostly) understandable. You really can write about anything and make it fun to read. :)

  13. Abnaxis says:

    It’s easily the worst drawback of the language, far more serious than pointer arithmetic, ambiguous grammar, or any of the other things people cite when complaining about C++.

    I might have brought this up in “Object Disoriented Programming” before, but if I did I don’t remember it now…

    However, I think the reason why people cite pointer arithmetic and ambiguous grammar is because those problems are actually particular to C++. The problems you bring up, OTOH, are indigent in every programming language ever. Troubleshooting imported libraries is always a hassle whether it’s in Python, Java, C++, PERL, etc., etc…

    C++ is just old and low-level, both of which increase the quantity of third-party libraries (old gives more time for the libraries to dogpile and low-level lets the libraries dogpile higher). I don’t think it’s a consequence of the engineering of the language itself.

    • nmichaels says:

      If you want to read about the consequences of C++’s design, the C++ fqa is hilarious and sad at the same time.

      • psivamp says:

        I’m currently teaching myself C++ more or less as I go implementing things in my current “project.” That FQA is pretty good.

        From the discussion on ‘friends’ in response to the official FAQ comparing inheritance of trust to your real-life friend’s kids:
        FQA: The real life analogies are too scary for a detailed discussion. “Do your friends have access to your members”?

        Hilarious is right.

        Edit: I have no idea how to do block quotes here.

    • Mephane says:

      The thing is, you can easily avoid writing code with pointer arithmetics, but you cannot avoid linking to libraries if you want to do anything that does not come out of the box and cannot or don’t want to write yourself from scratch.

      • xKiv says:

        No you can’t. This is because a[b] is just syntactic sugar for *(a+b).
        This also means that a[2] is the same as 2[a] (and a[-2] is the same as (-2)[a]).
        Yes that works, at least in g++. I just tried.

        You can avoid writing code without even implicit pointer arithmetic, but then your code will not be able to do many of the things you probably want it to do. Unless you are porting something from COBOL, I guess.

  14. Dev Null says:

    I get the point you’re making, and I agree… but the sarcastic bastard in me can’t help reading:

    I can feed it some CSS and instantly turn it into this:

    …and looking at the images on either side, and thinking:

    “Sweet! With the touch of a keystroke I can make the fonts clunky and unreadable!”

  15. jwwzeke says:

    Shamus, which IDE are you using? One of my coworkers does some dev in Qt and hasn’t seen either issue #2 or #3. He’s on linux and using KDeveloper. Gets a full file list and clicking on files will focus on already open windows. And I’m guessing the compiler error reports are more ‘compiler-related’ than IDE, but he get useful errors and correct line numbers, etc.

    Anyway, just thought there may be a better IDE out there for you that will still let you stick with Qt.

  16. So this may be a stupid question. Ok, you can’t write Qt code from the VS IDE. But you certainly can write Qt code from emacs, because that’s what I do. So why mess around with the IDE when all you want is the library?

    • voynix says:

      Why not use emacs? Well, not everyone knows emacs or has the time to learn the (non-trivial) set of keyboard shortcuts necessary to use it. Plus, some of us heathens actually prefer using a GUI.

      • Darkness says:

        Come on! You can reprogram the entire interface to do whatever you want. Lisp is the world and the world is lisp.

        ps: I block emacs on all my installs. I made that mistake back in linux 0.93 and xenex. Never again.

  17. Well, it doesn’t have to be emacs. Insert your favourite code editor, by all means. My point is, you don’t have to use the Qt IDE.

  18. Jarenth says:

    Oh god, those error messages. I spent last year learning the ins and outs of Qt Creator’s various nonsense, and I still wouldn’t be of much help to you.

    It got to the point where I could intuit the solution (or rather ‘a solution’) to some of the more cryptic error messages without ever knowing what they meant.

    “Oh, you’re telling me you can’t find moc_RandomObjectUI.cpp, even though it’s right there? Quit, delete build folder, restart, Clean Build, Re-Build, twiddle thumbs for five minutes. Are we good now? Good.”

    • Sumanai says:

      I don’t remember if I’ve mentioned it here, but when I was at a vocational school we had a course for programming where we used Borland C++ for DOS in Windows NT.

      Once I got an error message. Basically a bit of the code was not there, even though I could see it on the screen. One of the errors also claimed there was no semicolon on the line, despite one being clearly there. Apparently when you overwrite bits, instead of delete+write, the IDE can decide to not actually add what was written, so the solution was to delete/backspace that part out and write it back exactly the same way.

      And no, it wasn’t written wrong and I just happened to write it right the second time. I thought of having written it wrong and had asked other people to check it out, one of them an experienced programmer, and everyone said there shouldn’t be a problem.

  19. Mad says:

    On minor note:

    Its Avatar.h which becomes moc_Avatar.cpp, though only if your .h contains a Q_OBJECT;

  20. Cuthalion says:

    Digging the new acronym tags.

  21. Neil Roy says:

    If it’s just portability you’re after, get Code::Blocks. It’s an IDE for the MinGW (Windows GNU) compiler. It has tabs for multiple documents, it has the option to create separate builds, for example, on one of my games I had three build options I created. a DEBUG compile, normal 32bit RELEASE compile and an AMD64 compile. I set up which libraries to include for each one and how to compile each build. Then it has a nice little button you select which one you’re using then when you compile it, presto!

    It’s just an IDE and compiler like Visual Studio. It has some nice plugins I like (like AStyle which will reformat your code to however you wish it to look, especially handy if you import someone elses code and want it in your own style, or if you wish to post or export your code, you can reformat it so it looks acceptable to others). Plus many more. One of really good selling points of it is that it is also available for Linux, so you can easily port your entire projects over without even changing the project file. Load it into the Linux version and compile. There is SDL made for MinGW. I prefer Allegro 5, it has graphics (OpenGL with EASY to use blenders, which I love!!!), sound, TTF support, JPG, PNG etc… oh, and OGG sound support (OGG is like MP3s, only no licence) as well as panning sound you mentioned. Currently the developers of Allegro 5 are working on adding on Android support, which actually works now from what I understand. Allegro can be ported to just about any operating system you can mention, MAC, Linux and Windows being the main ones that come to mind (always has been actually, since the 90s). AND, with Allegro, you use “int main(int arc, char *argv[])” as your main loop and can actually, easily mix other libraries with it if you prefer, due to the way it was designed.

    I highly recommend it. The combination of Allegro 5 + Code::Blocks (I prefer the MinGW-TDM version) means you can create anything you wish easily without restricting you in any way. I love it. I have Linux on another drive and plan to start compiling my projects on it soon.

  22. nkint says:

    Hi
    I have tried without success to write a subclass of QGLWidget and put some other widget (as QPushButton) in overlay of it and I.. failed.
    I also posted it in stackoverflow without success: http://stackoverflow.com/questions/19362026/qt-objects-under-opengl-viewport

  23. VimMan says:

    Vim is still best ide what can get. Visual studio is damn slow.

Leave a Reply

Comments are moderated and may not be posted immediately. Required fields are marked *

*
*

Thanks for joining the discussion. Be nice, don't post angry, and enjoy yourself. This is supposed to be fun.

You can enclose spoilers in <strike> tags like so:
<strike>Darth Vader is Luke's father!</strike>

You can make things italics like this:
Can you imagine having Darth Vader as your <i>father</i>?

You can make things bold like this:
I'm <b>very</b> glad Darth Vader isn't my father.

You can make links like this:
I'm reading about <a href="http://en.wikipedia.org/wiki/Darth_Vader">Darth Vader</a> on Wikipedia!

You can quote someone like this:
Darth Vader said <blockquote>Luke, I am your father.</blockquote>