Hacker News new | past | comments | ask | show | jobs | submit login
Doom3 is the proof that “keep it simple” works (gamedev.net)
201 points by GeekandProud on Apr 1, 2015 | hide | past | web | favorite | 108 comments

This comment by Carmack seems to imply that the restrained use of advanced C++ features was more by accident then by design:

I had C and Objective-C background, and I sort of "slid into C++" by just looking at the code that the C++ guys were writing. In hindsight, I wish I had budgeted the time to thoroughly research and explore the language before just starting to use it.

You may still be able to tell that the renderer code was largely developed in C, then sort of skinned into C++.

(Source: http://fabiensanglard.net/doom3/interviews.php)

That doesn't necessarily imply that he's saying he should've used more advanced features. It could just as well mean he should've understood better the features he did use.

Agreed - but the post implies all of the choices made were mindful choices. Carmack indicates that is not necessarily so.

Fabian Sanglard's exploration[1] of Doom3 is much more in depth than this article, though the author does quote Sanglard's analysis albeit with a small source link

[1] http://fabiensanglard.net/doom3_bfg/index.php

For what it's worth, that code review is for Doom 3 BFG. This is the review of vanilla Doom 3:


The vanilla code review goes into the app structure first, and (what little I've read of) the BFG review compares that codebase against the vanilla one.

Thank you, much better link.

These adverts pretending to be learning experiences, really bother me

"CppDepend Tutorial" would be a better title

Ads that are decently educational? Compared to what we deal with currently, I have no problem with edu-ads becoming the next great trend in advertising.

The issue is that we lose the distinction between content and ad. As this distinction blurs, less people will be able to say which is which. I guess the real question underlying this is the one underlying advertising in general, how much are we morally allowed to manipulate someone who did not give informed consent for the purpose of modifying their behavior in a way that is beneficial to us?

You must be the target audience then because I read a great article about Doom3 and have no clue what youre talking about. I also dont know what CppDepend is...

> Let's go inside its source code using CppDepend and discover what makes it so special.

And the article is written by the creators of CppDepends

But as somebody with zero experience, I wasn't aware when reading that this was a tool and not a part of the language itself. I read articles like these because I have an interest and a lack of knowledge, and I'm learning all kinds of things today.

I've been a longtime fan of Carmack, and I wish I could read and understand his work for myself!

>But as somebody with zero experience, I wasn't aware when reading that this was a tool and not a part of the language itself.

That's the very problem he tries to address I believe...

I think he refers to the tool the author was using to query the code.

I was seated at the restroom at work yesterday morning when I noticed a strip of plastic had been added to the gap between the metal stall and the metal stall door. It was branded Privacy Cover (patent pending).

Welcome to the future where everything is branded and everyone is an Avon lady, endorsing some set of pet products :)

[a] http://www.rbahelp.com/toilet-partition-privacy-strip-instal... [b] http://www.partitionsandstalls.com/partition-privacy-cover.h... [c] https://www.youtube.com/watch?v=WxWnqR77Dzc&feature=em-uploa...

You might be interested to know that other parts of the world seem to have solved this quite ingeniously.. At least in Australia and New Zealand it is very common to have stalls with doors hinged and sized so when shut they overlap an outer bit. No gap.

Yeah, fancy west-pacific door technology. Who would have ever thought that a door can block your view if built properly? :P

I didn't realize people peeking through the slim slit was an issue.

I've been to America - on some stalls that gap is not what I would call slim.

In Chinese public bathrooms, it's even less of an issue

That's an example of "content marketing".


This is the "nicest looking code [you] have ever seen" ?

What's wrong with this?

Over 150 lines of code in a simple method?

C-style declaration of all the variables in the beginning? (Yes, I know what Carmack said about how he written the project; this explains it, but doesn't make it good C++ code.)

Unclear flow with just one comment, which doesn't really explain anything?

Why do you say it's a simple method, if it is 150 lines long? Are some lines not necessary?

There is a logic to keeping logic together if it is isolated: http://number-none.com/blow/john_carmack_on_inlined_code.htm...

Context is important, to anyone developing D3 code, this code might be obvious and comments would be unnecessary. Considering 'geterdone' attitude of many game projects, with high levels hackery, this is very nice code.

Thanks for the link, it's a very fascinating read! By the way, I discussed this issue on Programmers stack exchange a while back, you might find this interesting: http://programmers.stackexchange.com/questions/277098/method...

It's a "simple method", but it's responsible for a bunch of initialization, so yeah, it's kind of expected to be long.

Notice, though, that each section is pretty straightforward in what it does...basically forEach's.

You could make the argument for greater polymorphism in types, or something like a visitor pattern over collections or something, but honestly this is readable and maintainable code.

More comments at the function declaration would've been nice, but the implementation is pretty straightforward.

You should try a Perl codebase. In just this one module I'm looking at, there's methods with 505, 880, and 995 lines.

A popular VoIP product has switch statements that are in the thousands.

Is it automatically generated?

No, hand written.

I found no difficulty understanding what it does. Perhaps you need to acquire greater proficiency at reading code.

Well, some familiarity with the game helps, too. This is the code that runs when a certain pick-up item's effect activates.

Any critiques in specific?

   if ( ent->GetRenderEntity()->gui[ j ] && 
   ent->spawnArgs.FindKey( j == 0 ? "gui_demonic" : va( 
   "gui_demonic%d", j+1 ) ) ) { ent->GetRenderEntity()->gui[ 
   j ] = uiManager->FindGui( ent->spawnArgs.GetString( j == 0 
   ? "gui_demonic" : va( "gui_demonic%d", j+1 ) ), true );

Fair enough.

Just curious, are you cherry picking, or are there legitimately many areas of the code like this? I haven't had a chance to look yet.

To be honest i didn't look at all the code, but yes there are many areas like this.

Lots of structs is how http://handmadehero.org is being built.

"As we can observe many structs are defined, for example more than 40% of DoomDLL types are structs. They are systematically used to define the data model. This practice is adopted by many projects, this approach has a big drawback in case of multithreaded applications. Indeed, structs with public fields are not immutable."

> Doom3 is the proof that “keep it simple” works

This statement suits even better to id Tech 3 (Quake 3). John Carmack mentioned: 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 [Doom 3]: http://kotaku.com/thanks-a-few-comments-in-some-ways-i-still... and he linked to his blog post about "Functional Programming in C++" on the now defunct but former popular AltDevBlog: https://web.archive.org/web/20130126164111/http://www.altdev...

The engine of Doom 3 (id Tech 4) was good. The game itself was repetitive and a bit boring. It was a few months late Aug 2004, and Far Cry 1 (March 2004) already overshadowed it in terms of graphics and gameplay.

Licensing the id-Engine to other companies was very successful during the id Tech 2 (Quake 1/2) and id Tech 3 (Quake 3) era. Back then the Unreal engine was only used in Unreal and Unreal Tournament '99, with Deus Ex as an early adopter.

But few games were released starting with id Tech 4 (Doom 3) and later id Tech 5 (Rage). Compromises during the development of id Tech 4+ meant it wasn't suitable for many different purposes. Only small levels with a few light sources were possible - the later "mega texture" addition partly solved that issue but meant a huge hardware step during development and prevented Mods and custom maps. In retrospect the Unreal 3+ and CryEngine 1+ offered comparable results without sacrifice their universalizability. http://en.wikipedia.org/wiki/Far_Cry_(video_game) , http://en.wikipedia.org/wiki/Doom_3 , http://en.wikipedia.org/wiki/Id_Tech_4

The Call of Duty franchise is still using modified Quake 3 engine heavily extended with Ritual's ÜberTools, now named IW engine and comes with many modern features like texture streaming. Half Life 1+2 are based on a heavily modified Quake 1 engine. http://en.wikipedia.org/wiki/Quake_engine , http://upload.wikimedia.org/wikipedia/commons/6/63/Quake_-_f... , http://en.wikipedia.org/wiki/File:Quake_-_family_tree_2.svg , http://en.wikipedia.org/wiki/Heavy_Metal:_F.A.K.K.%C2%B2

All of these id tech engine games can be edited with the GtkRadiant map editor (Half Life, Call of Duty, Quake 3, Doom 3, etc.): http://en.wikipedia.org/wiki/GtkRadiant

I was surprised to learn that CoD still uses something based on the Quake 3 engine. Any idea how much the engine has changed?

Yeah, in particular I'd be interested to know if CoD still uses Quake 3's VM model.

Wait, HL2 uses the Quake engine? I know HL1 did, but I thought HL2's engine was Valve's in-house work.

HL1 uses the GoldSrc engine, which is a heavily-modified version of the Quake engine.

GoldSrc was again heavily modified to become the Source engine, but it does retain direct lineage to Quake.


Oh, that's pretty cool.

Gotta love how well-known brand names like Source originated as internal dev jargon. I've always been fascinated with things like that.

I wonder what John Camack's current thoughts are on C++ design. I rarely use inheritance and usually have either inlined functions or functions that operate on arrays or many objects at a time. I also use templates when they deal with straight type substitution (including functions). I am though starting to get familiar with extern templates to be able keep compile times down.

If anyone wants to see the opposite of keep it simple, take a look at the source for the build engine. It will blow your mind.

I wonder why they opted not to use references? It seems an odd choice to me, did id software give an explanation?

Probably because Carmack didn't actually know C++[1], and C doesn't support references.

1: https://news.ycombinator.com/item?id=9303387

The most common argument:

Pass by reference hides the implication of a side effect on the parameter. If you expect the function to manipulate the parameter, passing by pointer is clearer.

Pass by reference was also only added to efficiently support copy constructors and more importantly operator overloading, both of which are syntactic sugar that a C with Classes style would normally avoid.

Template programming also requires pass by reference but templates are sugar on sugar so not the core reason why pass by reference is needed.

Ps. Disclaimer: I haven't checked if the Doom3 code uses these features.

Fair points, although all references should ideally be const unless there are side effects. It's not perfect though, since you can't tell from just viewing the calling code, you have to check the function prototype.

References also help avoid problems with pointer aliasing, and make it clear that the called function definitely cannot delete the passed objects. So it's more than just syntactic sugar.

(n.b. I'm not arguing that pointers are bad and should never be used, I still just don't see a clear reason never to use references. The id Software coders are smart, they must have had good reason to pick their choice)

Also, references can't be nullptr, which eliminates needs for null checks and makes clear that nullptr isn't a valid value. RVO also makes "returning" values through non-const references not as necessary.

Though, the most important thing is consistency and readability over using fancy new features, so they should stick to the style they were using for the project.

I thought exactly the same. Probably they needed to model an empty state and decided that a null pointer was the easier way to do it.

If you read this article and agreed with it, you should definitely read this next: http://lesswrong.com/lw/dr/generalizing_from_one_example/

I think you meant "If you only read the headline and agreed with it".

Depends on how you interpret the "argument." If the argument is "all software projects can/should 'keep it simple'" then yes, it's clearly a logical fallacy.

But if the argument is "'keep it simple' works for some software projects," one example proves the point. This seems the more generous interpretation.

As someone who wants to learn modern c++, what are some good resources/books to learn from ? I have python and java experience and I have been reading Accelerated C++ since a while now.

Not a definitive list, but these are good:

  The C++ Programming Language, 4th edition
  Bjarne Stroustrup

  The C++ Standard Library, 2nd Edition
  Nicolai M. Josuttis

  Effective C++, More Effective C++, Effective Modern C++ 
  Scott Meyers


I would also add Effective STL too.

A Tour of C++ by B. Stroustrup is a good start point for a beginner too

Well, don't forget about exceptions, unless you decide to ban them like many people do. So add:

Exceptional C++ by Herb Sutter

More Exceptional C++ by Herb Sutter

Exceptional C++ Style by Herb Sutter

And Templates:

C++ Templates: The Complete Guide by Josuttis & Vandevoorde

And of course you need some background in generic & metaprogramming, so add:

Modern C++ Design by Alexandrescu

Advanced C++ Metaprogramming by Gennaro

So you're looking at over ten books. What does this say about C++? Can you think of another language that has a ten book prerequisite?

All of that is hardly prerequisite for using modern C++ on a day-to-day basis. You can get away with just reading "A Tour of C++" and the Effective C++ books.

If you want to start writing highly generic libraries with the intention of submitting them to boost, then absolutely you should be reading everything in your list and more. But how many C++ programmers are writing boost libraries?

Yeah and the Exceptional C++ series is not 'about exceptions' either. It looks like he just googled 'c++ exceptions book', and the same for templates and metaprogramming, probably.

It is also excellent for people who have worked in an older style of C++ and want to get a jumpstart on modern practices and the new C++11 features and keywords.

Thanks, I'll read through those as well.

As an addendum, I highly recommend not reading decade old source code like this as an example of modern C++. C++11/14 have changed the language so much for the better that anything targeting C++03 should be ignored for new projects and especially for new learners.

Also, avoiding Boost and Qt early on is also a good idea. Both have tremendous stylistic and design differences from ISO C++ and while the language supports all of them when using the Boost libraries and Qt toolkit you need to shift mindset entirely in how you are writing code to match the backing architecture. Learn the core language first.

I disagree because writing a Qt program is often the end goal.

the STL is also totally unlike the standard C library. are things like <algorithm> or <string> to be avoided because the core language is <cstdio>?

I really enjoyed Effective Modern C++. It covered the interesting stuff I wanted to know, and skipped the introductory "in case you've never programmed before" fluff.


This is back in the good old days when C++ didn't have all the crap, and everyone wanted to stay away from doing advanced stuff with STL and RTTI. Linus famously said that Linux is written in C if only to keep away the C++ developers.

Having said that, I used to write tutorials using the old ways as well: http://flipcode.com/archives/Theory_Practice-Issue_06_Event_...

Does anyone love the new C++, and if so, what are their experiences with being on teams that use the full range of functionality? Do you need a language lawyer?

I do enjoy programming in C++11 style. What I like the most is that once you understand the quirks, you would see a lot of opportunities to improve performance but only when necessary (Like using moving semantics if you have to pass a big object through several function calls)

Also STL has improved a lot and I am very happy that I don't need to include a huge dependency such as Boost or POCO just to have a hash table for instance.

This comment represents the my biggest frustration with current programming tools & practices. You shouldn't have to include any libraries. Ever! And you shouldn't have to rewrite some code that does something that's already available and well-written. That, and, if you want to include some functionality, there will be 13,000 versions of the same functionality for you to review before you decide which one to learn and commit to. (And it is easier to write it yourself sometimes.)

There's no reliable way for languages themselves to standardize and aggregate the work that others do. You just hope the language designers are willing to put up a new version, (and that it's a decent one) and they end up doing it ever-so-slowly because it's not automated in any way. Hand-pick and re-roll. There's no metric-based signaling or automated analysis or anything, it's just whatever your experts opine.

"You shouldn't have to include any libraries"

"you shouldn't have to rewrite some code that does something that's already available and well-written"

How are those not contradictions?

You tell the compiler what data type you're trying to use, and it finds a high-performance implementation for you over the internet.

That sounds incredibly safe.

Have you tried it? Or are you just imagining an extremely terrible implementation of the idea so you can write short quips about how bad it must be?

For basically every piece of software I work on this would have horrible security implications. Let me spell it out in black and white: every time someone does a deployment, by default it will download code from the internet and incorporate it into production code. All one would need do is subvert one external code provider and they'd have the ability to inject code into countless production systems at will. How much do you trust github or bitbucket? Would you give them the keys to your business, and your customer accounts?

Compile time never sounded so fun

I felt the same after reading all of ids engines source code, such as Quake 1-3. Those were C only, however.

What's the IDE he uses?

Visual Studio, like most game developers.

> Note: Please offer only positive, constructive comments - we are looking to promote a positive atmosphere where collaboration is valued above all else.

And keep your rose-colored glasses on at all times. You shall see no evil, hear no evil, speak no evil and never grow out of childhood.

No one have issues with source code files 5100 lines long? https://github.com/dhewm/dhewm3/blob/master/neo/game/ai/AI.c...

You make it sound like it is a single 5100 line long method. It seems actually very well organised in that file.

If you're using any kind of IDE then this wouldn't bug you as you can just jump to the point in the file you need.

And if you're not using a fancy IDE, jumping around in one file can be much easier than jumping around a dozen files.

Demonstrably, 5100 line long files are no barrier to quality software.

Not to brag but https://github.com/dhewm/dhewm3/blob/master/neo/idlib/Heap.c... (from line 154 down) that seems like another point against using tabs.

I always heard "Tabs for indenting, spaces for aligning."

These days just use expand tab, in an age of online code review tools etc it's just better not to have to configure every system to interpret tabs to your given number of spaces - just write the damn spaces into the file.

> "it's just better not to have to configure every system to interpret tabs to your given number of spaces"

The entire point of "tabs to indent; spaces to align" is that you don't need to make sure everyone displays tabs the same way. If we are using that scheme and I have mine set to 4 spaces but you have yours set to 8, everything is fine. There is no problem there.

That works but takes a lot of discipline. More than any team I ever worked with had.

In my experience, the difficult part is getting people to understand it.

Yeah, but since every time someone new comes along who doesn't understand what this means (witness the replies you're getting)... no tabs. It's just easier this way.

Mix tabs and spaces in code and you're in for a fun time :D

You think that's bad:


Scroll down and watch the readability disappear.

append ?ts=4 to the URL to change GitHubs default 8 character tab to 4 characters wide.

Is that really a GitHub thing? When I view diffs in the command line with Git, it always shows tabs as 8 spaces too.

8 spaces tends to be the de facto standard tab width. But because tab is it's own ASCII character (0x09), much like how space (0x20) and the lower case letter 'a' (0x61) are, it means it's up to whatever text processors used (eg diff, vim, GitHub web application, etc) to interpret a tab character by whatever width they choose. Which is why tab spaces are a per-application setting, eg:

    diff --tabsize=4 ...
    vim "+set tabstop=4" ...

Your comment has nothing to do with the article.. or even keeping things simple.

I think it's actually a point against lining up variable assignations like that more than a point for spaces (I prefer spaces over tabs btw).

> The game was a commercial success for id Software; with more than 3.5 million copies of the game were sold.

Wrong/Cheated. It was such a success that they had to sell the company - they sold ID-Software...

Doom 3 - 2004

ZeniMax - 2009

It seemed to do well enough to slow the need to sale for five years or so.

Or maybe, just maybe, it was so successful of a company that another company bought it to share in the success.

They were building Rage at the time. I'm sure the budget for that game was like 5x that of D3. Shit runs late, cost blooms. Lots of 90's era twenty person shops had trouble dealing with increasing costs.

So, you are suggesting that id was sold to cover the costs of Rage?

Why are you referring to the process of selling the company as an opposite of financial success?

I can't say for Id Software, because I have no clue about their financials. But historically, people who run profitable companies do not want to sell them. They want to grow them so they can make even more money. These days startups which are "owned" by VC money, usually have to sell so the VCs can recover their investment.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact