Irrlicht Lime is a .NET wrapper for Irrlicht Engine

Announce new projects or updates of Irrlicht Engine related tools, games, and applications.
Also check the Wiki
greenya
Posts: 1012
Joined: Sun Jan 21, 2007 1:46 pm
Location: Ukraine
Contact:

Re: Irrlicht Lime is a .NET wrapper for Irrlicht Engine

Post by greenya »

Jonhson243 wrote:-Can you give me the one line statement to translate a camera ?
-The same but to rotate a camera
It depends on what you need it to be. If you need it to rotate without user input, you just use some RotationAnimator and the mode will be constantly rotated. If you need give user ability to navigate, you can check how its done in L04.ParticleEmitterViewer, it has a slider (a WinForms UI control) which user drags it sends particular messages to rendering thread using Viewport class:

Code: Select all

private void trackBarCameraView_Scroll(object sender, EventArgs e)
{
    viewport.EnqueueCommand(CommandType.CameraView, (float)trackBarCameraView.Value);
}
So you can use same approach. You can add more commands to CommandType enum if you need and process them in rendering thread.
Jonhson243 wrote:-And finally, I would just need to insert a background 2D image. So I just need the code to insert such background then I'll manage the rest myself. The idea is to position the 3D object on the background image.
There is an example L05.ScreenshotToTexture, which draw a texture on the background and rotates the cube with that texture. Generally all you need is to load the image file as texture and draw it before scene.DrawAll() call:

Code: Select all

