What's the inner design [pattern] of Irrlicht?

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
Xeverous
Posts: 11
Joined: Tue Jan 24, 2017 7:25 pm

What's the inner design [pattern] of Irrlicht?

Post by Xeverous »

When I have started reading code from examples, I was a bit scared that Irrlicht is old and unmaintained.
I was mostly scared by all methods that return pointers and lack of references in the first glance.
I'm more used to modern C++ (11 or 14 standard) where things like

Code: Select all

Object* obj;
int arr[10];
are replaced by

Code: Select all

std::unique_ptr<Object> obj;
std::array<int, 10> arr;
.

I don't mind old-like features of Irrlicht much (speaking of irr::IReferenceCounted, "I-something" naming convention) because they can be
covered in templates / typedefs / functions so I don't have to manually use .grab() and functions like that.

What really bothers me, is that many Irrlicht classes (including core Irrlicht device) are abstract classes.
You can't have a local/static object of type irr::IrrlichtDevice, because at least 1 function is pure virtual.
You are supposed to get the pointer to IrrlichtDevice and call functions throught it.
What's the reason behind such design?
CuteAlien
Admin
Posts: 9633
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: What's the inner design [pattern] of Irrlicht?

Post by CuteAlien »

It's a pretty typical object oriented architecture. And yeah - it was written long before c++11 so that wasn't used (Irrlicht uses no STL at all). Which has the advantage that it's somewhat easier to create wrappers for other programming languages and also reduces depencies which makes distributing your applications a little easier.

One reason for abstract classes is a stronger separation of interface and implementation. Another is that many classes in Irrlicht use inheritance. For example there are many Irrlicht devices - for Linux, Windows, OSX, Framebuffer, SDL - but all are derived from the same IrrlichtDevice interface. So you can switch to another device (for example when you switch the OS) and your user code still looks exactly the same.

There's advantages and disadvantages to such an OO architecture. It's usually rather easy to understand and use. Also somewhat extentible (you can easy add own classes, while extending classes is a liitle harder as it can only be done by copying sources).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: What's the inner design [pattern] of Irrlicht?

Post by Cube_ »

in addition to CuteAlien's response - irrlicht doesn't use the STL because it didn't exist when the project was created [as mentioned], but even if it did it likely wouldn't because the quality of STL implementation is nowhere near consistent between compilers and even the 'good' implementations absolutely smash the cache, are needlessly complex, waste memory (and sometimes cpu), and generally make it really easy to fall into an antipattern (see: the reasons EASTL and STAPL were created. Worth noting is that irrlicht being OO introduces some of these caveats on its own, albeit to a significantly lesser extent).

Moreover while C++11 is almost old enough to be mature (and thus a candidate for a long term support library) this wasn't the case too long ago, anyone who cares about cross platform compatibility would likely still stay away since C++11 support isn't 100% implemented everywhere (g++ for example lacks quite a few features still and some features only partially work), this becomes an unscalable nightmare once you introduce C++14 or god forbid C++17 into the mix, if you only care about MSVC this is probably fine - microsoft tends to be pretty good at implementing at least rudimentary support early on, but if you want to support compilers like g++, mingw, clang or pretty much anything else, well here's a rule of thumb: is the feature older than ~7-8 years? Righto, then go right ahead. If it isn't then you actually have to do research and testing to figure out what is reasonably likely to be a good idea.

Well; that's my own general opinion on the topic - I speak for myself and myself alone, the irrlicht devs may have an entirely different opinion and may have used the STL if it were available when it was made, I'm just stating my reasoning for why I don't think it belongs in library code [when it comes to anything where you expect reasonably high performance]

now as for this:
What really bothers me, is that many Irrlicht classes (including core Irrlicht device) are abstract classes.
You can't have a local/static object of type irr::IrrlichtDevice, because at least 1 function is pure virtual.
You are supposed to get the pointer to IrrlichtDevice and call functions throught it.
What's the reason behind such design?
Because the alternative is to have IrrlichtDeviceLinuxOGL, IrrlichtDeviceWindowSOGL, IrrlichtDeviceOSXOGL, IrrlichtDeviceLinuxSDL, and so on and so forth; this is for obvious reasons not scaleable - if there was only one device type such as SDL/OpenGL then there would be no good reason for it but since there are so many device types it makes far more sense to have a derived abstract type (which adds a small amount of overhead but it's only in the order of a few cycles per call and since you usually only make a handful of device calls per frame... "this is not the bottleneck you are looking for"), this could technically also be done with some arcane abuse of templates but I wager the reasoning here is that it's much harder to maintain such code.
"this is not the bottleneck you are looking for"
CuteAlien
Admin
Posts: 9633
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: What's the inner design [pattern] of Irrlicht?

Post by CuteAlien »

STL did exist, it just had some troubles with some compilers so people avoided it a lot more back then (especially in the game industry). I wouldn't claim Irrlicht core classes to be better than STL really (which is why we consider switching). Less dependencies is probably the only real feature right now.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: What's the inner design [pattern] of Irrlicht?

Post by Cube_ »

CuteAlien wrote:STL did exist, it just had some troubles with some compilers so people avoided it a lot more back then (especially in the game industry). I wouldn't claim Irrlicht core classes to be better than STL really (which is why we consider switching). Less dependencies is probably the only real feature right now.
I know parts of the STL existed, but a lot of the C++11 and newer STL features didn't, and even today the STD implementation of STL is highly inconsistent at best and imo not brilliant, I'm not familiar enough with irrlicht's internal implementations of many of the similar features to directly comment on whether or not it's superior, what matters more is that it's consistent since it doesn't depend on compiler specific implementation details (EASTL is a brilliant candidate for the same purpose), moreover it's also not something that should be discussed here at any real length as that's thread hijacking, I mostly just went off on a tangent as to why I wager it wasn't originally chosen (and it seems I may have been correct in that assumption based on your response)

I don't necessarily condemn the STL, but I do condemn the implementation found under the STD namespace (but that's just my opinion)
"this is not the bottleneck you are looking for"
AReichl
Posts: 268
Joined: Wed Jul 13, 2011 2:34 pm

Re: What's the inner design [pattern] of Irrlicht?

Post by AReichl »

> thread hijacking
don't worry - this forum is very "focused" and most things are importand one way or another.

About gcc/mingw:
i always thought, gcc/mingw is ahead of MSVC when it comes to implementing standard features
( at least the "Support-Comparisons" say so ). Personally i work with a combination of gcc/mingw,
CodeBlocks and/or Eclipse-Cevelop, specially when learning new language features.
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: What's the inner design [pattern] of Irrlicht?

Post by Cube_ »

AReichl wrote:About gcc/mingw:
i always thought, gcc/mingw is ahead of MSVC when it comes to implementing standard features
( at least the "Support-Comparisons" say so ). Personally i work with a combination of gcc/mingw,
CodeBlocks and/or Eclipse-Cevelop, specially when learning new language features.
GCC is usually faster with getting an implementation, but it's almost never valid as far as the standard goes on the first go - MSVC is usually the first to comply with standards but this varies heavily on the specific feature, iirc GCC did lambdas correctly before MSVC for example.
Now vanilla G++ is usually fine, the mingw ports are however significantly less compatible, things that compile under native g++ magically fail under mingw (and mingw-TDM, and cygwin)

I personally work with GNU nano/clang usually, it has the best feature parity between platforms (and with the clang-llvm backend I can transpile to javascript which is nice)
"this is not the bottleneck you are looking for"
SLC
Posts: 21
Joined: Mon Jan 06, 2014 9:41 pm

Re: What's the inner design [pattern] of Irrlicht?

Post by SLC »

Cube_ wrote: ...MSVC is usually the first to comply with standards but this varies heavily on the specific feature, iirc GCC did lambdas correctly before MSVC for example.
...
I simply cannot agree to that. Let me see if I can have some examples. NOTE: The code is meant to demonstrate the feature not its usefulness as that depends on personal needs.

Extended constexpr:

Code: Select all

constexpr size_t dummy(const char * s) {
    size_t c = 0;
    while (*s) {
        ++s, ++c;
    }
    return c;
}
 
int main() {
  return dummy("some dummy text here");
}
GCC >=5.x? no problem - MSVC? most likely >=2017. Even regular constexpr was barely introduced in 2015.

Variable templates:

Code: Select all

template <typename T>
static constexpr T maxof = std::numeric_limits<T>::max();
 
int main() {
  return maxof<int>;
}
GCC >=5.x? no problem - MSVC? most likely >=2017

Generic lambdas:

Code: Select all

int main() {
  auto f = [](auto v) { return v * 2; };
  return f(-8.7) + f(17);
}
GCC >=4.9.x? no problem - MSVC? most likely >=2017

