www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Writing game engine in C++, considering switching to D

reply "Will Cassella" <wcassella gmail.com> writes:
Hi,

I have been working on a neat little game engine in C++ for the 
past year or so, and while C++ has served me well in the past, 
there are some points where its just awful to write. While I 
certainly can't call myself a master of C++, there's very little 
about the language that I am not familiar with, and I'd like to 
try something new.

Since I am writing this engine just for fun and experience and 
C++ game engines have been done to death, a D game engine would 
make for an interesting project as well as providing great 
experience with system/application oriented programming.

One of the main differences it seems between D and C++ is that 
the D compiler actually tries to be your friend by avoiding all 
the header/preprocessor/forward-declaration madness. I actually 
don't mind the syntax of C++ for the most part, but there are 
some cases where it just wants to make you tear your eyes out so 
you don't have to look at it anymore (ie, the '.template 
MemberName<T>()' syntax for calling dependant member functions on 
templated variables. I understand why its necessary, but its 
still ugly as hell. I also think that forward-declarations are 
hideous devil-spawn and have no reason to exist in 2015).

I like that D has a garbage collector, because while I intend to 
utilize RAII heavily in lower-level portions of code, having a 
native garbage collector to handle higher-level aspects (ie 
gameplay) would be extremely helpful.

That's not to say I don't have concerns about switching to D, and 
so I'm outlining them below:

Pros:
- Prettier code (this is actually a very big plus for me, I'm 
almost OCD about the cleanliness of my code)
- Modules: Less frustration with the compiler, faster compile 
times
- Larger standard library. I hate it when C++ people complain 
about "non-utility" features for the standard library. You don't 

it.
- Garbage collection. Garbage collection allows you to focus on 
algorithms, not management, so I don't understand why some people 
are so vehemntly opposed to it.

Cons (I'm not very experienced with D so these may be inaccurate):
- Not as easy to get up and running (I haven't gotten DMD to work 
with VisualD yet, even though they both appear to be set up 
correctly. There may be an easy fix, but it doesn't exactly 
inspire confidence). PHP may be an awful language, but you can't 
deny that its incredibly easy to get up and running on a web 
server - and there's a lot of appeal to that.
- DLLs. C++ DLLs/SOs are pretty simple for the most part, and 
don't require your code to really know that it's being referenced 
through a DLL. I really don't want to have to write dllmain and 
.def files for my DLLs.
- Portability (?) While I'm not currently targeting more exotic 
platforms like PS4 or XBone or Android or the iPhone or even 
asm.js, I would like to keep those options open. I don't know how 
portable D is towards more gated platforms like those, so if 
anyone can clarify on this I'd appreciate it.
- Library support. This may become a non-issue, as Ds support of 
C libraries seems pretty solid, and it sounds like further 
support for C++ is coming.

Anyway, if anyone here can give me advice on whether I should 
transition or not, I'd appreciate it.

Thanks!
Feb 18 2015
next sibling parent reply ketmar <ketmar ketmar.no-ip.org> writes:
On Wed, 18 Feb 2015 20:29:33 +0000, Will Cassella wrote:

 Anyway, if anyone here can give me advice on whether I should transition
 or not, I'd appreciate it.
do you really expecting the answer "no, stay with C++" in newsgroup that=20 is dedicated to D language? ;-) as for some of your answer... using DMD from command line is dead easy=20 both on GNU/Linux and on windows. you may miss visual studio integration=20 and debugging, though. me not. ;-) GNU/Linux (and FreeBSD) .so support seems to work good, we can even use=20 libphobos as shared library. it's still not possible to use libphobos as=20 separate DLL on windows, AFAIK. yet you can write self-contained DLLs;=20 alas, they will not share GC (so you can't transfer dynamically allocated=20 heap object from one DLL to another). GDC compiler is able to produce ARM code (and maybe LDC too, i don't=20 know), and i don't know about druntime porting status. yet there is some=20 work done, and i believe that we will have more of that. i don't think=20 that DMD will support ARMs in nearest future, as it requires completely=20 new codegen for that. so if you aiming at portability, you'd better test=20 your code with LDC/GDC (which usually one version behind the current DMD). as for the answer... writing such thing in D will be fun. and many things=20 may change in the future (full support for windows DLLs, better ARM/ android support, ownership and better controlled memory management,=20 etc.). i think that D is at least worth trying. you can always fallback=20 to "better C++" mode and write the missing parts yourself (and this will=20 be fun too).=
Feb 18 2015
next sibling parent reply Iain Buclaw via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 18 February 2015 at 20:48, ketmar via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 GDC compiler is able to produce ARM code (and maybe LDC too, i don't
 know),
GDC and LDC are able to produce any code. It's the runtime that may just need extra porting love. :) Iain.
Feb 18 2015
parent ketmar <ketmar ketmar.no-ip.org> writes:
On Wed, 18 Feb 2015 21:24:42 +0000, Iain Buclaw via Digitalmars-d wrote:

 On 18 February 2015 at 20:48, ketmar via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 GDC compiler is able to produce ARM code (and maybe LDC too, i don't
 know),
=20 GDC and LDC are able to produce any code. It's the runtime that may just need extra porting love. :)
ARM is at least tested... well, for some extent. ;-)=
Feb 18 2015
prev sibling parent "Casper =?UTF-8?B?RsOmcmdlbWFuZCI=?= <shorttail hotmail.com> writes:
On Wednesday, 18 February 2015 at 20:48:07 UTC, ketmar wrote:
 as for some of your answer... using DMD from command line is 
 dead easy
 both on GNU/Linux and on windows. you may miss visual studio 
 integration
 and debugging, though.
Actually, you can have both. Apparently the Windows installer for DMD installs VisualD and during a segfault in a raytracer, I noticed it asked me if I wanted to debug. I had no idea what it would do, and I was rather annoyed when Visual Studio started up, but it pointed me to the line that failed. And I was just using command line dmd... I was very impressed. ~.~
Feb 18 2015
prev sibling parent reply "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Wednesday, 18 February 2015 at 20:29:34 UTC, Will Cassella 
wrote:
 Hi,

 I have been working on a neat little game engine in C++ for the 
 past year or so, and while C++ has served me well in the past, 
 there are some points where its just awful to write.
Maybe you should consider creating D-bindings for your C++ engine and write a small game for it in D before you start porting?
 Anyway, if anyone here can give me advice on whether I should 
 transition or not, I'd appreciate it.
If your goal is to have fun I suggest you write something in D rather than port existing code. Otherwise you most likely will end up with "why is this hard in D" rather than "this is much more fun in D".
Feb 18 2015
parent reply "Will Cassella" <wcassella gmail.com> writes:
Thanks for the replies, everyone!

I think I'll try my hand at writing bindings for my existing game 
engine, as Grøstad suggested - that way I can gradually 
transition the codebase to D if I like what I see.
Feb 18 2015
next sibling parent Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 19 February 2015 at 12:08, Will Cassella via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 Thanks for the replies, everyone!

 I think I'll try my hand at writing bindings for my existing game engine, as
 Grøstad suggested - that way I can gradually transition the codebase to D if
 I like what I see.
I've used D alongside C++ code in games for a few years, professionally, and in my own toy projects, including on the console platforms you expressed a concern for. You might want to take a look at my engine + bindings: https://github.com/TurkeyMan/fuji/tree/master/dist/include/d2/fuji You can do some cool stuff in D that is impossible in C++. vertex.d for instance demonstrates some interesting opportunities to make the bindings far nicer in D, even though it's just a front-end for a C++ engine.
Feb 18 2015
prev sibling parent reply "francesco.cattoglio" <francesco.cattoglio gmail.com> writes:
On Thursday, 19 February 2015 at 02:08:39 UTC, Will Cassella 
wrote:
 Thanks for the replies, everyone!

 I think I'll try my hand at writing bindings for my existing 
 game engine, as Grøstad suggested - that way I can gradually 
 transition the codebase to D if I like what I see.
My 2 cents would be: start with a toy project that stresses a bit resource management (the toy project might as well be the rendering part of your existing engine). The only part of D I really don't like is non-deterministic resource destruction, because it can be really painful when it comes to stuff like OpenGL resources (e.g: if the GC calls any OpenGL function, you get a "nice" crash since OpenGL is not multithread-aware by default). IMO the first thing you should do, is trying to see if you are able to manage all your critical resources (including OpenGL objects) by using D structs coupled with Unique! and RefCounted! templates you can find in std.typecons module. I highly suggest you to do that, because that is the worst hurdle I had to face during any kind of D + OpenGL development. If you understand how to get stuff done right, you are set, and the rest of the work will be painless and fun.
Feb 20 2015
parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Friday, 20 February 2015 at 09:57:48 UTC, francesco.cattoglio 
wrote:
 (e.g: if the GC calls any OpenGL function, you get a "nice" 
 crash since OpenGL is not multithread-aware by default).
Really? I don't see this in my projects. The GC stops the world, so there shouldn't be any races.
Feb 20 2015
parent reply "ponce" <contact gam3esfrommars.fr> writes:
On Friday, 20 February 2015 at 13:04:51 UTC, John Colvin wrote:
 On Friday, 20 February 2015 at 09:57:48 UTC, 
 francesco.cattoglio wrote:
 (e.g: if the GC calls any OpenGL function, you get a "nice" 
 crash since OpenGL is not multithread-aware by default).
Really? I don't see this in my projects. The GC stops the world, so there shouldn't be any races.
Not a race. An OpenGL contect can only active in one thread at once. If the GC calls a destructor from a thread which doesn't have that context active, it will probably crash.
Feb 20 2015
next sibling parent "francesco.cattoglio" <francesco.cattoglio gmail.com> writes:
On Friday, 20 February 2015 at 13:44:04 UTC, ponce wrote:
 On Friday, 20 February 2015 at 13:04:51 UTC, John Colvin wrote:
 On Friday, 20 February 2015 at 09:57:48 UTC, 
 francesco.cattoglio wrote:
 (e.g: if the GC calls any OpenGL function, you get a "nice" 
 crash since OpenGL is not multithread-aware by default).
Really? I don't see this in my projects. The GC stops the world, so there shouldn't be any races.
Not a race. An OpenGL contect can only active in one thread at once. If the GC calls a destructor from a thread which doesn't have that context active, it will probably crash.
Exactly. Unless you do some special work yourself, you can't call OpenGL function from a different thread. It's not a real D problem, in fact, D is probably doing the right thing when it comes to Thread Local Storage and such. It is more of an OpenGL limitation. This is also the reason I can't wait to see OpenGL Next, since there were also promises of "far better multithread support".
Feb 20 2015
prev sibling parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Friday, 20 February 2015 at 13:44:04 UTC, ponce wrote:
 On Friday, 20 February 2015 at 13:04:51 UTC, John Colvin wrote:
 On Friday, 20 February 2015 at 09:57:48 UTC, 
 francesco.cattoglio wrote:
 (e.g: if the GC calls any OpenGL function, you get a "nice" 
 crash since OpenGL is not multithread-aware by default).
Really? I don't see this in my projects. The GC stops the world, so there shouldn't be any races.
Not a race. An OpenGL contect can only active in one thread at once. If the GC calls a destructor from a thread which doesn't have that context active, it will probably crash.
Hmm, yeah you're right. That would explain some of my weirder crashes! However, if you make the context current in the GC thread that's cleaning up, then you should be fine. There's nothing wrong with having the same context current in multiple threads as long as you don't access it concurrently.
Feb 20 2015
parent reply "ponce" <contact gam3sfrommars.fr> writes:
On Friday, 20 February 2015 at 15:26:02 UTC, John Colvin wrote:
 However, if you make the context current in the GC thread 
 that's cleaning up, then you should be fine. There's nothing 
 wrong with having the same context current in multiple threads 
 as long as you don't access it concurrently.
I'm sorry but there is two problems with your solution: - first an OpenGL context cannot be bound to more than one thread simultaneously https://msdn.microsoft.com/en-us/library/windows/desktop/dd374387%28v=vs.85%29.aspx "A rendering context can be current to only one thread at a time." Looks odd since compute APIs do not have this limitation. - At the point where destructors are called by the GC, all other threads have been resumed. http://dlang.org/garbage.html So concurrent OpenGL calls may happen for the same context which is forbidden. Really such ressources should not be freed by the GC, and I with it would not call destructors at all.
Feb 20 2015
next sibling parent "ponce" <contact gam3sfrommars.fr> writes:
On Friday, 20 February 2015 at 17:49:22 UTC, ponce wrote:
 Really such ressources should not be freed by the GC, and I 
 with it would not call destructors at all.
s/with/wish
Feb 20 2015
prev sibling next sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
On Fri, 20 Feb 2015 17:49:21 +0000, ponce wrote:

 On Friday, 20 February 2015 at 15:26:02 UTC, John Colvin wrote:
 However, if you make the context current in the GC thread that's
 cleaning up, then you should be fine. There's nothing wrong with having
 the same context current in multiple threads as long as you don't
 access it concurrently.
=20 I'm sorry but there is two problems with your solution: =20 - first an OpenGL context cannot be bound to more than one thread simultaneously =20 https://msdn.microsoft.com/en-us/library/windows/desktop/dd374387%
28v=3Dvs.85%29.aspx
 "A rendering context can be current to only one thread at a time."
=20
 Looks odd since compute APIs do not have this limitation.
=20
 - At the point where destructors are called by the GC, all other threads
 have been resumed. http://dlang.org/garbage.html So concurrent OpenGL
 calls may happen for the same context which is forbidden.
=20
=20
 Really such ressources should not be freed by the GC, and I with it
 would not call destructors at all.
the funny thing is that destructor can be called while another thread is=20 *inside* OpenGL call. is starts to be funniest with each post.=
Feb 20 2015
prev sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Friday, 20 February 2015 at 17:49:22 UTC, ponce wrote:
 On Friday, 20 February 2015 at 15:26:02 UTC, John Colvin wrote:
 However, if you make the context current in the GC thread 
 that's cleaning up, then you should be fine. There's nothing 
 wrong with having the same context current in multiple threads 
 as long as you don't access it concurrently.
I'm sorry but there is two problems with your solution: - first an OpenGL context cannot be bound to more than one thread simultaneously https://msdn.microsoft.com/en-us/library/windows/desktop/dd374387%28v=vs.85%29.aspx "A rendering context can be current to only one thread at a time." Looks odd since compute APIs do not have this limitation.
The OS X documentation makes it seem possible: https://developer.apple.com/library/mac/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_threading/opengl_threading.html
 - At the point where destructors are called by the GC, all 
 other threads have been resumed. http://dlang.org/garbage.html
 So concurrent OpenGL calls may happen for the same context 
 which is forbidden.


 Really such ressources should not be freed by the GC, and I 
 with it would not call destructors at all.
Ah, yes, you're right.
Feb 21 2015