Project Frontier #11: Bug Hunt

By Shamus
on Jul 1, 2011
Filed under:
Programming

I don’t have a proper post to cap off this week. My attention is elsewhere right now. To placate you, I thought I would show you my mistakes and let you point and laugh at my folly. This is a collection of screenshots I’ve collected over the past month. These are moments when something has gone horribly wrong and I’ve smacked the screenshot key instead of (or just before) cursing.

frontier11_1.jpg

This happened when I was working on the river system. I was working on making the rivers bend, instead of doing a hard turn. This is done by hooking the river around one of the four corners of the region. Obviously, I chose the wrong corner.

frontier11_2.jpg

This was my very first forest. Well, tree. Okay, tree trunk. The point is, this was the very first of whatever it was going to eventually be. If you look closely, you may notice that some dullard constructed the trunk upside-down.

I think it looks like a bolt of lightning. Wooden lightning, I guess.

frontier11_3.jpg

This was REALLY early in the development of rivers. (These screenshots aren’t in any sort of order.) I was playing around with depth values, trying to discover what values looked good and what looked horrible. This was one of the latter.

These next two shots go together:

frontier11_4.jpg

frontier11_8.jpg

Ugh. This bug. This happened when I had finished the system to make a “species” of tree and was working on building them in groups. Sigh.

For you coders, I was doing something like this:

for (i = 0; i < number_of_trees_around_here; i++) {
  Class TreeGroup;
 
  TreeGroup.BuildAndAllocateAndDoOtherStuff ();
  //Forest here is a vector of trees groups.
  Forest.push_back (TreeGroup);
}

Pseudocode, obviously. The point is, I was making an individual group of polygons and jamming them into a vertex buffer. Then I was handing off the info for the vertex buffer to the forest. I do this all the time with structs. I rarely do it with Classes, which might help explain how I ended up making such a bone-headed blunder.

See, when Tree went out of scope (you know, every single time the for () loop did its thing, once for every kind of tree in this region) it would of course call its deconstructor. This would notice that, during it’s fleeting lifespan, TreeGroup had allocated a couple of handles for vertex buffers. It thoughtfully released the handles before sailing off into oblivion. Of course, those handles (NOT pointers!) had been passed along to Forest, and Forest was planning on using them.

Allow me to re-enact this drama:


INTERIOR – MY COMPUTER: DAY

MY PROGRAM:
Hey OpenGL! I need a couple of handles.

OPENGL:
You do?

MY PROGRAM:
Yeah. I guess I need two. One for a vertex buffer, and one for an index buffer.

OPENGL:
Okay kid. Index #15 and #16 are free. You can use those.

MY PROGRAM:
Thanks mister! NOW I’M DESTROYING THEM! I DON’T WANT THEM ANYMORE! HAHAHAHA!

OPENGL:
Whatever.

MY PROGRAM:
Hey OpenGL! I need a couple of handles.

OPENGL:
I’ll bet. Here, #15 and #16 were taken about a nanosecond ago, but they have recently become available.

MY PROGRAM:
Thanks mister! NOW I’M DESTROYING THEM! I DON’T WANT THEM ANYMORE! HAHAHAHA!

OPENGL:
If you say so.

MY PROGRAM:
Hey OpenGL! I need a couple of handles.

OPENGL:
#15 and #16 are very popular today.

MY PROGRAM:
Yippie! Now I have six handles! I’m going to draw lots of trees!

OPENGL:
Kids these days.

At this point I had (say) three groups, all of which were using the exact same handles. What SHOULD have happened was that all three of them would call the same handles. In effect, all three groups would render the exact same polygons. From my viewpoint, it would have looked like two-thirds of the trees were missing. The last third was getting drawn three times. (Which I wouldn’t have been able to tell.)

But instead it was doing crazy stuff. It would render groups one and two using their proper index lists, but using the vertices of group three. See, drawing polygons is a bit like playing connect-the-dots. Let’s say I give you a collection of dot positions:

frontier_ctd1.jpg

And then I give you a list of indexes: A C E B D A

If you connect the dots in that order, you’ll make a star. If I give you another bunch of dots:

frontier_ctd2.jpg

And the following indexes: A B C D E F G H A

You’ll draw a heart. (Sort of.) But if something goes wrong and I give you the first set of dots and the second list of indexes, you’ll end up drawing gibberish. Which is exactly what was going on in the screenshots.

The problem was, this strange behavior led me to believe the problem was elsewhere in my code. The code to create the trees and turn them into polygons is huge, and I naturally assumed that’s where the problem was. Since a lot of the trees are of similar topology (even if they are vastly different size and shape, their polygon makeup can often be very similar) this bug would appear to “go away”. So sometimes trees were missing. Sometimes they were scrambled. And sometimes things looked fine.

Five hours of slamming my head off the desk to find a problem caused by thirty seconds of sloppy coding. Sigh. That was time I would have preferred to spend on something else. Moving on…

frontier11_5.jpg

I don’t remember what I did to create this. I was messing around with the various climates and some numbers got away from me. It’s still oddly appealing.

And finally, here are a couple of shots of the trees without their textures:

frontier11_6.jpg

frontier11_7.jpg

So that was fun. Next time I hope to show off some sort of progress.

Enjoyed this post? Please share!


202020203There are now 83 comments. Almost a hundred!

From the Archives:

  1. Nonesuch says:

    First!

    The one with the rather sharp cliffs/mountains on the one side looks very LOTR, for whatever reason.

  2. Glenn says:

    I like that horrible tree-lightning. I feel like having some bare, twisted trees in a weirder region might not be that bad. Then again, that depends on the rest of the program.

    • Zukhramm says:

      I thought it was a rock at first. Give them a gray texture and they could be monuments left by… someone?

    • Neko says:

      I reckon it’d make a good base for a Morrowind-style mushroom tree.

    • StranaMente says:

      I thought the same thing. That tree could work to let the player understand he’s in a hostile enviroment, where dark, twisted things happen!

    • Mewse says:

      I’ve been working on something similar to this project for a couple years (although it’s going in a different visual direction, but is covering most of the same technical bases)

      For my trees, I’ve noticed that the best way to make them really feel twisted and ominous is to make the branch cross-sections not sit square with the direction the branch goes; that is, build the branch geometry diagonally through the branch cross-sections. Really seems to make the branches feel misshapen and slightly odd in a way that’s difficult to pin down without knowing precisely what to look for.

      Also, having branches angle off from their parent branch at quite sharp angles and not necessarily try to grow upward helped a lot too. But the orientation of the branch cross-sections was what really worked for me, in terms of making eerie-looking trees.

  3. Jonathan says:

    Screenshot #3 (the canyon) reminds me more of Narnia. It’s not *too* out of place as an occasional happening.

  4. anna says:

    I’m not familiar with OpenGL (or graphics programming in general), but I’m assuming that the handles OpenGL gives you are similar to file descriptors (i.e., a simple integer that you pass back to the OpenGL API, and that it then matches to some internal structures that it handles for you). Is that about right?

    Incidentally, this project has inspired me to go learn about graphics programming. So, yeah, thanks for that.

    • Simon Buchan says:

      Yep, exactly right. The main difference with file numbers is that you reserve N of them ahead of time, then actually initialize them later:

      // from memory, don’t kill me!
      glint buffers[2];
      glGenBuffers(4, buffers);
      glCreateBuffer(buffer[0], …);
      glCreateBuffer(buffer[1], …);

  5. krellen says:

    This is the best post of the series. I don’t think anything really gives a feel for the actual process of programming better than bugs.

    • Daemian Lucifer says:

      Second.

      Also,those screenshots are funny.And its always funnier when someone else has to spend lots of time debugging.

      • Joe says:

        Nearly everything I program is back-end stuff, where you never see results except through the output of other programs. I was just thinking to myself if I would rather try to debug something as visual as this or my normal work where the feedback is minimal at best.

        On one had, it’s very easy to see that there IS a problem in Shamus’ code (i.e. the tree) whereas my stuff you don’t know that there is a problem until it’s released and the customer starts complaining that everything is out of limits. Conversely, with all of the visual feedback it could be harder to pinpoint the exact problem, while usually all I have to do is follow my flowchart with some expected values.

  6. X2-Eliah says:

    Fill that huge river trench with lava and boom, instant death gorge.

  7. Herrsunk says:

    I have, when looking at the third screenshot, this uncanny feeling that I’m looking at a valley.

  8. benjamin says:

    thanks for showing us the kind of problems you encounter, it’s really interesting. make us less shamed by your awesomeness, too.

  9. Jordi says:

    I consider this a very proper post to cap off the week. Progress is nice, but it is also interesting to read about the process, and you describe it very well and with a lot of humor.

    I have to say though: I’m fairly sure structs and classes are almost exactly the same in C++ (the only difference being the default access setting of attributes and methods). Changing the “Class” class to a struct shouldn’t fix the problem. I think you have to do something like this:

    for (i = 0; i &lt; number_of_trees_around_here; i++) {
      Class* TreeGroup = new Class();
     
      TreeGroup-&gt;BuildAndAllocateAndDoOtherStuff ();
      //Forest here is a vector of trees groups.
      Forest.push_back (*TreeGroup);
    }

    Or something like that, my C++ is a little rusty. Am I completely wrong here?

    • Shamus says:

      Correct, structs and classes are basically the same. (The only difference I know of is that classes default to private members and structs default to public.

      But it’s a matter of convention. I don’t usually treat classes like that, because my classes usually have constructors / destructors. My structs never do.

      • DougO says:

        My favorite interview question! Yes, that is the only difference, per spec; intended to ease the transition from struct->class for all those C programmers trying to use this new-fangled object stuff.

      • Kdansky says:

        It will probably not work well for OpenGL handles, but I have started to use smart pointers everywhere else. Sure, it’s a tiny bit slower than a real pointer, but it saves so much time finding bugs! And if I have more time, I can optimize more. In the end, it’s rarely slower, and usually less wrong.

        Recommended read: Effective C++ Programming. It’s one of those books which are just a necessary read for the profession (if you code C++, that is. There’s also a great Effective Java by the guy who wrote most template classes in Java).

        • William Newman says:

          Incidentally, when it is possible to use a very simple smart pointer like std::unique_ptr — which seems to be possible in at least 25% of the cases where my code has ownership/destruction issues — it isn’t even a tiny bit slower. The cases where you need a heavier-weight smarter pointer in order to pass it around in a flexible way are admittedly more common, though, and do naturally tend to be slower.

          And thanks, Shamus, for posting this article, I was cheered up by laughing continuously while reading through it. I have been doing a considerable amount of debugging recently, and I wish I could make a trophy hall of averted dysfunction like this. (I can’t ’cause my recent debugging largely involves invariants in abstract data structures which aren’t even all that easy to document, much less make shiny pictures of.)

          • Mephane says:

            Yeah, modern compilers are extremely good at optimization. So good that STL classes and the like can be used without thinking twice, as most of their code is being optimized anyway. std::vector? All that remains is a raw array and a size value.*

            Now enter C++11 with rvalue references and move semantics, and even returning huge arrays from functions can be reduced to a pointer and an integer swap.

            *That’s why I say C++ is only halfway object-oriented. A lot of your class definitions will be remove upon optimization, making the speed differences between C and C++ miniscule in many circumstances. Whereas in languages like C# or Java, “what you see is what you get”. Objects, class hierarchies etc. remain intact in the final binaries (though they’re optimized, too), and can even be evaluated at runtime, something we programmers like to call “reflection”, by the way.

      • Mephane says:

        Yes structs do have constructors and destructors. Just like classes, they automatically receive implicit default constructor, destructor, comparison operator (equality and inequality) and assignment operator. You can only prevent them from being available by declaring your own as private, heh.

        Don’t get me wrong, I know you know all of this, but the audience here might not. So they should go home with the essence of this:

        In C++, classes and structs are identical, and receive all the basic stuff automatically if you don’t provide it. Their only difference is what happens if you omit the access modifier: on structs “public” is assumed then, on classes “private” (yes that is the one and only difference). And that by itself it just for compatibility with C (the evolutionary precursor to C++), where there is only “public” and thus no modifier keyword at all. You can mix structs and classes freely and exchange them one for the other.

        That said, I prefer to use structs for dumb objects that just need to hold some data, provide convenient construction, possibly comparison and a less-than operator when they’re being put in sets or maps. Everything more sophisticated becomes a class.

      • Simon Buchan says:

        Structs have one other differnce I know about: the default visibility of inheritance, so these are equivalent:


        struct foo : bar { };
        class foo : public bar { };

        That bug is why any type you define that has (or should have!) a destructor should also declare the copy constructor and copy assign operator, even it’s just as private declare-only:


        class foo {
        public:
        foo() { ... }
        ~foo() { ... }
        private:
        foo(foo& no_copy);
        foo& operator=(foo& no_copy);
        };

        With C++11’s rvalue references (supported by VC10), you can define the move constructor and move assign operator to get the syntax you wanted there:


        for (...) {
        Tree tree;
        tree.init();
        // std::move here says "feel free to throw this
        // value away if it's more efficient"
        // It's implied for temporaries (rvalues) like "Tree(...)"
        forest.push_back(std::move(tree));
        }

        without loosing any performance or safety (cant get the usage wrong):


        #include // for std::move
        struct Buffer {
        gluint handle;
        Buffer() : handle() {}
        ~Buffer() { reset(); }
        Buffer(Buffer&& other) { // move constructor
        reset(other.release());
        }
        Buffer& operator=(Buffer&& other) { // move assign
        reset(other.release());
        return *this;
        }
        gluint release() { // escape hatch from ownership
        gluint result = handle;
        handle = 0;
        return result;
        }
        void reset(gluint new_handle = 0) {
        // ??? been ages since I did GL.
        if (handle) glFreeBuffer(handle);
        handle = new_handle;
        }
        private:
        Buffer(Buffer& no_copy);
        Buffer& operator=(Buffer& no_copy);
        };
        class Tree {
        Buffer index_buffer;
        Buffer vertex_buffer;
        public:
        ....
        Tree(Tree&& other) {
        index_buffer = std::move(other.index_buffer);
        index_buffer = std::move(other.vertex_buffer);
        }
        // same for operator=
        // Don't need to, but you can get better error messages
        // when you try copying by private declaring copy ctor/assign
        // here as well.
        };

        The tricky bit is figuring out when to use std::move() and when not to – stick to move-only types for a bit to get the feel of which is used when. The nice thing is that all of STL is super move-friendly: if T is movable, then std::vector is movable as well! This means you can do the obvious solution to a lot of problems:


        std::vector<Tree> create_trees(Region* region) {
        int count = region_tree_count(region);
        std::vector<Tree> trees;
        for (int i = 0; i != count; i++) {
        trees.push_back(create_tree(region));
        }
        return trees;
        }

        And it will work fine, without any copying or anything!

    • Bryan says:

      I believe that’s a leak. You need to Forest.push_back(TreeGroup), not *TreeGroup. (And obviously Forest needs to be a vector of Class*, not vector of Class. But that’s OK, because unless you’ve written correct copy constructors, assignment operators, and maybe one other thing I’m forgetting, you can’t treat Class instances as plain old data anyway, so you can’t really put them into a vector. And getting those correct is hard. Much easier to make a vector of pointers, and manually delete each pointer before cleaning up the vector.)

      The way the code is here, you end up giving the vector a reference to the heap-allocated TreeGroup object, but I don’t think you can ever get the pointer back out of it, so you can’t ever delete it. Which means its destructor is *never* called, meaning the OpenGL handles are never freed. Which *might* work OK (when your program goes down, the handles *might* get freed automatically), but I don’t know if I’d trust it.

      (Though it may work to run through the vector with a “vector<Class>::iterator it”, then do something like “delete &(*it)”. But that seems much more complicated than using a “vector<Class*>::iterator it” and doing a “delete *it” instead. Of course it means every other time you use an iterator you need to dereference it before dereferencing it, so you need to “(*it)->Render()” or some such. Code is complicated.)

      Some of the various smart pointer classes may work for this too, but those tend to be complicated. It’s often easier (in the long run) to figure out an explicit ownership model for your heap-allocated memory, and just stick to that.

      • Simon Buchan says:

        The C++11 solution is super nice:


        vector<unique_ptr<Class>> Forest;
        Forest.push_back(new Class(...));

        for_each(Forest, [&](unique_ptr<Class> tree) {
        tree->Render(context);
        });

        Lambdas and move semantics make C++ a very nice feeling language :). (They even fixed the problem with >>!)

        • Mephane says:

          Absolutely. That’s why I am constantly trying to get the message that as soon as we upgrade to VS2010 (hopefully this year finally…) at work, C++11 should really be embraced, it introduces quite a bunch of nice features, even some where I think that it was a mistake that they were forgotten in the beginning (example: explicit virtual function overrides… so many subtle yet possibly devastating bugs introduced by not having this).

  10. Jarenth says:

    Screenshot #3 looks like the setup for a Chuck Norris joke.

    Meanwhile, the last two screenshots tell me that you’re ever going to procedurally create TRON, you got the digi-trees down already. So that’s a silver lining of sorts.

    In fact, all of these ‘bugs’ would do pretty well on your Hollywood Drug Trip Simulator.

    EDIT: Also, OpenGL sounds like a cool sort of dude. But I guess if you have to deal with those crazy function-call kids all day, you have to be.

  11. Primogenitor says:

    You could probably make some very interesting dream / other universe / other planet / drug-induced landscapes using things like that.

    • Sleeping Dragon says:

      Yeah, I’m kinda hoping this will become a feature of minecraft at some point, to have worlds/continents/huge chunks of terrain following a less realistic or more extreme world creating script. I know there are mods for this but it’s not really the same thing.

  12. Strangeite says:

    When I went whitewater rafting the Colorado River through the Grand Canyon, a very severe thunderstorm popped up right before one of the larger rapids (I believe it was Sockdolager). At this point the cliffs seem unnaturally tall and narrow. With the sky turning very dark and lightening illuminating the small gap ahead, the rocks around us appeared black with long streaks of white running through them.

    Add some rapids, a thunderstorm and put your point of view at the river level, and the third image would replicate my feelings of that time very well.

    p.s. Here is a link to a picture that shows the rapid in question, minus the thunderstorm.

    Sockdolager Rapid

    http://www.kerrickjames.com/2/Artists/16546/Mediums/Medium_2202008112855AM_0017%20AZ-2.jpg

  13. Irridium says:

    Is screenshot number 3 where Paul Bunyan dragged his axe across the Earth?

  14. karln says:

    damnit man you led me to expect interesting procedural insects

    (and possibly therefore a first hint at the gameplay ideas for this thing)

  15. UbarElite says:

    Screenshot 3: and so God doth parted the…earth?

  16. mac says:

    The third screenshot looks awesome. It would get old fast, if it was common, but as a ‘once or twice per map’ thing, it would be great.

  17. kikito says:

    I’d say that the “straight river through earth” picture doesn’t look *bad*; it doesn’t look “natural”, but it’s cool nonetheless.

    There’s actually at least one real-world structure that resembles it quite a lot …

    http://www.flickr.com/photos/seibi/207579197/

  18. As always, I am enjoying your wonderful amazing progress and the details with which you share them with us, but……
    And forgive me for bringing this off-topic subject up…
    Maybe someone already has and you’ve already answered and I missed it…
    Anyway, ahem, uh, are you on hiatus from Experienced Points and/or Stolen pixels?
    Did the Escapist fire you?
    Did you make the mistake of reading a negative comment from an ass-clown and are just simmering down before you continue?
    Is there an huge secret project in the making for the aforementioned places that I should be champing at the bit for?
    Anyway, sorry to bother you with a topic derail.
    OOoo, look, a cliff!

  19. bigGrandma says:

    I kind of like the eerie cliffs in the picture before the tree-outlines. They give a sense of end-of-the-world, land-of-the-dead texture. I am no good at such programming but I suppose that you could have a library of “extreme world features-landmarks” that could appear (in limited quantities and rather rarely) in your world. Or do you expect them to occur naturally (and randomly) through your procedural generation? Right now it seems to me that you are avoiding the extremes and aim for a more smooth world where faults (geological term) are unwanted.
    Great job, anyway.

  20. Zak McKracken says:

    Help an old man with little knowledge of C++, will you?
    so, the error was having the class definition inside the loop? You should have defined the class once and then made use of it inside the loop, ist that right?
    And what’s a handle in your world? Some sort of variable name, right?

    … I’m one of those engineers who only ever learned Fortran (and C64 basic, and Pascal, and Matlab, and so on…) properly, and some Python lately, but no “real” programming language, and everytime I start believing I know something about programming, I see one of those C++ things and my day’s ruined :(

    • Shamus says:

      The proper way to handle this case was to NOT create a class, then pass off the values in that class to something else. Sooner or later the original class was going to pass on, and when it went, it was going to take those handles with it. (Handles are identifiers. It’s just a number that identifies this thing I’ve allocated. It’s not a pointer, it doesn’t point anywhere. OpenGL creates a thing, and then gives me this number – #15. Then if I want to talk about the thing with OpenGL later, I use #15 and it will know what I’m talking about.

      The proper way is to put the values into the vector directly, instead of putting them inside of an object, and then passing them from that soon-to-die object to it’s destination.

      I’m sure that explanation was still too jargon-heavy. I apologize.

      • LVC says:

        I’ve mostly written garbage collected code so I’m having a little trouble understanding what you actually keep around. I think you are throwing everything away except the index and vertex buffer. These are stored in the Forest.

      • Zak McKracken says:

        wasn’t so difficult to understand, thanks!
        You want to tell openGL to create a thing, so you give it a bunch of data and tell it it’s a … tree. From then on, the tree will be handled by openGL, so if you want to do anything to it, that’s what you need the handle for. But now you didn’t pass the actual data to OpenGL but an object containing the data (call by reference instead of call by value, good old mistake). So after you destroy the object, because you thought the data was in good hands, OpenGL will also remove the data from the game world, because there’s nothing there anymore?
        Then you fill another object with data, pass it on and get the same handle as before … hmmm… but then I’d have thought you to only be able to see the last tree that was generated. Or were the connectivity lists handled separately somehow and survived the mess?

        The other thing I’m wondering about: Why would anyone define a class inside a loop? I thought you define a class, and then you start creating instances of it? (Which is, for oooold-school programmers, like defining a variable type and then creating variable with that type, only with, you know, objects)

  21. LMR says:

    First picture looks, appropriately, like a frowny-face.

  22. jwwzeke says:

    Several above have mentioned it, but I’d like to vote “Yes” for screenshot #3 as well. I love the idea of a Grand Canyon/Colorado River style of river… on occasion.

    Maybe a river wall depth/slope function that returns mostly “normal” rivers but with some really deep/steep ones every once in a while? Our river here through town in probably about 200′ wide, but only 8-12′ deep lots of years. Sort of the opposite of the Grand Canyon I suppose.

    Oh, also, speaking of bugs. Screenshot #2 looks like the leg for an epic sized insect of some kind. Please DON’T include that in this game. *Shudder* :)

  23. krellen says:

    I’m adding a comment to see if the front-page message changes, just like it told me to.

    (EDIT: It didn’t.)

  24. Cybron says:

    The one with the huge cliffs is a very interesting looking fantasy landscape.

    Also, I don’t think the river in the valley was all that bad. You could use it for some sort of canyon.

  25. Stephanie says:

    This is starting to look really pretty. Well, not the dodgy, here’s-what-it-looks-like-with-coding-errors screenshots, but the rest of it. I’m getting very curious about what gameplay mechanic Shamus is planning, mind.

    The one with the gorge looks like it was meant to be there: http://en.wikipedia.org/wiki/Corinth_Canal

  26. Skeeve the Impossible says:

    You know based on that first photo I would say you suck at playing Pipe Dreams

  27. Tree Looks Cool says:

    I like the upside down tree. Most people want trees that look “normal”. The upside-down tree would offer a unique bit of variety to your game. It is just “off” enough that most people will do a double-take and wonder what is wrong, never quite figure it out, and love the quirky things the game has to offer. Mind you, I have no idea what your game actually offers.

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>