Inheriting constructors:

Code: Select all

struct A {
    explicit A(int x) {}
};
 
struct B: public A {
     using A::A;
};
 
int main() {
    B b(-9);
}
GCC >=4.9.x? no problem - MSVC? >=2015

User-defined literals:

Code: Select all

constexpr long double operator"" _deg ( long double deg ) {
    return deg*3.141592/180;
}
 
int main() {
  double x = 90.0_deg;
}
GCC >=4.9.x? no problem - MSVC? >=2015

Extended sizeof:

Code: Select all

struct S {
  int m;
};
 
int main() {
  return sizeof(S::m);
}
GCC >=4.9.x? no problem - MSVC? >=2015

noexcept
GCC >=4.9.x? no problem - MSVC? >=2015

Unrestricted unions
GCC >=4.9.x? no problem - MSVC? >=2015

And the list goes on...

So you cannot tell me that MSVC is the first to implement new c++ standards.
Cube_ wrote: ... GCC is usually faster with getting an implementation, but it's almost never valid as far as the standard goes on the first go ...
I cannot agree with that either. Maybe to Microsoft's standards. But not to the actual C++ standard. I can remember the times when I wrote C++ on MSVC and then tried to compile the code on other compilers. Boy oh boy, the things it allowed me to compile.

I still remember the time when I was using an std::string that came via a template parameter and MSVC was glad to do something like printf("%s", std::string("whatever")) (and worked btw). But when I switched to GCC, he was like "wtf you tryna do, fool?".

And there's a 50% chance that you'll find MSVC workarounds in C++11 projects/libraries and about 90% chance for C++14 projects/libraries. There's always a piece of code with a comment near it "Need to use this workaround because MSVC does or does not do a certain thing properly or at all.".

I'm not saying that one is better than the other. But claiming that MSVC is the first to adopt C++y features and that is more compliant to the standard, is plain bullshit. No offence, but you can't sell that cookie to me.

The story might be different in recent MSVC version. I certainly wouldn't know about it. I haven't used it in a long while. So you could be right after all. But only to a certain degree.
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: What's the inner design [pattern] of Irrlicht?

Post by Cube_ »

nice necrobump.

Also, more importantly you're missing the entire context and cherrypicking specific features - betcha if I did the same thing I can find features microsoft implemented first but that's beside the point, I more or less conceded that I don't give a poop in my final post if you actually parse the context and phrasing - it's irrelevant to me, when I build for *nix I use GCC and when I build for windows I use MSVC (clang for everything else) - this has less to do with feature support, I can refactor around that and use #ifdef's to encapsulate it.

No the point is primarily how well it integrates with the host environment, including how well the output binary behaves.
I still remember the time when I was using an std::string that came via a template parameter and MSVC was glad to do something like printf("%s", std::string("whatever")) (and worked btw). But when I switched to GCC, he was like "wtf you tryna do, fool?".
printf isn't typesafe, to throw std::string at it you must postfix it with .c_str(), MSVC has some microsoft extensions to make this optional (i.e the compiler inserts it or whatever) but it's not standard code, user error isn't an argument for or against a compiler. (fyi GCC also has a bunch of vendor extensions that break outside the environment, like the oh so useful #warning preprocessor directive)
And there's a 50% chance that you'll find MSVC workarounds in C++11 projects/libraries and about 90% chance for C++14 projects/libraries. There's always a piece of code with a comment near it "Need to use this workaround because MSVC does or does not do a certain thing properly or at all.".
Yeah but guess what, working around a quasi-broken feature is still better than nothing.

For example, move semantics and perfect forwarding - this depends on a few features like being able to get the rvalue references (you can hack around this but nonetheless, you can't do this properly in 4.7), GCC 4.7 branch doesn't support it (2012), MSVC 2010 supports this according to the MSDN. (2010) and this isn't even a fair comparison, we should compare to MSVC 2012 or MSVC 2013 ;)

Nonetheless, the point wasn't to bash any one compiler. The point was that I don't give one flying gently caress in reality, does it output acceptable machine code? If yes: well where's the problem then?
The story might be different in recent MSVC version. I certainly wouldn't know about it. I haven't used it in a long while. So you could be right after all. But only to a certain degree.
Depends on how recent we look at and what features we consider important, using rvalues is partially a cheap move on my end since microsoft are the ones who pushed for it to be part of the standard, but the point is more or less for both compilers you have to do a fair bit of hacking to get around vendor extensions, incomplete or incorrect implementations, missing implementations et cetera.

This is compounded when you use forks of compilers such as mingw which has its own set of supported features that differs from GCC's, especially problematic when it comes to missing C++11/14/17 features (C++11 is just now becoming mature enough to have a reliable implementation across the board, I'll still probably hold off for a couple of years to use more than a handful of features)

