PloetzS
Topic Author
Posts: 6
Joined: 08 Mar 2018, 10:38

Is a second window possible on Linux with C#?

19 Mar 2018, 19:39

I've searched the forum and the code samples for a second window/dialog window solution but all i found are tips how to fade-out the current view/render tree and fade-in a new render tree (e. g. the discussion "Simulating modal dialog inside a view"). The fade-out/fade-in approach is good for a full screen presentation. But for a window-based presentation this solution looks strange.
What i'm looking for is a solution with a second window. I have already managed to create, display and close a second GL window, that doesn't disturb or crash the main window. But as soon as i connect the OnPreRender() or OnPostRender() event handler, the application crashes.
at <unknown> <0xffffffff>
at (wrapper managed-to-native) Noesis.Renderer.Noesis_Renderer_NeedsOffscreen (System.Runtime.InteropServices.HandleRef) <IL 0x0001a, 0xffffffff>
at Noesis.Renderer.Noesis_Renderer_NeedsOffscreen_ (System.Runtime.InteropServices.HandleRef) <IL 0x00001, 0x00063>
at Noesis.Renderer.NeedsOffscreen () <IL 0x00006, 0x0005b>
at IntegrationSample.DialogWindow.OnPreRender () [0x00013] in /home/rupert/Projects/NoesisGUI/NoesisGUI-IntegrationSample/MainWindow.cs:469
at Noesis.GLUTWrapper.OnPreRender () [0x00010] in /home/rupert/Projects/NoesisGUI/NoesisGUI-IntegrationSample/GLUTWrapper.cs:153
at Noesis.libGLUTWrapper.GLUT_Display () [0x00042] in /home/rupert/Projects/NoesisGUI/NoesisGUI-IntegrationSample/libGLUTWrapper.cs:322
at (wrapper native-to-managed) Noesis.libGLUTWrapper.GLUT_Display () <IL 0x0002f, 0xffffffff>
at <unknown> <0xffffffff>
at (wrapper managed-to-native) Noesis.GLUT.MainLoop () <IL 0x0000e, 0xffffffff>
at Noesis.libGLUTWrapper.GLUT_Run () [0x0009a] in /home/rupert/Projects/NoesisGUI/NoesisGUI-IntegrationSample/libGLUTWrapper.cs:517
at Noesis.GLUTWrapper.Run () [0x00015] in /home/rupert/Projects/NoesisGUI/NoesisGUI-IntegrationSample/GLUTWrapper.cs:291
at IntegrationSample.MainWindow.Run () [0x0018a] in /home/rupert/Projects/NoesisGUI/NoesisGUI-IntegrationSample/MainWindow.cs:269
at IntegrationSample.MainWindow.Main (string[]) [0x001c4] in /home/rupert/Projects/NoesisGUI/NoesisGUI-IntegrationSample/MainWindow.cs:189
at (wrapper runtime-invoke) <Module>.runtime_invoke_void_object (object,intptr,intptr,intptr) <IL 0x00058, 0xffffffff>
For me it looks like a renderer confusion. I can not figure out how each renderer determines it's own OpenGL window and connects to it. This is how i create the renderer for the first and second window (every window has it's own class and consequently it's own member attributes _view and _renderer):
private void Run()
{
....
var content = (Noesis.Grid)Noesis.GUI.LoadXaml("TextBox.xaml");
_view = Noesis.GUI.CreateView(content);
_renderer = _view.Renderer;
_renderer.InitGL(new Noesis.VGOptions());
...
}
private void Run()
{
...
var content = (Noesis.Grid)Noesis.GUI.LoadXaml("SampleGUI.xaml");
_view = Noesis.GUI.CreateView(content);
_renderer = _view.Renderer;
_renderer.InitGL(new Noesis.VGOptions());
...
}
Any ideas? Thanks in advance!
 
