Slashdot Mirror


Doom 3 Source Code: Beautiful

jones_supa writes "Shawn McGrath, the creator of the PS3 psychedelic puzzle-racing game Dyad, takes another look at Doom 3 source code. Instead of the technical reviews of Fabien Sanglard, Shawn zooms in with emphasis purely on coding style. He gives his insights in lexical analysis, const and rigid parameters, amount of comments, spacing, templates and method names. There is also some thoughts about coming to C++ with C background and without it. Even John Carmack himself popped in to give a comment."

33 of 399 comments (clear)

  1. Beautiful code but by discord5 · · Score: 5, Funny
    • It might be beautiful code, but 90% of it just renders a black screen in a horribly inefficient way.
    • For best effect the source code should be read in the dark with a flashlight in your hand.
    • // TODO : add the code for the lightswitch in this class

    I'll be here all week.

    1. Re:Beautiful code but by djlemma · · Score: 4, Funny

      Don't forget that you can't use your keyboard and your flashlight at the same time...

    2. Re:Beautiful code but by IcyNeko · · Score: 5, Funny

      John Carmack: The Kanye West of Video Game Programming.

      "Imma let you finish your Dragonborn DLC in a minute, but DOOM 3 has the cleanest source code of all time. OF ALL TIME!"

    3. Re:Beautiful code but by Stormwatch · · Score: 5, Funny

      // TODO : rehire Romero, Petersen, Hall, McGee, Prince.

      There, fixed. The engine may be fantastic, but Doom 3 is a horrible game that can't hold a candle to the previous titles. Or at least it can't hold a candle and a gun at the same time.

    4. Re:Beautiful code but by Anonymous Coward · · Score: 5, Insightful

      I did. No issues. Hint: The dark parts are supposed to be dark.

    5. Re:Beautiful code but by X0563511 · · Score: 4, Insightful

      Speak for yourself. I thoroughly enjoyed Doom 3. Quake 4 as well. I actually modded in more self-shadowing and flashlight shadows into Quake 4 - wasn't dark enough.

      --
      For large sets, this will be our guide even unto death, for the LORD will work for each type of data it is applied to...
    6. Re:Beautiful code but by DrXym · · Score: 4, Insightful

      The dark parts are dark because the game was completely bereft of ways to generate suspense or fear. Typical Doom 3 level - walk forward, lights out, invisible panel opens, bang bang bang, lights on, advance a bit, lights out, invisible panel opens, bang bang bang, lights on. It was scary the first time, after the 20th time it was just boring especially as the game was almost totally linear. FEAR suffered exactly the same issue.

    7. Re:Beautiful code but by Ash+Vince · · Score: 5, Interesting

      Daikatana and Alice were far from perfect, but they're still more enjoyable than Doom 3.

      I think you hit the nail on the head there, but possibly not in the way you mean.

      Doom3 was an absolute masterpiece of atmospheric gaming, but it was just too much. It set your nerves on edge in a way that meant playing for more than an hour or so was just too stressful. I love the levels, the monsters, the story (ok, its basic but what do you want from a FPS) but I just find playing it burns me out too quickly. It is just too good at making you feel uncomfortable and claustrophobic without any respite.

      I was just thinking back to Doom as I type this and from memory the big difference is that Doom had more variety with some levels set outside or in huge cavernous high ceilinged spaces. This variety is what made it great as it certainly had plenty of claustrophobia inducing levels too.

      --
      I dont read /. to RTFA, I read /. to offend people in ignorance.
    8. Re:Beautiful code but by wiggles · · Score: 4, Funny

      Did we play the same game?

      The atmosphere was interesting for the first 5 hours of gameplay, then it just got in the way of trying to play the game.

      I got to the point where, every time I'd walk through a door, I'd look to the side and fire into the demon I *knew* was standing there. It was like the line in Last Action Hero where Arnold walks into his apartment, kid in tow, walks into the bedroom and puts a few rounds into the closet door. A ninja falls out of the closet, dead, and the kid says, "How did you know there was a ninja in there?" Arnold says, "There's always a ninja in there."

      The only discomfort I felt was when I was squinting and cranking the gamma up just so I could see what I was doing.

      The story sucked, too. What do I expect from a FPS? Deus Ex, Bioshock, System Shock, and all their associated sequels, etc. etc.

  2. Limiting your market by tepples · · Score: 4, Insightful

    A developer needs to make an application for the hardware people have, not the hardware he wishes people had. Otherwise, he's likely to end up limiting his market to a subset that's not big enough to turn a profit.

    1. Re:Limiting your market by Uhyve · · Score: 4, Insightful

      Yeah.... No. Developers aren't going to drop half a colour palette because you're too lazy to look into which TVs don't suck.

  3. His Comment by phantomfive · · Score: 5, Informative
    Here is what John Carmack wrote:

    In some ways, I still think the Quake 3 code is cleaner, as a final evolution of my C style, rather than the first iteration of my C++ style, but it may be more of a factor of the smaller total line count, or the fact that I haven’t really looked at it in a decade. I do think "good C++" is better than "good C" from a readability standpoint, all other things being equal.

    I sort of meandered into C++ with Doom 3 – I was an experienced C programmer with OOP background from NeXT’s Objective-C, so I just started writing C++ without any proper study of usage and idiom. In retrospect, I very much wish I had read Effective C++ and some other material. A couple of the other programmers had prior C++ experience, but they mostly followed the stylistic choices I set.

    I mistrusted templates for many years, and still use them with restraint, but I eventually decided I liked strong typing more than I disliked weird code in headers. The debate on STL is still ongoing here at Id, and gets a little spirited. Back when Doom 3 was started, using STL was almost certainly not a good call, but reasonable arguments can be made for it today, even in games.

    I am a full const nazi nowadays, and I chide any programmer that doesn’t const every variable and parameter that can be.

    The major evolution that is still going on for me is towards a more functional programming style, which involves unlearning a lot of old habits, and backing away from some OOP directions.

    One might suggest that every good programmer, if they spend enough time improving, eventually moves toward a more functional programming style.

    --
    "First they came for the slanderers and i said nothing."
    1. Re:His Comment by MobyDisk · · Score: 4, Funny

      You remind me of my mom, who ends every political debate by stating that as people become older and wiser they tend toward being Republicans.

    2. Re:His Comment by girlintraining · · Score: 5, Insightful

      One might suggest that every good programmer, if they spend enough time improving, eventually moves toward a more functional programming style.

      Good programmers don't move towards any one style, they become familiar with all of them and use them when and where appropriate. Just like computer geeks. You find Linux one day, install it, then fall under the spell of believing this year will be the Year of the Linux Desktop. But after awhile, you reach the second plateau of understanding -- Linux is good for some things, but not everything. The third plateau is no longer caring which tool you use, as long as its the best tool for the job.

      --
      #fuckbeta #iamslashdot #dicemustdie
    3. Re:His Comment by meerling · · Score: 5, Funny

      Especially with the rising symptoms of Dementia and Alzheimers. :)

    4. Re:His Comment by jez9999 · · Score: 4, Interesting

      Yet the fourth plateau is the realization that if one vendor becomes extremely powerful, it tends to create huge barriers of entry for others and so your choice is reduced, sometimes drastically, and therefore it can be a good idea to just arbitrarily support competition even if what everyone uses is good enough right now.

    5. Re:His Comment by Rhacman · · Score: 5, Insightful

      As I get older, I gain more experience and hence believe that my opinions carry more weight. Since me and my close knit group of similarly aged friends agree with me it stands to reason that what I have come to believe now is in fact correct and that others who disagree with me are simply immature.

      --
      Account -> Discussions -> Disable Sigs
    6. Re:His Comment by Alomex · · Score: 4, Insightful

      4) The programmer discovers that functional languages do not provide enough access to basic data structures to write high volume state of the art applications, and rewrite many key portions of the code in C thus coming full circle.

      Whoever writes a functional language that understands arrays and pointers will rule the world.

    7. Re:His Comment by FrangoAssado · · Score: 4, Informative

      That's a fair point, but you have to pay closer attention to what Carmack wrote:

      I am a full const nazi nowadays, and I chide any programmer that doesn’t const every variable and parameter that can be.

      The major evolution that is still going on for me is towards a more functional programming style, which involves unlearning a lot of old habits, and backing away from some OOP directions.

      He said functional programming style, that doesn't necessarily mean using a functional language -- the point is that he is going in the direction of functional style when writing C++, which would involve, among other things, making as much as possible immutable (hence being a "const nazi").

    8. Re:His Comment by MobyDisk · · Score: 5, Funny

      Mom, I told you nobody mods you up until you register.

  4. Mostly right, but a few problems. by Anonymous Coward · · Score: 4, Interesting

    I've developed for large game and non-game projects, and each needs a different approach. Console games especially have serious problems with dynamic memory allocation (they don't typically have swap files and can die due to heap fragmentation) so you have to avoid a lot of convenience libraries like STL.

    STL, however - especially in newer compilers that support C++0x - is actually quite good and is very, very robust. It's a good way to avoid a lot of the memory management bugaboos that happen when you *are* doing lots of dynamic/heap allocation. So I would very much endorse a sane amount of STL use in desktop code.

    The other thing that rubbed me the wrong way here was public member variables. Since inlining and move semantics make getters and setters essentially free, there is no good reason to expose bare, public variables on anything but the simplest, most struct-like objects. The biggest source of weird, hard to trace bugs in our code at the game studio were often due to people modifying public members of other objects in unexpected ways or at unexpected times.

    Having public, non-const member variables actually hurts a principle the author supports, which is "Code should be locally coherent and single-functioned". This means that an operation should do one thing and put you in one of several known and easily discoverable states, even on failure. That is, if I say, make this guy do X, then either he does X or he fails and ends up in a known state. If that state is available in the form of modifiable public data, then his state can get messed with at any point along that path by some other code, and the final state (in cases of success and failure) is not fully known. At the very lest, making data private means that only certain code paths can modify the data, and it's much easier to keep state coherent.

    Anyway, that's just my $0.02.

    1. Re:Mostly right, but a few problems. by Zan+Lynx · · Score: 4, Insightful

      The other thing that rubbed me the wrong way here was public member variables. Since inlining and move semantics make getters and setters essentially free, there is no good reason to expose bare, public variables on anything but the simplest, most struct-like objects. The biggest source of weird, hard to trace bugs in our code at the game studio were often due to people modifying public members of other objects in unexpected ways or at unexpected times.

      There's zero difference between a public getter/setter pair and a public variable. Encapsulation and future proofing the interface? In a game codebase? You'll never use it, and if you did need it the code editor can search and replace for you. Meanwhile, writing piles of getter/setter functions is a waste of time. Unexpected modification of public values doesn't get any better when its done through a setter function.

  5. Re:Not the best analysis by gbjbaanb · · Score: 5, Informative

    the concept of the bracket placement there is to emphasise indentation over bracketing. Once you "get" the view of it, it becomes a nice thing to look at, similar to python code.

    I don't use it nowadays (too many coding standards that are written for the bracketing-style) but I appreciated it when I did. There's nothing wrong with the style, so I hope that you pass any code you review written in this style and focus on the important parts like readability of the code, good naming, commenting and the like rather than subjective opinions.

  6. Re:Else ifs - yuck by Anonymous Coward · · Score: 4, Insightful

    Are you an idiot? Case statements don't do the same thing as if else. The example in the article does some floating-point compares. How do you represent that as a case statement in C++? Come on, I'm waiting. Oh, that's right. You can't.

    Case statements take an integer value and switch based on it. You cannot have case (dot < -epsilon) or case (dot > epsilon). Got that? Good.

    wonder what else ID missed

    If you think Carmack "missed" something, take a deep breath, count to ten, and figure out what you missed.

    No, he's not perfect - I found a bug in DOOM 2 that he never tracked down - but until you prove yourself STFU about how Carmack may have "missed" something you only learned on Stack Overflow anyway. Carmack is a Level 99 Wizard while all you can do is read the descriptions of the kinds of spells he can cast.

    God people like you are annoying. Shut up and think, and you might learn something.

  7. Comment-free programming by swillden · · Score: 5, Interesting

    I really liked this bit, because it's something I've been really focusing on for the last year or so, and I think it has significantly improved my code:

    Comments should be avoided whenever possible. Comments duplicate work when both writing and reading code. If you need to comment something to make it understandable it should probably be rewritten.

    Comments can be useful, IMO, but primarily only for generating documentation (think Javadoc or doxygen, etc.). Other exceptions include bits of code that perform highly-optimized mathematical calculations, in which case I think the best solution is to write a proper document and then add a comment linking to the document, and bits of code that do something which apparently could be done differently but for some other reason must not -- assuming that explanation doesn't belong in the doc-generating comments.

    Other than that, I find it makes my code a lot better if every time I find myself wanting to write a comment to explain some bit of code's purpose or operation, I instead refactor until the comment is no longer necessary. Often it's as simple as taking a chunk of code from one method/function and pulling it out into another with a well-chosen name, or else introducing a variable to hold an intermediate value in a calculation, with a well-chosen name. Sometimes the fact that a bit of code is hard to explain is a strong indicator that the design is wrong, that stuff is mashed together that shouldn't be.

    The bottom line is that I've found eliminating comments does more for improving the readability of my code than anything else, and I've gotten similar feedback from colleagues whose code I critique by pointing out that they can eliminate their comments if they refactor a bit.

    --
    Note to ACs: I usually delete AC replies without reading them. If you want to talk to me, log in.
  8. Most of His Admiration Is Not Technical by Greyfox · · Score: 5, Insightful
    Most of his admiration appears to be issues of code formatting and lack of comments, not the technical design of the code. He started to lose me even before his rants on the ugliness of STL and boost libraries. Do the objects play well together? Is it easy to assemble them to accomplish tasks in sensible ways and with as little set-up as possible on the part of the user of the library? These were not questions I saw answered.

    And a note on the relative evil of comments; bad or not, well placed comments have saved me an awful lot of time when taking on maintenance of code bases in the past. Most of the time they can't present a design document to you, or if they do it covers the design at the start of the project, a decade and a half earlier. Code is a method of communication between two programmers, but if the code doesn't suffice to illuminate the design the original programmer had in mind, I'd really appreciate a comment explaining his thoughts. Especially if the particular section of code is complex, and especially if I'm the guy writing it and end up being the guy maintaining it a couple years later.

    --

    I'm trying to teach myself to set people on fire with my mind... Is it hot in here?

  9. Re:Else ifs - yuck by phantomfive · · Score: 4, Informative

    I know some situations else-if statements are necessary, but my understanding is that case statements are far faster.

    Very often rules about efficiency like this one are incorrect. Sometimes the compiler will even change things completely when you compile it. In one example, I once carefully wrote a function to only have a return statement at the end, because I (somehow) thought it would be more efficient. Then I looked at the assembly output from the compiler, only to find that the compiler had added in all the extra return statements I had so carefully avoided. After that, I just went with what was most readable.

    If you really care about efficiency, there is one way to do it: you MUST time your code. Try the case statement, and time it. Then try the if statements, and time it. If you don't time it, you are just guessing and you WILL be wrong.

    The case of the if statements in the article is a tricky example, because it is a range, and writing it as a switch statement would likely be a large table. Doing this could actually slow things down because it fills up the memory caches with mostly needless information. Note this can also be a problem with traditional optimizations like pre-calculated tables or loop unrolling, they can actually slow things down.

    TLDR: If you want to make your code efficient, you need to time it.

    --
    "First they came for the slanderers and i said nothing."
  10. Re:Solaris Code by phantomfive · · Score: 5, Interesting

    Write a review of Solaris code, and it'll probably get posted on Slashdot, too. I for one would be interested in reading that.

    --
    "First they came for the slanderers and i said nothing."
  11. Re:Else ifs - yuck by Anonymous Coward · · Score: 5, Informative

    Often as in you've measured it, or often as in "I'm making shit up"?

    A good compiler will never implement a case statement as a load of if-else's, unless the case values are sparse, or you're not optimizing.

    Meanwhile, transforming a set of if-else statements into a lookup table is seldom possible unless the if-elses all compare the same integer variable to a constant. In that case, it can in theory, but almost certainly won't in practice.

    Other things being equal, a switch statement with contiguous constant cases will almost always compile to faster code than the equivalent set of if-elses. And it will be far faster. Every if/else induces a branch, and mis-prediction will be severe on most of those branches, causing 10-20+ cycles of stall on modern processors. The jump table mispredicts almost always, but only once. If one arm is taken 99% of the time you can speed things up by using an if/else and then a switch, but that's a rare case.

    I appreciate the fact you're responding to the idiocy of the above post, but your points are as wrong as his.

  12. Re:Not the best analysis by Rhacman · · Score: 5, Insightful

    This is one of those topics of an almost religious fanatacism but I tend to agree. I want my braces to match in the same column and have an easier time looking at code with vertical spaces between blocks of related operations. Functions should still be short enough that they fit on a modern screen (with rare exceptions).

    The whole concept of self-documenting code irks me too. Too often programmers use it as an excuse for not writing comments at all. Of course the code should be written clearly enough to the point where you don't need the comments to understand how the code will execute, but I don't think you should count on that as showing what and why that block of related operations is doing what it does. Comments can certainly be overused and underused and while commenting every single line is absurd in most cases, not commenting under the umbrella of "self-documenting" code can be detrimental as well.

    --
    Account -> Discussions -> Disable Sigs
  13. You asked for it. by Dan+East · · Score: 4, Informative

    How do you represent that as a case statement in C++? Come on, I'm waiting. Oh, that's right. You can't.


    switch (dot < -LIGHT_CLIP_EPSILON ? 1 : dot > LIGHT_CLIP_EPSILON ? 2 : 0) {
            case 1:
                    sides[i] = SIDE_BACK;
                    break;
            case 2:
                    sides[i] = SIDE_FRONT;
                    break;
            default:
                    sides[i] = SIDE_ON;
    }

    Yeah, yeah, I know, that's totally ridiculous (although I did see things as bad and worse as a CS instructor's assistant whose job it was to grade Pascal students' programming assignments back in the day - that was very interesting to say the least).

    On a side note, why can't > and < characters be used in a code element? Um, that's lame, especially for a site that discusses programming so much.

    --
    Better known as 318230.
  14. The things he likes are the things I hate by Dixie_Flatline · · Score: 4, Insightful

    He loves the lack of white space, I hate it. Cramped code is irritating to read. If you want to take up less vertical space, reduce your font and increase the whitespace. You have a better sense of the separation of statements, stronger scoping and less room for error.

    He also loves the lack of comments. I remain firmly in the camp that if you eschew comments as common practice, you're an idiot and you should stay away from programming on big teams.

    It's not a clarity of code issue. I expect your code to be clear, too. But even after 20 years of programming, I read English faster than I read code. A description of an algorithm in English is going to be more terse than the code that implements it. Your code has to account for edge cases, but I probably just want to know what the code does and how the code does it at a high level so I can get a sense of the system and architecture. A descriptive method name only tells me WHAT the method does, not the manner in which it's done.

    English (any natural language, really) is a powerful language with extraordinary expressive power. I don't understand why programmers are constantly trying to sweep it under the rug. Don't fill your code with useless comments like // increments the counter by 1, but if you're doing a non-trivial mathematical calculation that takes a whole method to encapsulate it, let me know what I'm getting in to.

    Code comments--especially system level comments--should include the name of the author or current maintainer, as well. I tag my methods with my name and the date that the code was put in so people know where to go if there's trouble. They don't have to hunt through perforce time-lapses to see that I checked it in, they just email me.

    And have some consideration for the new guy on the team, or the team that has to use your code 5 years in the future. They can't ask you questions, the context of the situation is lost, the code-base might be in the middle of being re-purposed (common in the game industry--which is where I am); comments are essential to maintainability. Man, I do code reviews and people often manage to forget exactly what they were trying to do, and it's only been a few hours. We always work it out, but if there were a comment, we wouldn't even have to spend THAT time.

    Use comments. Use them wisely. It makes you a better programmer because you're wasting less of OTHER people's time.

  15. Re:Not the best analysis by DeadCatX2 · · Score: 4, Insightful

    My take on comments:

    Write the comments first, describing the overall goal, inputs and outputs.

    Then write the actual code that implements the comments.

    --
    :(){ :|:& };: