Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

 
Advanced search

891561 Posts in 33550 Topics- by 24784 Members - Latest Member: 1980s

June 20, 2013, 12:37:57 AM
TIGSource ForumsDeveloperTechnical (Moderators: Glaiel-Gamer, ThemsAllTook)Proficiency in C++
Pages: 1 [2] 3 4 5
Print
Author Topic: Proficiency in C++  (Read 4220 times)
Klaim
Level 10
*****



View Profile WWW
« Reply #15 on: March 03, 2012, 06:50:23 AM »

In fact with the new standard, Microsoft pushing it in Visual Studio AND in Windows 8, a lot more of efforts going on in the C++ committee...

... also the fact that embedded hardware are becoming present everywhere and is far more economic when programmed with something that is cheap on memory & speed...

... I think you'll se more C++ in video gaming.



That said, video game developpement is far wider today and it means C++ isn't the only good choice for your specific game. It's good to be able to use it, as it often need a mindset a bit harder to get than other languages (functional languages taken appart) but it's better to know at least a bit about other language for non-system programming.

Also, anyone telling you a technology widely used will die is just victim of the hype curve. See: http://programmers.stackexchange.com/questions/87972/oop-technology-death

So, don't listen to them, just inform yourself about the initial goals, history and direction of your tools (languages are only tools) if you want to know if it's worth learning & using them in your very specific context.

Logged

http://www.klaimsden.net | Game : NetRush | Digital Story-Telling Technologies : Art Of Sequence
paste
Level 6
*


BARF!

HeyIAintEddie
View Profile WWW
« Reply #16 on: March 03, 2012, 12:05:15 PM »

Thanks to everyone who gave answers, very helpful!

Don't neglect learnning how to design programs in C++. I think in a senior position they would be more interested on how you design software. Of course this is not exclusive to C++, but even if you know all the features of C++ and can write complex algorithms, it won't help you in a game industry job where you need to write large software and work with a team of programmers.
For me being proficient in C++ is knowing how to write readable, maintainable and neatly designed software.
Even if they don't ask you about that, "sharing" your knowledge about software design would add you a lot of points. And it's something you should learn if you want to improve your coding SKILLZ.


Yeah, I've been writing programs in c++ lately just for the hell of it, trying to incorporate a new c++ topic whenever possible and appropriate.

I am decent with pointers and good with many programming concepts in general, but I still stumble with specific c++ syntax.  So I figure, like with natural languages, just using it everyday will help me become fluent.
Logged

Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW Email
« Reply #17 on: March 03, 2012, 12:42:40 PM »

Like others have said, "proficiency" depends very much on the job you're interviewing for and the person doing the interviewing.  Proficiency will mean something totally different in an embedded environment than in does in a super-computing environment.

In the C++ job I got (not video game related) I did well in the interview mostly because I'm a proud language lawyer, and so was the guy interviewing me.  I was able to answer most of his technical questions, which the other candidates certainly couldn't do.  When I learn a programming language, I really learn it, and I try to use as many features as I can in every program I write (I have this goal of using every language keyword in every program, I don't think I've ever actually met it).  Understanding a complete language (or as close as you can get) can go a long way in interviews.

In general terms, I would recommend the following:

Read as much Stroustrup as you can find

The man has written a lot, and it's almost all worth reading.  Everything in C++ has a good reason behind it, and he's explained almost everything at some point.  I would recommend picking up his book The C++ Programming Language, but with the recent finalization of C++2011 I would wait for a new edition that covers that.

C++ is a multi-paradigm language, learn them all

C++ really isn't about OOP anymore, and it's quite arguable that it never was in the first place.  Generic programming is the current focus of language, and it's also an excellent imperative language as well.  Not all problems fit the OOP mold, and there are too many programmers that only own the OOP hammer.

Learn C

C and C++ have diverged significantly since C and C++ were originally standardized.  Looking at how C has evolved and handled various issues will probably give a better understanding of how and why C++ approached the same issues.  Also, knowing how to write C style programs will allow you to use C++ as what Stroustrup calls "a better C" and this is valuable knowledge.  Sometimes the C style approach is simpler and faster.

Most importantly, keep programming

I program almost every day.  I've always had some kind of project going for at least the last ten years.  There is no substitute for experience.  I had to interview some candidates at my last job, and it's really easy to tell the difference between "programmers" and "people that know how to program."  Most jobs want "programmers," but some are fine with just "people that know" (these companies are best avoided, if you ask me).
Logged

Franchise - The restaurant wars begin!

What would John Carmack do?
paste
Level 6
*


BARF!

HeyIAintEddie
View Profile WWW
« Reply #18 on: March 03, 2012, 01:59:20 PM »

@Average Software: I've been reading that Stroustrup book on and off lately. What book would you recommend for C? I'm guessing Kernighan and Ritchie's? What do you mean by "a proud language lawyer"? Why aren't I asking you this stuff on IRC?


Logged

Will Vale
Level 4
****


will@secondintention.com
View Profile WWW Email
« Reply #19 on: March 08, 2012, 01:35:03 PM »

Learn C

Yes, yes, a thousand times yes. Preferably before learning C++ - C is much easier/smaller, and everything happens in the open where you can see it.

If you're a good C programmer then C++ provides an awesome box of tricks that you will want to use, but naturally have some suspicions/reservations about. That's healthy. Too many people learning C++ go straight into the OO "class Car is-a Vehicle" paradigm and get stuck there. They also tend to accept or not even realise the costs of various language features.

Will
Logged
Klaim
Level 10
*****



View Profile WWW
« Reply #20 on: March 08, 2012, 02:29:16 PM »

Learn C

Yes, yes, a thousand times yes. Preferably before learning C++ - C is much easier/smaller, and everything happens in the open where you can see it.

If you're a good C programmer then C++ provides an awesome box of tricks that you will want to use, but naturally have some suspicions/reservations about. That's healthy.

I do not agree at all. Learning C will give the false impression of mastering the basics of C++ with additional tricks, that is totally false. Modern C++ isn't C, they are different languages that HAVE TO be learnt separately (and with distance) to benefit from both. C++ is NOT a stack of tricks over C, it's a different language that you write totally differently.

Quote
Too many people learning C++ go straight into the OO "class Car is-a Vehicle" paradigm and get stuck there. They also tend to accept or not even realise the costs of various language features.

That I agree with. This is not related to learning or not C. C++ provide several idioms, one being object orientation and as any language with object orientation, it is easily abused. The problem here is more a teaching/learning problem. Those developers you describe don't understand that a simple functions is a better abstraction for a big part of their code, instead of objects. But C have nothing to do with this.


C is good to know (assembly too - but I don't know much) but it HAVE to be taken as a DIFFERENT language.


Otherwise, you're the working on doom.

(pun intended)
Logged

http://www.klaimsden.net | Game : NetRush | Digital Story-Telling Technologies : Art Of Sequence
Will Vale
Level 4
****


will@secondintention.com
View Profile WWW Email
« Reply #21 on: March 08, 2012, 03:24:59 PM »

I think that's a reasonable response, but I'm not sure I agree. I guess my "box of tricks" comment made it sound like I don't think that C++ is different/difficult, and I was trivialising the step from one to the other. That wasn't intended, I agree that it's a big step, that's partly why C first is a good idea.

They share some hard parts, like pointer arithmetic, memory management, etc. which are easy to "see" in C, but can be obscured in C++ by language features.

Going back to your "grok list", I don't think that RAII, or smart pointers, or STL, or OO are required fundamental concepts for making effective use of C++. They're all concepts which are outside the core of the language and inside one or more use paradigms.

Maybe the point we're disagreeing on is "Modern C++" vs. just "C++"?

I strongly agree about the importance of C (and asm) in a C++ context - it helps to know what's happening on the levels below the one you work at. Not always, but when you need it you really need it.

Will

Logged
Klaim
Level 10
*****



View Profile WWW
« Reply #22 on: March 08, 2012, 04:06:16 PM »

I think that's a reasonable response, but I'm not sure I agree. I guess my "box of tricks" comment made it sound like I don't think that C++ is different/difficult, and I was trivialising the step from one to the other. That wasn't intended, I agree that it's a big step, that's partly why C first is a good idea.

Yes that was my impression, so you're making it a bit more clear here, thanks.

Quote
They share some hard parts, like pointer arithmetic, memory management, etc. which are easy to "see" in C, but can be obscured in C++ by language features.

Yes, that's the point of C++, not having to deal with all that until you have to, at almost no cost.
That's also, in a more general way, why we use abstractions. That is, tools that help use hide details when they are noise when we're thinking a solution to a problem.
Most C++ code don't need to go to the pointer arithmetic for example, but it's good to know if you need it, in SOME part of C++ code, of SOME projects.

Also that depends on which feature you use, but the C++ guiding principle is that you don't pay for what you don't use. That means that if you try to implement an equivalent object-oriented architecture to solve a problem in C and C++, the C++ one will be less or as much expensive (on memory and speed) than C.

So, it's only useful abstractions to use when it helps solving your problems. (often only experience and a lot of literature on the project allow one to understand which abstractions are more suited for which kind of problem).

Quote
Going back to your "grok list", I don't think that RAII, or smart pointers, or STL, or OO are required fundamental concepts for making effective use of C++. They're all concepts which are outside the core of the language and inside one or more use paradigms.

What?

No, they are all precisely why C++ is not C.

Read this: http://programmers.stackexchange.com/questions/16390/what-are-the-fundamental-differences-between-c-and-c

By "use paradigms" you mean "idioms" right?

C++ idioms are not C idioms. When you use C++, you should dive entirely into the RAII idiom because it's the only way to get safe-efficient-clear-simple-correct code in C++. RAII "is" C++. The others are basic tools of the language (SL/STL) or very useful abstractions (OOP, templates) that need to be understood to use C++ fluently (as initially asked).

They are not "outside of the core of the language" at all, they make the language.
However they are outside of C language yes, because you wouldn't use most of those in C anyway as they are just not possible to implement. RAII is impossible to implement in C. STL is impossible without templates that are impossible to implement in C (macro are not templates at all). Object orientation, in the presence RAII, is impossible to implement in C (C way of doing OOP is fine and good, but it is nor safe nor easily correct and debuggable, while RAII imply that it is). Smart pointers are just impossible to implement without RAII then impossible to implement in C.

Smart pointers are the reason why you can write C++ code for years without never having any memory leak. (don't abuse them though) They don't replace you thinking how to manage your memory, they force you to know object's lifetime rules, with very very simple words (shared, unique, weak).

That said, I think it's really hard to understand all that without experimenting modern C++, instead of the old C++ that is often used in old C++ shops like most game development companies. So I understand if what I'm saying seems alien or wrong to any C++ user not used to idiomatic C++.

Maybe think it like this, if you know python: designing your code in Python like in C is not Pythonic (this is the name given to Python idiomatic code). In the same way, designing C++ code like in C is not idiomatic, therefore, it goes against the intended use of the language. It's a bit like when you have to fight your tool/engine to get a specific feature done. Maybe it's because it's not meant to be used this way.


Quote
Maybe the point we're disagreeing on is "Modern C++" vs. just "C++"?

What is commonly called "modern C++" is simply "standard ISO C++ with a correct implementation, using C++-specific idioms".

So, C++ is modern C++, but we have to make a distinction with "C with classes" that is the old way to work with C++ when it was badly implemented by compilers. It have been less than 10 years that we have more standard-compliant compilers.

Since we have them, we can code C++ code that looks like java/c# code but is predictable on the performance side and is more generic than in those languages. Mostly because of templates.

Since we have C++11 (last revision), we can write C++ code that looks more like Python code.

By the way, did you know that the last Stroustrup book, targetted at total beginners in programming, use C++ but don't introduce pointers until something like after 500pages? (it have 1400 pages I think). The book isn't specifically about C++, but it uses only this language. Before this point in the book, you build a calculator and start using GUI.

Quote
I strongly agree about the importance of C (and asm) in a C++ context - it helps to know what's happening on the levels below the one you work at. Not always, but when you need it you really need it.


The problem is more to understand when it is necessary to know/use. I almost never use my C knowledge these days, but I still work on high performance C++.

« Last Edit: March 08, 2012, 04:12:45 PM by Klaim » Logged

http://www.klaimsden.net | Game : NetRush | Digital Story-Telling Technologies : Art Of Sequence
Will Vale
Level 4
****


will@secondintention.com
View Profile WWW Email
« Reply #23 on: March 08, 2012, 07:52:21 PM »

I don't think I have time to write a similarly in-depth response, sorry. I think we'll have to agree to disagree Smiley

I will say that IMHO RAII isn't a "native" part of C++, it's a way of working with the language, using a native feature (constructors and destructors) to accomplish something useful (freeing resources). If it was native, you wouldn't need to write wrappers or use libraries to get the desired behaviour.

The other features we've contested are even less native, they're entirely provided by external libraries Smiley I guess it's a semantic thing about where the dividing line is between internal features and external libraries, even if they're provided with the compiler toolset. I know that if I'm writing in C and want e.g. efficient file I/O for large files, streaming, unbuffered reads etc. I would forgo the stdio FILE* and go to the OS layer, so this isn't just an unwillingness to use the C++ std library.

That said, I think it's really hard to understand all that without experimenting modern C++, instead of the old C++ that is often used in old C++ shops like most game development companies. So I understand if what I'm saying seems alien or wrong to any C++ user not used to idiomatic C++.

This is a pretty common line about game development studios, it makes me sad because it assumes so much. Games have difficult problems to solve and using a language in "the intended way", whatever that is, may not be the right way to solve them.

Christer Ericson has some thoughts on this which I'd generally agree with, but it boils down to "If you want to ship complex high performance games on console systems, you need to pick and choose your language features carefully and be very aware of what they cost."

This is cost in compile time, complexity, transparency, as well as runtime performance and code size. These costs are important and features are never "almost free" - either they have no cost, or they have a cost of which you must be aware. If you're writing a smaller game, maybe you'll never worry about them on PC. If you port it to a 'phone or an embedded platform, maybe you'll need to worry about them then. In my day job I worry about them a lot.


Anyway, sorry paste for the thread hijack - there's been some good advice plus you can see the different opinions on the subject - there isn't a right answer, although I think Average Software probably said it best

My take is that most game companies will value pragmatic language proficiency derived from game development experience (either in a job, or on your own) over theoretical language proficiency acquired through formal learning. Courses are good and all, but the making and shipping games (indie or not) with your language is what teaches you the hard lessons. It also gives you something you can show off in interviews or as job application material.

Best of luck,

Will
Logged
BlueSweatshirt
Level 10
*****


the void


View Profile WWW
« Reply #24 on: March 08, 2012, 08:14:16 PM »

Is it bad that in 5 years I have never used smart pointers?(or ever even learned about them)
Logged

Paul Eres
Level 10
*****


Also known as RinkuHero.

RinkuHero
View Profile WWW Email
« Reply #25 on: March 08, 2012, 08:14:41 PM »


i only mind the word when it's said by someone who never read stranger in a strange land
Logged

ham and brie
Level 2
**



View Profile Email
« Reply #26 on: March 09, 2012, 01:37:24 AM »

I will say that IMHO RAII isn't a "native" part of C++, it's a way of working with the language, using a native feature (constructors and destructors) to accomplish something useful (freeing resources). If it was native, you wouldn't need to write wrappers or use libraries to get the desired behaviour.

This "native" distinction you're drawing seems pointless. If you're not using RAII you're either not making effective use of C++ or hopefully you're doing something more advanced and risky having chosen not to use it.

Is it bad that in 5 years I have never used smart pointers?(or ever even learned about them)

It's not good if the reason you're not using them is that you've never learned about them.
Logged
Klaim
Level 10
*****



View Profile WWW
« Reply #27 on: March 09, 2012, 02:08:14 AM »

I don't think I have time to write a similarly in-depth response, sorry. I think we'll have to agree to disagree Smiley

Looks like it. Smiley
However, I need to point some things.


Quote
I will say that IMHO RAII isn't a "native" part of C++, it's a way of working with the language, using a native feature (constructors and destructors) to accomplish something useful (freeing resources). If it was native, you wouldn't need to write wrappers or use libraries to get the desired behaviour.

I didn't say it is "native", it's an idiom (resulting from the presence of destructors, yes) and it's what makes the difference between C++ (and ADA?) and almost any other language. If you experience and deeply understand it, then you'll be able to write modern C++.

I don't understand what you mean by "write wrappers to use libraries to get the desired behaviour"? What is the relation with RAII?

Quote
The other features we've contested are even less native, they're entirely provided by external libraries Smiley

?

In my list, only boost are "external libraries" (the standard library isn't external, it's part of the language specification Wink - ok it's still a library, I agree ).
Smart pointer, is an concept resulting from the RAII idiom. The SL provide some but you can write some too if you want, I did some simple ones few months ago.
Template is language feature, OO support is language feature, etc.

Quote
I guess it's a semantic thing about where the dividing line is between internal features and external libraries, even if they're provided with the compiler toolset. I know that if I'm writing in C and want e.g. efficient file I/O for large files, streaming, unbuffered reads etc. I would forgo the stdio FILE* and go to the OS layer, so this isn't just an unwillingness to use the C++ std library.


I think we don't talk about the same thing here.

Quote
This is a pretty common line about game development studios, it makes me sad because it assumes so much. Games have difficult problems to solve and using a language in "the intended way", whatever that is, may not be the right way to solve them.

This is... I can't find the right word so I'll say "misleading". Games are really complex problems fit together, right, so why make things harder by not using useful abstractions so simple separate each problem and still make the compiler and runtime extract as much juice it can from the hardware? That's the original need C++ is intended to fill. It provides lot of different abstractions because there is a lot of way to represent micro or macro solutions.

As I said, it's more about knowing your tool, it's strengths and weaknesses, than a language problem (today). In our case C++ weaknesses are compilation time, no build system specification, no ABI, not enough good education about it (even today). Strenghs are (very-)high and (very-)low abstractions, allow to combine totally different paradigms (as needed for totally different categories of problems), same or more efficient exploitation of the hardware (assuming the algorithms are efficient too).

So, if you know most of C++ abstractions (ok there are a lot, so it's time consuming), you might solve some problems in a simpler and yet more efficient way than before, and even write it faster than without knowing them.

To me, not taking time to know those tools is like paying a lot of dept to get things quicker. I understand that it's more a short-term strategy than a long term one, so it's fine in a pragmatic way.


Quote
Christer Ericson has some thoughts on this which I'd generally agree with, but it boils down to "If you want to ship complex high performance games on console systems, you need to pick and choose your language features carefully and be very aware of what they cost."

I agree too, but it have nothing to do with C++ specific features: if you know those features, their cost and advantages, you can use them exactly when they are useful, not in other cases. C++ have a lot of features so it's often said in those shops that you HAVE TO restrict to some, even if others might solve your specific problem at hands.

It's an educational/knowledge/communication problem.

Quote

This is cost in compile time, complexity, transparency, as well as runtime performance and code size. These costs are important and features are never "almost free" - either they have no cost, or they have a cost of which you must be aware. If you're writing a smaller game, maybe you'll never worry about them on PC. If you port it to a 'phone or an embedded platform, maybe you'll need to worry about them then. In my day job I worry about them a lot.

Yes you have to take account of all this, it's the same if you have to consider using other languages.

So, as C++ have tons of abstractions that helps with widely different contexts, and half those features weren't reliable like 10 years ago (when tools weren't even close to the standard), C++ game shops just rely on what they learnt was easy to understand quickly and easy to predict at the time.
Most just don't have the time to learn what is the current state of C++ and why they should care, so it's totally understandable that they still rely on old C++ context to decide what to use or not.

4-5 years ago I worked on 4 shipped in the shops Nintendo DS games. I used STL (because we began with no code at all...), template, object orientation, and other maybe obscure features but only where it was very useful to use. Measurements revealed that all the code I worked on was lean on memory and very fast. The main reason is only knowledge of my tools, because other less experienced developers did use most of the same features but didn't always get efficient code. One guy over-used templates to the point his bugs took weeks to fix. One intern abused from object orientation to the point it produced very very slow code. Both were easy to fix if you rewrote them with experience and knowledge of what to use when.

So again, it's an knowledge/educational problem (it's in fact one of the thing that the C++ commitee worry the most about). It depends a lot on your developer's C++ knowledge and experience, and as we already tackle really complexe problems without even considering the language, I assume it's... logical (but not "good") that most (old) C++ shops still have to just use the basics. Even if they only would benefit from learning what is relyable now.

I agree it's better to have a team working without worrying about those features. Yet it's a potential loss of productivity too. Anyway, it's more a company dev-team thing than something that can be really discussed outside of specific contexts.
I wouldn't impose meta programming knowledge on my coworkers if they think it's too hard to understand (I think it can too easily be, even if it's helpful in some contexts).


Quote
My take is that most game companies will value pragmatic language proficiency derived from game development experience (either in a job, or on your own) over theoretical language proficiency acquired through formal learning. Courses are good and all, but the making and shipping games (indie or not) with your language is what teaches you the hard lessons. It also gives you something you can show off in interviews or as job application material.

Well I'm not sure what I cited are "over theoritical language proefficiency acquired through formal learning", first because I've used them all in real game (and not game) code with high efficiency and second because I know that C++ features only get into the language if they are proven to be pragmatically useful. I've also found that the only way to write quickly effcicient enough code in C++ is to know and be experienced with what I cited. (like in game jams and with less prototype-kind of game dev.)
Also, I never had any course of C++ (I'm self-made) and only relied on a hard mix of knowledge (books) and practice (tons of projects). I got C++ jobs only because I showed some modern C++ code and had some old demo.


All that said, I din't ship a complete commercial indie game alone myself yet so, let me prove my points in a hopefully short future, will you?  Gentleman

Maybe then what I'm saying could have more sense to some.
I just wish I could work all day on those games  Tired



Best of luck to you too.


ham and brie : ++, exactly

Paul Eres: the book have been in my amazon list for some years, but I read a lot about about the 'grok' word before starting using it. Actually, I think it's the first time I did. I was originally intending to use it to name a gameplay feature.

Jakman4242 : it always depends on the context. However, if you wish to continue to use C++, you should constantly try to learn more about it and about other languages to get perspective.
Logged

http://www.klaimsden.net | Game : NetRush | Digital Story-Telling Technologies : Art Of Sequence
peous
Level 2
**


Indie opportunist


View Profile Email
« Reply #28 on: March 09, 2012, 02:19:36 AM »

I don't want to answer to philosophical thoughts about C++ and OOP, just about my experience in writing C++ code for games. In my opinion,

- Use references instead of pointers when you can, prevents a lot of null pointers bugs/ or unnecessary checks
- RAII is a good thing, specially with threading issues, but not used much in other areas
- RTTI and exceptions are mostly not used in C++ games
- stl may be used or not, but it's always good to know it but about collections, the more important is being aware of what is the difference (from a memory point of view) between a list and a vector, a map, a freelist, a lock-free queue... knowing when it reallocs, knowing the speed difference of finding in a map or in a vector... Many prorammers use one container or the other randomly, when performances could suffer so much !

I would say some good experience could also be (not formely part of C++)

- Some good 3d math/classes design
- Memory debugging : This is more related to C if you want, but at the end of every game, you always have some memory corruption problem, or memory allocation/leaks (PS3 does not allow any leak for example)
Logged

Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW Email
« Reply #29 on: March 09, 2012, 06:01:08 AM »

Smart pointers are the reason why you can write C++ code for years without never having any memory leak. (don't abuse them though) They don't replace you thinking how to manage your memory, they force you to know object's lifetime rules, with very very simple words (shared, unique, weak).

This I actually disagree with quite strongly.  I write a lot of C++ and Ada code, and I very rarely touch smart pointers for memory management because I very rarely use dynamic memory allocation.  I can do this because I've embraced value semantics.

C++ and Ada are built entirely around value semantics, and too many people only know how to program with reference semantics.  My C++ and Ada types have proper copy constructors/assignment operators whenever possible, and have copying explicitly disabled when not possible.  In the nearly 50000 lines of Ada that make up my current game, I have only 3 or 4 places that need dynamic memory, and a couple of those are actually working around compiler bugs.  This is slightly easier in Ada since it supports value polymorphism and polymorphic copying (allowing heterogeneous containers) but is not unheard of in C++.  In a C++ job I had I wrote a major new module for our program, probably close to 5000 lines of C++, without a single use of the word new.

To me, smart pointers are too often a bandage on a much larger problem, the overuse of dynamic memory.  I think this problem is mostly caused by people trained in languages like Java who think that you have to use new on everything and never really learn the C++ way.  This is why I get nervous around anyone preaching smart pointers.  They have their place, certainly, but in truly well written code they shouldn't even be necessary.  The best way to not leak memory is to not allocate it in the first place.
Logged

Franchise - The restaurant wars begin!

What would John Carmack do?
Pages: 1 [2] 3 4 5
Print
Jump to:  

Theme orange-lt created by panic