Irrlicht Lime is a .NET wrapper for Irrlicht Engine. It is single C++ .NET project which doesn't use P/Invokes, it uses Irrlicht directly from one side, and shows only managed types for the end client application. Originally aimed to be used with C#, VB.NET or other .NET language.

To start developing your own applications, all you need is to add a reference on IrrlichtLime.dll to your .NET project. When running your application, make sure that IrrlichtLime.dll and Irrlicht.dll are placed near your executable.

Last edited by greenya on Sun Mar 06, 2016 3:35 am, edited 20 times in total.

Wow, fantastic news! A lot of people have been waiting for this. I know very little about .NET/CLR, but I have some questions all the same:

1) Will it also work on Linux/MacOS through Mono?
2) Does your method have less overhead than Irrlicht.Net CP's methods, ie will it be easier to upgrade between versions?
3) Will you be using it yourself, and therefore be forced to keep it up to date?
4) Are there any design considerations we should keep in mind when updating Irrlicht, so we make it easier for you and other wrapper authors?

I'am not familiar with Mono and cannot give an answer right now. All i can say is that i do not want to use anything like DllImport and so, where you really get too close to OS environment. The idea at first to wrap basic functionality and leave its meaning the same as in Irrlicht, not to mix or build complex solution, because that will make any further Irrlicht versions support harder and harder.

bitplane wrote:2) Does your method have less overhead than Irrlicht.Net CP's methods, ie will it be easier to upgrade between versions?

Yes, that is a priority. All the functionality should be clear and easy updated to new Irrlicht changes. I omit documentation since it is not a different engine, but a wrapper. So i'll try to keep most structure close to one that Irrlicht has. However, as it .NET, i would like to use its language specifics like properties, events etc. For example, Irrlicht has SKeyMap struct and every function that uses it requires 2 params: a pointers on the array of this struct and a value with its size -- that is common practice in C++ coding, but its odd to .NET where you have all types managed. So this functionality covered by KeyMap class now and easy to use. Other example about "staying close to native API": native IrrlichtDevice has no method getWindowCaption() (only "set"), so it also absent in wrapper even if its realization is simple.

bitplane wrote:3) Will you be using it yourself, and therefore be forced to keep it up to date?

Yes. Now it is possible to load a mesh and add FPS camera -- that's not bad, and can be used already. One more example: to have a C# WinForms project that need to visualize sort of 3D chart -- that shouldn't be hard to do. The usage must be simple as C# is. Nobody will use it on C# if it will be harder than it is in C++ now.

bitplane wrote:4) Are there any design considerations we should keep in mind when updating Irrlicht, so we make it easier for you and other wrapper authors?

I think i will get something to say about it when get more deeper into wrapping.

For now on C++ level all is clear, for instance: we have core::vector2df which is a value type, so cannot be null: but in .NET wrapper i created Core::Vector2Df which is reference type just because managed types cannot contain unmanaged values, only references on them. This restriction brings 2 problems:
- user will be able to pass null and that is why incoming value should be checked;
- as we store reference on a value, we need to free memory when variable of wrapping class frees, so we bother with additional functionality: all constructors allocates value, destructor and finalizer (a .NET term). Also holding a real object (that is wrapped by this class) is important, because all that wrapper should do -- redirect call to native underlying Irrlicht API, and not to re-implement the functionality of it.

Other thing is that you might be wondering why Core::Vector2D is not a template class, but instead of it we have xx2Df and xx2Di -- that an odd at first look. Indeed it is more simpler and effective (for further support) and it would look like "class Vector2D<T> : NativeValue<core::vector2d<T>>", BUT when comes to linking compiled code, linker says:

Just finished porting/designing stuff to compile 03.CustomSceneNode, which was a challenge indeed, because its kind of hard to fake inheritance from ISceneNode, when managed types cannot inherit native C++ stuff.

So the custom node can be inherited from SceneNode now in the next way:

Couple of notices:1. Not all 5 events that listed in constructor must be handled, but in most cases you will handle them all; some event are vital, for instance OnGetBoundingBox and OnGetMaterial, otherwise ASSERT will popup (in debug only ofcause).2. OnGetBoundingBox is important and vital for your inheritance, since base ISceneNode has no implementation for it at all -- that is weired thing in Irrlicht. Bounding box should be provided by each implementor. That is why you should never call something like "device->getSceneManager()->getRootSceneNode()->getBoundingBox()" because there is no special node-type for root scene node.For example 2 virtual implementations:

same for OnRender event, its ISceneNode::render() is completely virtual and must be defined if you inherited from SceneNode. The only difference that in C++ will not be able compile your code, because you will not be able to create an instance of your node with anything virtual left. But in C# i cannot inherit this interface and let user implement all, so internally there is C++ class called SceneNodeInheritor which serves as user inherited object, provides all functionality to its managed brother SceneNode.