EDIT: oh yeah, here's one of the MSDN pages used: https://msdn.microsoft.com/en-us/library/hh567368.aspx

It has a pretty good overview of supported features.

As for GCC support:
https://gcc.gnu.org/gcc-4.5/cxx0x_status.html (in case you want to compare 2010 to 2010)
https://gcc.gnu.org/gcc-4.6/cxx0x_status.html (2012 or so, has reasonable C++11 support but is 2 years newer than the compared MSVC branch)

(GCC 4.8.1 has a 'feature complete' implementation but that's late 2013)


EDIT 2: I just found a citation for a thing I wanted to list, nullptr support - but I wasn't going to trust my memory on that one
http://stackoverflow.com/questions/2419 ... ted-in-gcc

MSVC 2010 supported nullptr, GCC at the time did not - this caused some amount of grief with having to either not use nullptr, not support non-ms platforms, or hack around the lacking support. Still probably have that hack in some old backup or test.
"this is not the bottleneck you are looking for"
SLC
Posts: 21
Joined: Mon Jan 06, 2014 9:41 pm

Re: What's the inner design [pattern] of Irrlicht?

Post by SLC »

Either way, MSVC fell way behind after GCC 4.9.x And while yes, most of it comes down to generated code. I was mostly bugged by the claim that MSVC is somehow the king of C++y features and standard loyalty when I knew from experience that's not the case.

And the other thing to note here is the frequency at which GCC versions are released compared to MSVC. GCC gets new versions every few months whereas MSVC gets a new version every few years. So if GCC is lacking a feature at the time MSVC releases a version. You have to understand that there's a chance you'll get that feature in the upcoming months. Whereas with MSVC, you're pretty much stuck with it for a while.
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: What's the inner design [pattern] of Irrlicht?

Post by Cube_ »

SLC wrote:... I was mostly bugged by the claim that MSVC is somehow the king of C++y features and standard loyalty when I knew from experience that's not the case.
Which is not what I said, but however you wish to interpret it is fine I guess.
SLC wrote:And the other thing to note here is the frequency at which GCC versions are released compared to MSVC. GCC gets new versions every few months whereas MSVC gets a new version every few years.
you know, ignoring service packs and feature packs and bugfixes, those obviously don't count. (ignoring those is more or less like saying GCC only releases major versions, ignoring that GCC 4 had 4.1, .2, .3, .4 .... .8; maybe even a .9 but iirc only went up to 4.8.6 before they went 5.0)

Also: 2008, 2010, 2012, 2013, 2015 (2016 possibly, I don't keep track) - that's almost exactly in line with GCC release schedule for releases (major.minor.patch) if we also consider that most of those have one or two service packs as well.
SLC wrote:So if GCC is lacking a feature at the time MSVC releases a version. You have to understand that there's a chance you'll get that feature in the upcoming months. Whereas with MSVC, you're pretty much stuck with it for a while.
Again, if we ignore service packs ;)

I'm not a huge fan of MSVC, indeed if I could have it my way I'd use CLANG for everything. But it's a tool like any other and I have no interest in glorifying or slandering it out of some sort of bias, both MSVC and GCC get feature updates relatively regularly *assuming you actually install them*, which one I use depends entirely on how well it integrates with the platform I release on and frankly microsoft has made it a pita to release on windows using a non-microsoft compiler.
"this is not the bottleneck you are looking for"
SLC
Posts: 21
Joined: Mon Jan 06, 2014 9:41 pm

Re: What's the inner design [pattern] of Irrlicht?

Post by SLC »

Cube_ wrote:... I'd use CLANG for everything...
Indeed, having that work on all platforms would be great. I could never get it to work windows and tbh didn't try too much. You either need MSVC to get it to work because it uses the standard library of MSVC and if you want to use the one that comes with MinGW, well, you're in bad luck. From what I've seen there are some hard-coded MinGW paths (which I didn't believe there could be such a thing in this day and age) and even then I still couldn't make it work properly. I've always had issues with standard includes and libraries. So I decided to be patient for a while and see how it matures for the time being.

