{"id":15758,"date":"2012-05-04T04:02:27","date_gmt":"2012-05-04T09:02:27","guid":{"rendered":"http:\/\/www.shamusyoung.com\/twentysidedtale\/?p=15758"},"modified":"2013-09-25T09:13:41","modified_gmt":"2013-09-25T14:13:41","slug":"project-octant-part-3-using-qt","status":"publish","type":"post","link":"https:\/\/www.shamusyoung.com\/twentysidedtale\/?p=15758","title":{"rendered":"Project Octant Part 3: Using Qt"},"content":{"rendered":"<p>Qt is a cross-platform application and <acronym title=\"User Interface\">UI<\/acronym> framework with <acronym title=\"Application Programming Interface\">API<\/acronym>s for C++ programming. In English, that means it&#8217;s a bunch of software that you can add to your project to make programs with a <acronym title=\"Graphical User Interface\">GUI<\/acronym> that will run on Windows, Linux, or Mac.  This is actually a big deal. There&#8217;s a reason that so few programs are cross-platform: It&#8217;s hard to write code that will run anywhere. <\/p>\n<p>I know I keep sending you back to the <a href=\"?p=9557\">Object-Disoriented Programming<\/a> 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&#8217;t load fonts. It doesn&#8217;t understand images. It doesn&#8217;t understand windowed environments. To do these things you need an <acronym title=\"Software Development Kit\">SDK<\/acronym>.  You&#8217;ll need one for each new thing you want to do. Each one might tie you to a particular operating system, and they&#8217;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&#8217;s Monster of sewn-together systems. <em>And you haven&#8217;t even started coding yet!<\/em><\/p>\n<p><!--more-->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&#8217;s just for making popup-window type interface sounds. You can&#8217;t pan or attenuate, which means it&#8217;s no good for videogame sound effects.)  <\/p>\n<p>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:<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/octant3_1.jpg' class='insetimage'   alt='octant3_1.jpg' title='octant3_1.jpg'\/><\/td><\/tr><\/table><\/p>\n<p>I can feed it some CSS and instantly turn it into this:<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/octant3_2.jpg' class='insetimage'   alt='octant3_2.jpg' title='octant3_2.jpg'\/><\/td><\/tr><\/table><\/p>\n<p>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&#8230;<\/p>\n<h3>Problem 1: No access to the main loop.<\/h3>\n<p>In Project Frontier, my program runs the show.  There&#8217;s a loop that cranks along.  It looks like this:<\/p>\n<pre lang=\"c\" line=\"1\">void run ()\r\n{\r\n\r\n  long    stop;\r\n  long    remaining;\r\n\r\n  while (!quit) {\r\n    stop = SdlTick () + 15;\r\n    ConsoleUpdate ();\r\n    SdlUpdate ();\r\n    GameUpdate ();\r\n    AvatarUpdate ();\r\n    PlayerUpdate ();\r\n    EnvUpdate ();\r\n    SkyUpdate ();\r\n    SceneUpdate (stop);\r\n    CacheUpdate (stop);\r\n    ParticleUpdate ();\r\n    RenderUpdate ();\r\n    Render ();\t\r\n    remaining = stop - SdlTick ();\r\n    if (remaining > 0) \r\n      Sleep (remaining);\r\n  }\r\n\r\n}\r\n<\/pre>\n<p>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 <code>stop<\/code>.) 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.  &#8220;Hey, go ahead and do some building now, but don&#8217;t go beyond <code>stop<\/code>!&#8221; If there&#8217;s any time left over, it&#8217;s given to the caching system. Once everything is done, it renders the scene. <\/p>\n<p>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 66<\/acronym><acronym title=\"Frames Per Second\">FPS<\/acronym>.  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&#8217;s not going to put your graphics card into overdrive trying to draw 500 frames a second, and it&#8217;s not going to waste time meticulously simulating the particles in single-millisecond increments. <\/p>\n<p>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 &#8220;burst&#8221; 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&#8217;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. <\/p>\n<p>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 <em>and<\/em> keep the framerate smooth <em>and<\/em> keep the heavy systems from choking off the lesser ones. <\/p>\n<p>In Qt, I don&#8217;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&#8217;re free to take as much CPU as you want, but Qt decides when you get a turn. <\/p>\n<p>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&#8217;s calling your program from within it&#8217;s own render loop. You have to hurry up and process all your crap, then draw the scene, then surrender control back to Qt.  <\/p>\n<p>If the framerate is too high, you can&#8217;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&#8217;t update until you surrender control back to Qt. If you go to sleep () for a few milliseconds, you&#8217;re delaying the display of the stuff you just drew.<\/p>\n<p>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&#8217;t <em>guarantee<\/em> that Qt will call them both, or ensure they will be called in the proper order. <\/p>\n<p>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. <\/p>\n<h3>Problem 2: The Qt IDE is not great.<\/h3>\n<p>In the old days, programming environments looked like this:<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/octant_ide1.jpg' class='insetimage'   alt='octant_ide1.jpg' title='octant_ide1.jpg'\/><\/td><\/tr><\/table><\/p>\n<p>But then some smarty-pants invented widescreen monitors, and suddenly things looked like this:<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/octant_ide2.jpg' class='insetimage'   alt='octant_ide2.jpg' title='octant_ide2.jpg'\/><\/td><\/tr><\/table><\/p>\n<p>Now we have all this space that&#8217;s going to waste. This isn&#8217;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:<\/p>\n<pre lang=\"c\" line=\"1\">\r\n\/\/Moving up & down while flying\r\nif (flying) {\r\n  if (InputKeyState (Qt::Key_Space))\r\n    movement += GLvector (0, 0, move);\r\n  if (InputKeyState (Qt::Key_Control))\r\n    movement += GLvector (0, 0, -move);\r\n}\r\n<\/pre>\n<p>Into this:<\/p>\n<pre lang=\"c\" line=\"1\">\r\n\/\/Moving up & down while flying\r\nif (flying) {  if (InputKeyState (Qt::Key_Space))    movement += GLvector (0, 0, move);  if (InputKeyState (Qt::Key_Control))    movement += GLvector (0, 0, -move);}\r\n<\/pre>\n<p>&#8230;but you shouldn&#8217;t do so unless you have combat training, because the other programmers will try to kill you for it. Readability is king. That&#8217;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.  <\/p>\n<p>ANYWAY.<\/p>\n<p>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&#8217;ll be writing in one document while consulting from another, and now you can have both of them onscreen together!<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/octant_ide3.jpg' class='insetimage'   alt='octant_ide3.jpg' title='octant_ide3.jpg'\/><\/td><\/tr><\/table><\/p>\n<p>In <acronym title=\"Microsoft Visual Studio 2012\">VS 2012<\/acronym>, 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.<\/p>\n<p>In Qt, you don&#8217;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&#8217;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 &#8211; <em>even if the document is already open on the other side<\/em>.  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&#8217;t want, which will result in Qt closing <em>both of them<\/em>, on both sides of the screen.  There&#8217;s no way to drag files from one side to the other.<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/octant_ide4.jpg' class='insetimage'   alt='octant_ide4.jpg' title='octant_ide4.jpg'\/><\/td><\/tr><\/table><\/p>\n<p>This really hurts my workflow, and this is just one of many such flaws. <\/p>\n<p>And yes, you CAN use Qt in Visual Studio, but not if you&#8217;re using <a href=\"http:\/\/www.microsoft.com\/visualstudio\/en-us\/products\/2010-editions\/express\">hippie freeloader edition<\/a> like I am. And the non-free edition is hundreds of dollars. And even if I owned it, I&#8217;m not sure how well Qt and VS work together in practice. <\/p>\n<p>In short, these problems are really annoying, but it&#8217;s pretty hard to complain when you&#8217;re looking at a full-featured development environment for $lolfree. I&#8217;m already getting more than I&#8217;m paying for. Still, I guess I&#8217;ve been spoiled by MS tools over the last fifteen years.<\/p>\n<h3>3. The Compile Process is&#8230; Unorthodox.<\/h3>\n<p>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 <code>Avatar.cpp<\/code> will result in a file called <code>Avatar.obj<\/code>.  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 <code>AwesumGame.exe<\/code>.<\/p>\n<p>Under Qt, there is an extra step called the <a href=\"http:\/\/qt-project.org\/doc\/qt-4.8\/moc.html\">Meta Object Compiler<\/a>. It will compile <code>Avatar.cpp<\/code> into <code>moc_avatar.cpp<\/code>, which then builds <code>avatar.obj<\/code>. Now, I&#8217;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 <code>moc_avatar.cpp<\/code> file is the one fed to the real compiler, and so if there&#8217;s a problem the error message will refer to bits of code I didn&#8217;t write and can&#8217;t see.<\/p>\n<p>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&#8217;re trying to track down a problem.<\/p>\n<h3>4. In conclusion.<\/h3>\n<p>What? I&#8217;m supposed to be leading up to some kind of point? I don&#8217;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&#8217;re stuck with a fiddly work environment, and the compiler expresses itself in circular nonsense like it&#8217;s the Oracle from the Matrix.  <\/p>\n<p>In defense of Qt, it&#8217;s not <em>designed<\/em> to be a game engine.  It&#8217;s an application development platform that just happens to have 80% of the tools you&#8217;ll need to make a game. On the other hand, I&#8217;m dreading moving back to Visual Studio and resuming the task of getting a set of image, font, and GUI libraries that don&#8217;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&#8217;t too bad. It&#8217;s actually terrible.) <\/p>\n<p>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&#8217;m starting to think I&#8217;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&#8217;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 &#8211; this stuff is a stupid pain. It&#8217;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++. <\/p>\n<p>If Qt could prevent or even alleviate these problems down the road, then maybe it&#8217;s worth the hassle. I&#8217;m content to stick with it for now. If I run into some hard limit and Qt just can&#8217;t deliver what this project needs, I can just walk away from the whole thing.  I should be working on my book anyway. <\/p>\n<p>Next time: We&#8217;ll add some cool stuff. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Qt is a cross-platform application and UI framework with APIs for C++ programming. In English, that means it&#8217;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&#8217;s a reason that so few [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[66],"tags":[233],"class_list":["post-15758","post","type-post","status-publish","format-standard","hentry","category-programming","tag-octant"],"_links":{"self":[{"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/posts\/15758","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=15758"}],"version-history":[{"count":0,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/posts\/15758\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=15758"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=15758"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=15758"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}