User avatar
jsantos
Site Admin
Posts: 2906
Joined: 20 Jan 2012, 17:18
Contact:

Re: Is a second window possible on Linux with C#?

20 Mar 2018, 00:43

For me it looks like a renderer confusion. I can not figure out how each renderer determines it's own OpenGL window and connects to it. This is how i create the renderer for the first and second window (every window has it's own class and consequently it's own member attributes _view and _renderer):
The renderer knows nothing about the window. It just uses the current active context. So, you need to make sure that the context that is bound when the renderer is initialized is the same as the one bound when rendering. You probably need two different contexts, one for each window, and you probably want to enable sharing between them, but that's optional.

By they way, I recommend you upgrading to Noesis 2.1, the API is a bit clearer.
 
nikobarli
Posts: 178
Joined: 26 Apr 2017, 06:23

Re: Is a second window possible on Linux with C#?

20 Mar 2018, 01:04

Hi, I saw your article in codeproject :)

https://www.codeproject.com/Articles/12 ... eatable-fr
 
User avatar
jsantos
Site Admin
Posts: 2906
Joined: 20 Jan 2012, 17:18
Contact:

Re: Is a second window possible on Linux with C#?

20 Mar 2018, 02:43

Oh, you are the author of that article. Awesome! :)
 
PloetzS
Topic Author
Posts: 6
Joined: 08 Mar 2018, 10:38

Re: Is a second window possible on Linux with C#?

20 Mar 2018, 07:26

Hi, you are rigt.

I wanted to get NoisisGUI a little more known to the programmer community. I also introduced NoisisGUI to the German WiKi, because NoisisGUI is not very visible. I plan to add more articles from the perspective of a serious GUI programmer. But I must be sure that NoisisGUI is suitable for the creation of serious GUI.

Back to the question. If it's not bossible to achive this from managed code only, to create a little C or C++ wrapper shared library would not be a show stopper. All that's required for this case is access to the unmanaged pointers, held by the managed code to realize calls into the underlaying native code.

Regards & thanks in advance.
 
User avatar
jsantos
Site Admin
Posts: 2906
Joined: 20 Jan 2012, 17:18
Contact:

Re: Is a second window possible on Linux with C#?

21 Mar 2018, 05:47

Back to the question. If it's not bossible to achive this from managed code only, to create a little C or C++ wrapper shared library would not be a show stopper. All that's required for this case is access to the unmanaged pointers, held by the managed code to realize calls into the underlaying native code.
No, you don't need to create a wrapper at all. Just make sure you are properly creating each GL context and activating them when using the corresponding noesis view. Please, read me previous message again. We have many clients creating several windows with Noesis.
 
PloetzS
Topic Author
Posts: 6
Joined: 08 Mar 2018, 10:38

Re: Is a second window possible on Linux with C#?

23 Mar 2018, 12:08

Hello jsantos,

thank you for your reply and for your advice regarding der OpenGL context! I've made the necessary changes - but without success. This is the main window initialization:
private void Run()
{
	Noesis.GUI.Init();

	// Define the resource folder, ALL resources are loaded from. This includes the fonts. The project must provide them.
	Noesis.GUI.SetResourceProvider("Data");

	// Initialization
	_glWindow = GLWindow.Init(800, 600, "NoesisGUI Integration Sample");

	// Load the global theme (from resource folder).
	var theme = (Noesis.ResourceDictionary)Noesis.GUI.LoadXaml("WindowsStyle.xaml");
	Noesis.GUI.SetTheme(theme);

	// Data loading (from resource folder)
	var content = (Noesis.Grid)Noesis.GUI.LoadXaml("TextBox.xaml");
	_view = Noesis.GUI.CreateView(content);
	_renderer = _view.Renderer;
	_renderer.InitGL(new Noesis.VGOptions());

	// Attach to window events
	_glWindow.Close += this.OnClose;
	_glWindow.Tick += this.OnTick;
	_glWindow.PreRender += this.OnPreRender;
	_glWindow.PostRender += this.OnPostRender;
	_glWindow.Resize += this.OnResize;
	_glWindow.MouseMove += this.OnMouseMove;
	_glWindow.MouseDown += this.OnMouseDown;
	_glWindow.MouseUp += this.OnMouseUp;
	_glWindow.KeyDown += this.OnKeyDown;
	_glWindow.KeyUp += this.OnKeyUp;

	_eventsAttached = true;

	// Main Loop
	GLUT.SetOption(FreeGLUT.GLUT_ACTION_ON_WINDOW_CLOSE, FreeGLUT.GLUT_ACTION_CONTINUE_EXECUTION);
	_glWindow.Run();
	// Do cleanup - since FreeGLUT.GLUT_ACTION_ON_WINDOW_CLOSE is set to FreeGLUT.GLUT_ACTION_CONTINUE_EXECUTION,
	// GLUT.MainLoop() renturns instead of calling c library exit().
	;
}
This is the second window's initialization (no Noisis.GUI calls before GLWindow.InitDialog()):
public void Run()
{
	// Initialization
	_glWindow = GLWindow.InitDialog(300, 150, "Dialog");

	// Data loading (from resource folder)
	var content = (Noesis.Grid)Noesis.GUI.LoadXaml ("SampleGUI.xaml");
	_view = Noesis.GUI.CreateView (content);
	_renderer = _view.Renderer;
	_renderer.InitGL (new Noesis.VGOptions ());

	// Attach to window events
	_glWindow.Close += this.OnClose;
	//_glWindow.PreRender += this.OnPreRender;
	//_glWindow.PostRender += this.OnPostRender;
	_glWindow.Resize += this.OnResize;

	_glWindow.RunInForeignMainLoop();
}
The methods calls GLWindow.Init() and GLWindow.InitDialog() prepare the OpenGL window and memorize display, drawable, and context:
/// <summary>Init a GL application's first window.</summary>
/// <param name="windowWidth">The GL window client area width.</param>
/// <param name="windowHeight">The GL window client area height.</param>
/// <param name="title">The GL window title.</param>
/// <returns>The <see cref="GLUTWrapper"/> of the window.</returns>
public static GLWindow Init(int windowWidth, int windowHeight, string title)
{
	string[] myargv = new string[] { "GLWindow" };
	int myargc = 1;

	GLUT.Init(myargc, myargv);
	GLUT.InitDisplayMode(GLUT.GLUT_RGB | GLUT.GLUT_DOUBLE | GLUT.GLUT_DEPTH | GLUT.GLUT_STENCIL);

	// InvokeResize() is automatically called before InvokeRedraw() -> window dimension must not be saved here.
	GLUT.InitWindowSize(windowWidth, windowHeight);
	GLUT.InitWindowPosition(0, 0);

	GLWindow result = new GLWindow(GLUT.CreateWindow(title), GL.XGetCurrentDisplay (),
		GL.XGetCurrentDrawable (), GL.XGetCurrentReadDrawable (), GL.XGetCurrentContext ());

	return result;
}

/// <summary>Init a GL application's dialog window.</summary>
/// <param name="windowWidth">The GL window client area width.</param>
/// <param name="windowHeight">The GL window client area height.</param>
/// <param name="title">The GL window title.</param>
/// <returns>The <see cref="GLUTWrapper"/> of the dialog.</returns>
public static GLWindow InitDialog(int windowWidth, int windowHeight, string title)
{
	// InvokeResize() is automatically called before InvokeRedraw() -> window dimension must not be saved here.
	GLUT.InitWindowSize(windowWidth, windowHeight);
	GLUT.InitWindowPosition(0, 0);

	GLWindow result = new GLWindow(GLUT.CreateWindow(title), GL.XGetCurrentDisplay (),
		GL.XGetCurrentDrawable (), GL.XGetCurrentReadDrawable (), GL.XGetCurrentContext ());

	return result;
}
Both initializations create different values for window, display, drawable, read-drawable and context, e.g.:
Primaty window: 1, 0x16172a0, 0x2c00002, 0x2c00002, 0x162e650
Secondary window: 2, 0x16172a0, 0x2c000f4, 0x2c000f4, 0x241a70e