device.VideoDriver.GetTexture( // loads the image file as a texture
device.VideoDriver.Draw2DImage( // draws the texture
roxaz
Posts: 575
Joined: Tue Jan 23, 2007 8:35 pm
Location: LT

Re: Irrlicht Lime is a .NET wrapper for Irrlicht Engine

Post by roxaz »

By the way i crafted proof of concept code that fixes crash due to textures being deleted in another thread. Its a dirty hack. Idea is simple - when ref count is 1 and finalizer calls drop we push native object to the list, later on method called from main thread iterates list and drops final reference thus freeing up object. For some reason i bumped into weird internal compiler errors when i tried to use System::Windows::Threading::Dispatcher to invoke drop on main thread. Using that would be preferable to doing this manually. Anyway - please evaluate idea.

Code: Select all

Index: source/ReferenceCounted.cpp
===================================================================
--- source/ReferenceCounted.cpp (revision 493)
+++ source/ReferenceCounted.cpp (working copy)
@@ -3,6 +3,7 @@
 
 using namespace irr;
 using namespace System;
+using namespace System::Threading;
 
 namespace IrrlichtLime {
 
@@ -28,20 +29,59 @@
 ReferenceCounted::ReferenceCounted(irr::IReferenceCounted* referenceCounted_or_null)
 {
    m_ReferenceCounted = referenceCounted_or_null;
+   if( referenceCounted_or_null != nullptr )
+       Grab();
 }
 
 bool ReferenceCounted::Drop()
 {
    LIME_ASSERT(m_ReferenceCounted != nullptr);
-   return m_ReferenceCounted->drop();
+   GarbageCollect();
+   if(m_ReferenceCounted->drop())
+   {
+       m_ReferenceCounted = nullptr;
+       return true;
+   }
+   return false;
 }
 
 void ReferenceCounted::Grab()
 {
    LIME_ASSERT(m_ReferenceCounted != nullptr);
    m_ReferenceCounted->grab();
+   GarbageCollect();
 }
 
+ReferenceCounted::!ReferenceCounted()
+{
+   if( m_ReferenceCounted != nullptr )
+   {
+       if(m_ReferenceCounted->getReferenceCount() == 1 && Thread::CurrentThread->ManagedThreadId != m_MainThreadId)
+       {
+           Monitor::Enter(m_PendingDeletion);
+           IntPtr ptr((Void*)m_ReferenceCounted);
+           if(!m_PendingDeletion->Contains(ptr))
+               m_PendingDeletion->Add(ptr);
+           Monitor::Exit(m_PendingDeletion);
+       }
+       else
+           Drop();
+   }
+}
+
+void ReferenceCounted::GarbageCollect()
+{
+   if((Environment::TickCount - m_LastGarbageCollect) > 60000 && Thread::CurrentThread->ManagedThreadId == m_MainThreadId)
+   {
+       m_LastGarbageCollect = Environment::TickCount;
+       Monitor::Enter(m_PendingDeletion);
+       for each(IntPtr ptr in m_PendingDeletion)
+           ((irr::IReferenceCounted*)ptr.ToPointer())->drop();
+       m_PendingDeletion->Clear();
+       Monitor::Exit(m_PendingDeletion);
+   }
+}
+
 String^ ReferenceCounted::DebugName::get()
 {
    LIME_ASSERT(m_ReferenceCounted != nullptr);
Index: source/ReferenceCounted.h
===================================================================
--- source/ReferenceCounted.h   (revision 493)
+++ source/ReferenceCounted.h   (working copy)
@@ -4,6 +4,7 @@
 
 using namespace irr;
 using namespace System;
+using namespace System::Threading;
 using namespace IrrlichtLime::Core;
 
 namespace IrrlichtLime {
@@ -21,11 +22,21 @@
    property String^ DebugName { String^ get(); }
    property int ReferenceCount { int get(); }
 
+   ~ReferenceCounted(){this->!ReferenceCounted();}
+   !ReferenceCounted();
+
 internal:
 
    ReferenceCounted(irr::IReferenceCounted* referenceCounted_or_null);
 
    irr::IReferenceCounted* m_ReferenceCounted;
+
+   void GarbageCollect();
+
+   delegate bool DropDelegate();
+   static int m_MainThreadId = Thread::CurrentThread->ManagedThreadId;
+   static List<IntPtr>^ m_PendingDeletion = gcnew List<IntPtr>();
+   static int m_LastGarbageCollect = 0;
 };
 
 } // end namespace IrrlichtLime
\ No newline at end of file
 
greenya
Posts: 1012
Joined: Sun Jan 21, 2007 1:46 pm
Location: Ukraine
Contact:

Re: Irrlicht Lime is a .NET wrapper for Irrlicht Engine

Post by greenya »

Thats some true street magic is going on at GarbageCollect() :)
Pilo
Posts: 2
Joined: Wed Aug 28, 2013 1:21 pm

Re: Irrlicht Lime is a .NET wrapper for Irrlicht Engine

Post by Pilo »

Hi, I have been using IrrlichtLime for a few weeks now and I have to say I am truly impressed by how good it is.

Unfortunately, I hit a bump in the road and I can't undestand what I should do to get out of it: what I want to do is basically to have a plane with a texture repeated across it. Based on some examples around and the documentation, I am doing the following:

Code: Select all

 
var grid = ScreenManager.Scene.AddHillPlaneMesh("grid", DIMENSION2DF_ONE, DIMENSION2DI_ONE);
var gNode = ScreenManager.Scene.AddMeshSceneNode(grid, null, MY_ID);
 
gNode.Position = new Vector3Df();
gNode.Scale = new Vector3Df(20, 1, 20);
gNode.SetMaterialFlag(MaterialFlag.Lighting, false);
gNode.SetMaterialType(MaterialType.TransparentAlphaChannel);
gNode.GetMaterial(0).SetTexture(0, ScreenManager.Driver.GetTexture(MY_TRANSPARENT_TEXTURE_HERE));
gNode.GetMaterial(0).GetTextureMatrix(0).SetTextureScale(20, 20);
 
But I end up with a huge square with a scaled up texture, and not a repeated texture as I would like.


I also tried the following, based on example 12 (TerrainRendering)

Code: Select all

 
var terrain = ScreenManager.Scene.AddTerrainSceneNode(
    (string)null, 
    null, 
    MY_ID, 
    new Vector3Df(),
    new Vector3Df(), 
    new Vector3Df(20, 1, 20), 
    new Color(255, 255, 255), 
    5, 
    TerrainPatchSize._17, 
    0, 
    true); //should let me add the mesh even if the heightmap is null
terrain.SetMaterialFlag(MaterialFlag.Lighting, false);
terrain.SetMaterialType(MaterialType.TransparentAlphaChannel);
terrain.SetMaterialTexture(0, ScreenManager.Driver.GetTexture(MY_TRANSPARENT_TEXTURE_HERE));
         
terrain.ScaleTexture(0, 20);
 
And in this case I end up with nothing at all on screen.

Any idea on what I am doing wrong?

Thanks
greenya
Posts: 1012
Joined: Sun Jan 21, 2007 1:46 pm
Location: Ukraine
Contact:

Re: Irrlicht Lime is a .NET wrapper for Irrlicht Engine

Post by greenya »

Pilo wrote:...a plane with a texture repeated across it.
Hello!

Well, your first approach was right, the second one i didn't tested. Anyway, the problem was that GetTextureMatrix() returns a copy of the matrix, so the intention is that you save it, make changes and call SetTextreMatrix(). I made next code with the screenshot.

Code: Select all

            var grid = smgr.AddHillPlaneMesh("grid", new Dimension2Df(100), new Dimension2Di(1));
            var gNode = smgr.AddMeshSceneNode(grid);
            gNode.SetMaterialFlag(MaterialFlag.Lighting, false);
            gNode.SetMaterialType(MaterialType.TransparentAddColor);
            gNode.SetMaterialTexture(0, driver.GetTexture("../../media/particlegreen.jpg"));
            Matrix m = gNode.GetMaterial(0).GetTextureMatrix(0); // here, while debugging, you can see "m.m_DeleteOnFinalize == true", which means that "m" contains a copy of texture matrix
            m.Scale = new Vector3Df(20);
            gNode.GetMaterial(0).SetTextureMatrix(0, m);
Image
Pilo
Posts: 2
Joined: Wed Aug 28, 2013 1:21 pm

Re: Irrlicht Lime is a .NET wrapper for Irrlicht Engine

Post by Pilo »

Thanks a lot, it works perfectly! I didn't know about m_DeleteOnFinalize.. I am still learning about all of this :D
Jonhson243
Posts: 9
Joined: Sun Aug 04, 2013 4:03 pm

Re: Irrlicht Lime is a .NET wrapper for Irrlicht Engine

Post by Jonhson243 »

Hi!
I'm facing what I believe will be my last issue on this project. I'm allowing the user to change the color of the node by clicking on a button in the WPF part of the UI. The problem I have is the following :

Not every node can be colored the same way, therefore the colours list for each node is generated in the Irrlicht Thread. I have to wait that this list is generated in the Irrlicht Thread so that I can generate a colored button for every color of the list in the WPF part of the UI.

My problem is that I can't wait ! I mean : every time I try to put a tempo in the window thread, the rendering in the viewport becomes terrible, not smooth at all. Looks like there is a problem with the vsync between WPF and the Irrlicht. What I'm saying is certainly not accurate but this is the my intuition, hope it will give you an idea. To elaborate this tempo, I tried several things :

Put

Code: Select all

 while(!(bool)viewport.checkState) ;
In the window_load function of my WPF window. checkState is a variable that I set to "true" in the Irrlicht Thread when I'm sure that the colours list have been generated. I use the thread safe techniques that greenya taught me to read and to set the variable (private read only object...). But it produces the same ugly rendering in the viewport.

Then, I also try to simply wait for some seconds in my window_load function with

Code: Select all

Thread.Sleep(2000)
But it produces the same distortion.

The problem is clearly with the fact of temporizing in the Window Thread, the viewport doesn't seem to like it.
Any idea of how I can handle it ? I checked the ParticleEmitter example but it seems that they don't need a tempo.

Image
greenya
Posts: 1012
Joined: Sun Jan 21, 2007 1:46 pm
Location: Ukraine
Contact:

Re: Irrlicht Lime is a .NET wrapper for Irrlicht Engine

Post by greenya »

I don't really get what is the problem.
If generation time of some colors take so much than why you just don't pre-generate them all?
Why do you need to generate the colors in the Irrlicht thread? Maybe you can do it in WPF thread, when user selects a color, you just pass it to the Irrlicht thread.
And nothing like

Code: Select all

while(!(bool)viewport.checkState) ;
or

Code: Select all

Thread.Sleep(2000)
is correct in most cases. You force to wait the thread for something to happen. Instead, the logic should be next: you should check for example viewport.checkState and if its "not ready", you should continue the thread and do all the stuff (rendering in case of Irrlicht thread), and on next iteration you check viewport.checkState again and if its ready at that moment - you do the job.
mrfireturkey
Posts: 1
Joined: Tue Nov 05, 2013 8:27 pm

Re: Irrlicht Lime is a .NET wrapper for Irrlicht Engine

Post by mrfireturkey »

Hello, I've found the Irrlicht Lime wrapper to be quite excellent!

I'm having trouble converting this 2D image with rotate method, posted here, into the C# Lime equivalent:
http://irrlicht.sourceforge.net/forum/v ... =9&t=32388

I've attempted to extend this 2D example into my application.

Here is what I have so far, but it doesn't draw anything to the screen, where the standard Draw2d

Code: Select all

 
public class Sprite
{
        public Texture BaseTexture { get; set; }
        public float Rotation { get; set; }
        public Vector2Di Position { get; set; }
        public Vector2Di RotationPoint { get; set; }
        public Vector2Df Scale { get; set; }
        public Recti SourceRect { get; set; }
 
        public Sprite()
        {
            BaseTexture = null;
            Rotation = 0;
            Position = new Vector2Di();
            RotationPoint = new Vector2Di();
            Scale = new Vector2Df();
            SourceRect = new Recti();
        }
 
        // Works fine
        public void DrawSimple(VideoDriver driver)
        {
            driver.Draw2DImage(BaseTexture, Position);
        }
 
        // This is the trouble method //
        public void DrawRotate(VideoDriver driver, Color color, bool UseAlphaChannel)
        {
            // Store and clear the projection matrix
           Matrix oldProjMat = driver.GetTransform(TransformationState.Projection);
           driver.SetTransform(TransformationState.Projection, new Matrix());
 
            // Store and clear the view matrix
            Matrix oldViewMat = driver.GetTransform(TransformationState.View);
            driver.SetTransform(TransformationState.View, new Matrix());
 
            // Store and clear the world matrix
            Matrix oldWorldMat = driver.GetTransform(TransformationState.World);
            driver.SetTransform(TransformationState.World, new Matrix());
 
            // Find horizontal and vertical axes after rotation
            float c = (float)Math.Cos(-Rotation * 0.017453f);
            float s = (float)Math.Sin(-Rotation * 0.017453f);
 
            Vector2Df horizontalAxis = new Vector2Df(c, s);
            Vector2Df verticalAxis = new Vector2Df(s, -c);
 
            // First, we'll find the offset of the center and then where the center would be after rotation
            Vector2Df centerOffset = new Vector2Df(Position.X + SourceRect.Width / 2.0f * Scale.X - RotationPoint.X, Position.Y + SourceRect.Height / 2.0f * Scale.Y - RotationPoint.Y);
            Vector2Df center = new Vector2Df( (horizontalAxis.X * centerOffset.X) - (verticalAxis.X * centerOffset.Y), (horizontalAxis.Y * centerOffset.X) - (verticalAxis.Y * centerOffset.Y) );
            center.X += RotationPoint.X;
            center.Y += RotationPoint.Y;
 
            // Now find the corners based off the center
            Vector2Df cornerOffset = new Vector2Df(SourceRect.Width * Scale.X / 2.0f, SourceRect.Height * Scale.Y / 2.0f);
            verticalAxis *= cornerOffset.Y;
            horizontalAxis *= cornerOffset.X;
            Vector2Df[] corner = new Vector2Df[4];
            corner[0] = center + verticalAxis - horizontalAxis;
            corner[1] = center + verticalAxis + horizontalAxis;
            corner[2] = center - verticalAxis - horizontalAxis;
            corner[3] = center - verticalAxis + horizontalAxis;
 
            // Find the uv coordinates of the sourceRect
            Vector2Df textureSize = new Vector2Df(BaseTexture.Size.Width, BaseTexture.Size.Height);
            Vector2Df[] uvCorner = new Vector2Df[4];
            uvCorner[0] = new Vector2Df(SourceRect.UpperLeftCorner.X, SourceRect.UpperLeftCorner.Y);
            uvCorner[1] = new Vector2Df(SourceRect.LowerRightCorner.X, SourceRect.UpperLeftCorner.Y);
            uvCorner[2] = new Vector2Df(SourceRect.UpperLeftCorner.X, SourceRect.LowerRightCorner.Y);
            uvCorner[3] = new Vector2Df(SourceRect.LowerRightCorner.X, SourceRect.LowerRightCorner.Y);
            for(int i = 0; i < 4; i++)
            {
                uvCorner[i] /= textureSize;
            }
 
            // Vertices for the image
            Vertex3D []vertices = new Vertex3D[4];
            ushort []indices = { 0, 1, 2, 3 ,2 ,1 };
 
            // Convert pixels to world coordinates
            Vector2Df screenSize = new Vector2Df(driver.ViewPort.Width, driver.ViewPort.Height);
            for (int i = 0; i < 4; i++) 
            {
                vertices[i] = new Vertex3D();
                vertices[i].Position = new Vector3Df(((corner[i].X/screenSize.X)-0.5f)*2.0f,((corner[i].Y/screenSize.Y)-0.5f)*-2.0f,1);
                vertices[i].TCoords = uvCorner[i];
                vertices[i].Color = color;
            }
 
            // Create the material
            Material material = new Material();
            material.BlendOperation = BlendOperation.Add;
            material.Lighting = false;
            material.ZWrite = false;
            material.ZBuffer = ComparisonFunc.Disabled;
            material.BackfaceCulling = false;
            material.SetTexture(0, this.BaseTexture);
            
            /* can't find lime equivalent
            material.MaterialTypeParam = 
                irr::video::pack_texureBlendFunc(irr::video::EBF_SRC_ALPHA, 
                    irr::video::EBF_ONE_MINUS_SRC_ALPHA, 
                    irr::video::EMFN_MODULATE_1X, 
                    irr::video::EAS_TEXTURE | irr::video::EAS_VERTEX_COLOR); 
            */
 
            if(UseAlphaChannel)
                material.Type = MaterialType.OneTextureBlend;
            else
                material.Type = MaterialType.Solid;
 
            driver.SetMaterial(material);
            driver.Draw2DVertexPrimitiveList(vertices, indices);
 
            // Restore projection, world, and view matrices
            driver.SetTransform(TransformationState.Projection, oldProjMat);
            driver.SetTransform(TransformationState.View ,oldViewMat);
            driver.SetTransform(TransformationState.World, oldWorldMat);
           
        }
}
 
If I'm totally missing something, or there is a much easier way to rotate a 2d image, let me know. My previous games were done with the Haaf's Game engine. Unfortunately I can't mix 3D in with it, and Irrlicht Lime is otherwise awesome except not being able to rotate a 2d image intuitively.

Thanks.
greenya
Posts: 1012
Joined: Sun Jan 21, 2007 1:46 pm
Location: Ukraine
Contact:

Re: Irrlicht Lime is a .NET wrapper for Irrlicht Engine

Post by greenya »

Hello.
mrfireturkey wrote:

Code: Select all

 
            /* can't find lime equivalent
            material.MaterialTypeParam = 
                irr::video::pack_texureBlendFunc(irr::video::EBF_SRC_ALPHA, 
                    irr::video::EBF_ONE_MINUS_SRC_ALPHA, 
                    irr::video::EMFN_MODULATE_1X, 
                    irr::video::EAS_TEXTURE | irr::video::EAS_VERTEX_COLOR); 
            */
 
Right now, Lime has no pack_texureBlendFunc(), temporary you can write it yourself.
Here how it can be done:

Code: Select all

// Floating-point representation of an unsigned integer value.
public static float FR(uint x)
{
    return BitConverter.ToSingle(BitConverter.GetBytes(x), 0);
}
 
// MaterialType.OneTextureBlend: pack srcFact, dstFact, Modulate and alpha source to MaterialTypeParam
// alpha source can be an OR'ed combination of AlphaSource values.
public static float pack_textureBlendFunc(BlendFactor srcFact, BlendFactor dstFact, ModulateFunc modulate = ModulateFunc._1x, AlphaSource alphaSource = AlphaSource.Texture)
{
    uint x = (((uint)alphaSource) << 12) | (((uint)modulate) << 8) | (((uint)srcFact) << 4) | ((uint)dstFact);
    return FR(x);
}
Now your code can use it like:

Code: Select all

material.MaterialTypeParam = pack_textureBlendFunc(
    BlendFactor.SrcAlpha,
    BlendFactor.OneMinusSrcAlpha,
    ModulateFunc._1x,
    AlphaSource.Texture | AlphaSource.VertexColor);
Here is what I have so far, but it doesn't draw anything to the screen, where the standard Draw2d
Try my code above. If you don't see anything, then you should try step-by-step approach: first try do draw an image without special material blend functions and without rotations, then if you see it, you can go for the next step. Eventually you will stop seeing the image, and you will know what step causes it.
NemoStein
Posts: 17
Joined: Mon Aug 11, 2008 12:04 am

Re: Irrlicht Lime is a .NET wrapper for Irrlicht Engine

Post by NemoStein »

greenya,

If you follow this thread you'll see that CuteAlien made a small (but precious) bugfix in the Collada loader.

He said that the fix won't come until 1.9, but that doesn't matter for me too much, as I use Lime and, as you use the IrrLicht trunk, I can have the fix faster.
Could you, by any chance, recompile Lime? :D

If not, I understand perfectly, but you'll make a kid very happy if you do! ^_^
greenya
Posts: 1012
Joined: Sun Jan 21, 2007 1:46 pm
Location: Ukraine
Contact:

Re: Irrlicht Lime is a .NET wrapper for Irrlicht Engine

Post by greenya »

Next Lime version will be released sooner than Irrlicht 1.9. But not this week for sure, more likely 1-2 weeks later.
NemoStein
Posts: 17
Joined: Mon Aug 11, 2008 12:04 am

Re: Irrlicht Lime is a .NET wrapper for Irrlicht Engine

Post by NemoStein »

I'm looking forward to it...
cra0kalo
Posts: 3
Joined: Fri Aug 09, 2013 1:56 pm
Location: String.Null
Contact:

Re: Irrlicht Lime is a .NET wrapper for Irrlicht Engine

Post by cra0kalo »

I will be posting my winform viewport control which lets the user interact with irrlicht through a class I wrote which inherents the control.panel class ill release it once i release the tool im working on
Looking forward to the next lime release
giulioz
Posts: 8
Joined: Mon Jun 24, 2013 2:21 pm

Re: Irrlicht Lime is a .NET wrapper for Irrlicht Engine

Post by giulioz »

It's not possible to inherit MeshLoader, is this a bug? How do I create a custom MeshLoader?
Thank you :)
Post Reply