You may ask why i choose events instead of virtual members of SceneNode? Because:1. With events i can hold user functionality and call it when i really need it to call, so emulate inheritance; indeed, execution in inherited class for several members goes in different way, like:

if user able to override a method, than he able do not call base method (example: "base.render();" in C# or "ISceneNode::render();" in C++), and block wrapping code.2. I cannot have anything pure virtual like ISceneNode::getBoundingBox(), because SceneNode should be initially instantiable because the objects of the class creates all the time when needed to wrap ISceneNode pointer.

driver.DrawVertexPrimitiveList(vertices, indices);

You may notice that DrawVertexPrimitiveList() has much less arguments in comparison to its C++ analog call

New examples are available: 05.UserInterface, 06.2DGraphics.
IrrlichtLime still doesn't provide all the bouquet of GUI elements that Irrlicht does. Also it is impossible for now to create custom GUI element.

~ When method returns a SceneNode, in general (and in Irrlicht ofcause) it means that you can cast it to more specific type if you completly sure that it is it, and it may looks like next sample code should work:

Vector3Df v1 = new Vector3Df(10, 20, 30);vector3Df v2 = v1; // this will create a reference on v1, so when you do v2.X = 11; then v1.X == 11 will be "true"Vector3Df v3 = new Vector3Df(v1); // this will create new copy of v1; this is what you need in most cases

~ When you need to change only 1 member of core type value from the property, for example SceneNode.Position:

~ In this release operators are implemented for next core types: Vector2D, Vector3D, Rect and Dimension2D ("operator -" is additionaly implemented for Dimension2D, since Irrlicht doesn't have one).And now it is possibly to write:

~ In Video::Coloru/f class changed location of Alpha argument (in constructor and Set() methods), now it goes last and has default value 255/1.0f. Now, when you need to define opaque yellow color, you can do:

~ In some CreateXXX methods of ParticleSystemSceneNode class, time values specifies as float (not as s32/u32 as in Irrlicht), since proper classes (which this CreateXXX returns) operates with float too.

~ Wrapped all Irrlicht's particle emitters and affectors. They are all now can be created via ParticleSystemSceneNode.

- Added overloads to GUIFont.Draw(): now position can be specified as Recti, Vector2Di or two int values (x and y).

- Rect improved; now available int and float versions.

- Dimension2D improved; now available unsigned int and float versions.

- Vector2D improved; now available int and float versions.

- VideoDriver has been extended with new methods: ClearZBuffer, CreateScreenShot, DeleteAllDynamicLights, Draw2DLine, Draw3DBox, Draw3DLine, Draw3DTriangle, DrawMeshBuffer, DrawPixel, EnableClipPlane. Changed argument order of some VideoDriver.DrawXXX methods to be same structured: now color follows at the end (or before clip if present) and it became mandatory.

- Vector3D class has been improved: all native functionality wrapped (including operators). Templates imitation has been implemented and now there are two classes for 3d vectors: Vector3Df and Vector3Di.

- Added enum LightType, classes LightSceneNode, Light and Colorf. Normalized argument list of RGBA values in constructors and Set() methods of Coloru/f classes: for constructors: R, G, B, A = 255 or 1.0f, for Set(): R, G, B, A? (if A not set, than it will not be changed). All the examples updated to this change, since there is no need to specify alpha value all the time now (if its 255).

About Mono: i have tried Mono (from http://monodevelop.com/ latest stable) on Windows. And if i add reference to IrrlichtLime.dll it works OK. But i'm not sure that on Linux it is possible to reference Windows DLL (I'm not familiar with this at all). If some recompiling of IrrlichtLime itself required, then that linux compiler must support CLR.

Can you give me info how its all done; how on linux all the Mono works?

Amazing job, greenya, thank you very much for your efforts so far! I also just started to clean up the Irrlicht.NET codes [1] and rebase to 1.7.1 when I saw your project. IrrlichtLime definitely has less overhead than Irrlicht.NET, and it doesn't use P/Invoke, so performance must also be better.

For curiousity, greenya, how do you work with IReferenceCounted? I'm not very familiar with managed C++, is there any place we need to be cautious about GC or is it something that will just work with C++?

BlindSide wrote:I have run EXE compiled on Windows in Mono on Linux, so I'm fairly sure it's just as possible to use a Windows DLL.

Mono can run .NET assemblies just fine, but you might have a problem with native dlls (eg Irrlicht.dll) and as far as I know (although haven't checked it in a while) mono doesn't support mixed assemblies where you link managed and unmanaged C++. The page I found on the mono site recommends compiling with the /clr:safe switch, but I don't think that is possible, because IrrlichtLime links against native Irrlicht. There might be ways around it, but I'm not sure what would be needed and also what would happen with the native dependencies (maybe you'd need a different version for Linux/Mac/Windows?).