The GLUT DisplayProcDelegate implementation ensures display, drawable, read-drawable and context are adjusted before any othe call:
/// <summary>Invoke the registered callbacks for tick, pre-render and post-render.</summary>
/// <remarks>This method is compatible to <see cref="GLUT.DisplayProcDelegate"/>.</remarks>
private void InvokeRedraw()
{
	int windowID = GLUT.GetWindow();
	if (_windowId != windowID)
	{
		throw new InvalidOperationException(this.GetType().Name +
			$":InvokeRedraw() called for window {windowID} but was designed for window {_windowId}.");
	}

	// Ensure display, drawable, read-drawable and context are adjusted for the window to redraw.
	MakeContext ();

	// Frame tick
	if (_tickCallback != null)
	{
		_tickCallback();
	}

	// PreRender
	if (_preRenderCallback != null)
	{
		_preRenderCallback();
	}

	// Render Scene (now only a clear)
	GL.Enable(GL.GL_DEPTH_TEST);
	GL.DepthFunc(GL.GL_LESS);
	GL.ClearDepth(1.0f);
	GL.DepthMask(GL.GL_TRUE);

	GL.Disable(GL.GL_CULL_FACE);
	GL.Disable(GL.GL_ALPHA_TEST);
	GL.Disable(GL.GL_STENCIL_TEST);
	GL.Disable(GL.GL_BLEND);
	GL.Disable(GL.GL_SCISSOR_TEST);

	GL.UseProgram(0);
	GL.BindFramebuffer(GL.GL_FRAMEBUFFER, 0);
	GL.Viewport(0, 0, _width, _height);
	GL.ColorMask(true, true, true, true);

	GL.ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	GL.Clear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
	GL.LoadIdentity();

	// START: Identify window
	GLU.Ortho2D(0,400,0,500);
	if (windowID == 1)
		GL.Color3f(0.5f, 1.0f, 1.0f);
	else
		GL.Color3f(1.0f, 0.5f, 1.0f);
	GL.Begin(GL.GL_POLYGON);
	GL.Vertex2i(200,125);
	GL.Vertex2i(100,375);
	GL.Vertex2i(300,375);
	GL.End();
	// END: Identify window

	GL.Ortho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);

	// PostRender
	if (_postRenderCallback != null)
	{
		_postRenderCallback();
	}

	// End
	GL.Flush();
	GLUT.SwapBuffers();

	// Update again and again...
	GLUT.PostRedisplay();
}
But the new code still comes up with the same crash/stack trace. I don't know what to do in addition.
Stacktrace:

at <unknown> <0xffffffff>
at (wrapper managed-to-native) Noesis.Renderer.Noesis_Renderer_NeedsOffscreen (System.Runtime.InteropServices.HandleRef) <IL 0x0001a, 0xffffffff>
at Noesis.Renderer.Noesis_Renderer_NeedsOffscreen_ (System.Runtime.InteropServices.HandleRef) <IL 0x00001, 0x00063>
at Noesis.Renderer.NeedsOffscreen () <IL 0x00006, 0x0005b>
...
Since I can't inspect the Noesis code, I don't know which handle Noesis.Renderer.Noesis_Renderer_NeedsOffscreen_ () tries to use - obviously an uninitialized handle (0xffffffff).
Just make sure you are properly creating each GL context and activating them when using the corresponding noesis view.
I added code between '// START: Identify window' and '// END: Identify window' to draw differntly colored triangles on primary and secondary window - works fine.
That's why I assume, the adjustment of display, drawable, read-drawable and context works.
But as soon as I enable the '_preRenderCallback' or '_postRenderCallback' the application crashes.