Although, in most other cases I've tried it. It was very good at optimizations and feature support. Anyway, I'm going (actually I've already gone) off-topic so I'll stop here.
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Re: What's the inner design [pattern] of Irrlicht?

Post by REDDemon »

Cube_ wrote: MSVC is usually the first to comply with standards but this varies heavily on the specific feature
I slightly disagree, I have a C++11 library, that contains an hack just because MSVC does not comply with standard C++11. :D and fail compilation otherwise. I think this is ok, since they have to get also IDE support (by the way, reshaper is much better and faster than VS refactoring/intellisense), but coming to features (And sometimes even to optimizations) GCC and CLANG are better. Yes, GCC and CLANG do not have intellisense, but if you are using CLion then it is probable you will be more confortable with it than with VS, instead VS really shines with C# (+Resharper) and Xamarin support. I will not be surprised if most cross platform projects will switch to xamarin (again since accessing OpenGL through C# is somewhat slower than C++, 3D engines will be always backed by a native backend (still interesting the evolution of Rust).


Here's one example of hack I did to allow compilation on VS.

Code: Select all

 
template< typename Impl, typename... SmartPointers>
inline void Container::wire(){
 
    isWireable< Impl>(); //compile time test
 
#ifndef _MSC_VER
 
    // Best solution for GCC and CLANG => minimal executable size.
    priv::TypeInfoP types[ sizeof...( SmartPointers)]
                        { &typeid(typename SmartPointers::type)... };
 
#else
    // -this is to fix a VS bug. I manually setted a reasonable high limit  // OUCH
    static_assert( sizeof...(SmartPointers) <= 8,
        "Unable to wire more than 8 dependencies");
 
    priv::TypeInfoP types[8]
        { &typeid(typename SmartPointers::type)... };
#endif
 
    container->wire( &typeid(Impl), types, sizeof...( SmartPointers),
                     &factoryFunction< Impl, SmartPointers...>,
                     &instancesFactoryFunction< Impl, SmartPointers...>);
}
 
to stay in topic, irrlicht uses several patterns, the architecture is to access everything from a root instance, so dependencies are created inside the root, or inside managers created by the root. This is a mix of service locator/factory. Everything is reference counted. To actually extend the functionality you have to extend classes like ISceneNode (this can be viewed like a Decorator/TemplateMethod).

It tries to separate concerns and responsibilities (in example once you get a manager you cannot get the pointer to the device) at its best and to minimize external dependencies (by embedding them or writing its own code).

Irrlicht is not layered, in the sense that below certain interfaces you find immediatly a concrete implementation (Which is basically 2 files, 1 header and 1 source).

Also the irrlicht video driver, is a builder pattern (like OpenGL) because it allows you to build a scene in a imperative way, without even needin a scene manager.
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: What's the inner design [pattern] of Irrlicht?

Post by Cube_ »

REDDemon wrote:
Cube_ wrote: MSVC is usually the first to comply with standards but this varies heavily on the specific feature
I slightly disagree, I have a C++11 library, that contains an hack just because MSVC does not comply with standard C++11. :D and fail compilation otherwise.
I disagree, in my experience GCC has been inconsistent with their correctness, in fact all existing compilers are really inconsistent with whether their implementations suck or not.
REDDemon wrote:I think this is ok, since they have to get also IDE support (by the way, reshaper is much better and faster than VS refactoring/intellisense), but coming to features (And sometimes even to optimizations) GCC and CLANG are better. Yes, GCC and CLANG do not have intellisense, but if you are using CLion then it is probable you will be more confortable with it than with VS, instead VS really shines with C# (+Resharper) and Xamarin support. I will not be surprised if most cross platform projects will switch to xamarin (again since accessing OpenGL through C# is somewhat slower than C++, 3D engines will be always backed by a native backend (still interesting the evolution of Rust).
I know GCC and Clang don't have intellisense and good riddance. Intellisense is not good.
I only really use MSVC on windows because the GCC ports that exist (mingw and cygwin) are utterly abysmal, GCC on its own is pretty good, I'd rate it on par with MSVC - they both have pretty good support and output reasonable assembly.

Well no matter, this is entirely off topic so I suggest we move this to a separate topic if we really must continue comparing compilers (something I find wholly redundant)
"this is not the bottleneck you are looking for"
Post Reply