Do I have to ensure by code, that '_view = Noesis.GUI.CreateView(content)' or '_renderer = _view.Renderer' or '_renderer.InitGL(new Noesis.VGOptions())' use the right context?
Is it correct to call '_renderer.InitGL(new Noesis.VGOptions())' for primary and secondary window with Noesis.VGOptions()?
Is the adjustment of display, drawable, read-drawable and context within the GLUT DisplayProcDelegate implementation right or too late?
Is it necessary to adjust display, drawable, read-drawable and context anywhere else in addition?

Thanks in advance.
 
User avatar
jsantos
Site Admin
Posts: 2906
Joined: 20 Jan 2012, 17:18
Contact:

Re: Is a second window possible on Linux with C#?

27 Mar 2018, 10:46

Do I have to ensure by code, that '_view = Noesis.GUI.CreateView(content)' or '_renderer = _view.Renderer' or '_renderer.InitGL(new Noesis.VGOptions())' use the right context?
Is it correct to call '_renderer.InitGL(new Noesis.VGOptions())' for primary and secondary window with Noesis.VGOptions()?
Is the adjustment of display, drawable, read-drawable and context within the GLUT DisplayProcDelegate implementation right or too late?
Is it necessary to adjust display, drawable, read-drawable and context anywhere else in addition?
Yes, when calling renderer.InitGL you need to make sure the right context is active because inside that function we create GL resources that are later reused when rendering. But as said before, we changed many things in the API, I recommend updating to the latest version of NoesisGUI before going on.
 
PloetzS
Topic Author
Posts: 6
Joined: 08 Mar 2018, 10:38

Re: Is a second window possible on Linux with C#?

30 Mar 2018, 10:01

Hello jsantos,

thank you for your reply and for your advice regarding new Noesis version. I've changed from version 2.0.2f2 to 2.1.0f1 (libNoesis.so 22.05.2017 ==> 10.03.2018 and NoesisManaged.dll 22.05.2017 ==> 10.03.2018).
There are massive API changes. Now the programmer is forced to create and assign at least an xaml provider (and, where appropriate, a font provider and/or a texture provider) - but all provider implementations are within the NoesisAppManaged.*.dll - which is available only as NoesisAppManaged.Android.dll and NoesisAppManaged.Windows.dll.
I have copied the EmbeddedXamlProvider code into my project (because there is no NoesisAppManaged.Linux.dll) and made all required API changes, but what I get now is:
SystemDllNotFoundException: Noesis at (wrapper managed-to-native) Noesis.NoesisGUIPINVOKE+SWINGEx)
NoesisManaged.dll and libNoesis.so are copied to the compilation output folder. Is there another *.so or *.dll I have to include into the project?
 
User avatar
jsantos
Site Admin
Posts: 2906
Joined: 20 Jan 2012, 17:18
Contact:

Re: Is a second window possible on Linux with C#?

30 Mar 2018, 19:04

I have copied the EmbeddedXamlProvider code into my project (because there is no NoesisAppManaged.Linux.dll) and made all required API changes,
EmbeddedXamlProvider is for files embedded inside the executable. You probably don't want that. You can easily implement a Xaml provider that reads files from disk. That way you can have the same behavior you had in previous versions.
but what I get now is:
SystemDllNotFoundException: Noesis at (wrapper managed-to-native) Noesis.NoesisGUIPINVOKE+SWINGEx)
NoesisManaged.dll and libNoesis.so are copied to the compilation output folder. Is there another *.so or *.dll I have to include into the project?
You only need libNoesis.so, that error is happening because it cannot be found (Noesis -> libNoesis.so). Are you sure the library is in the same location as the executable?

PS: forget about NoesisManaged.dll, you don't need it.

Who is online

Users browsing this forum: No registered users and 1 guest