samssonart's picture

Can't get GLWidget to render in Monodevelop

Hi, I've been struggling with the GLWidget for GTK# for some time now, first I couldn't even make the app compile, but all that is sorted out. Now I have a GTK# project that has a Vbox with two divisions, one has a menu bar and the other a GLWidget. I saw the "documentation" for the GLWidget usage and it says to hook to the RenderFrame event or override OnRenderFrame() method. I implemented an event handler for the RenderFrame event but I can't even create a simple triangle. I haven't been able to override OnRenderFrame(), I don't know where to place my implementation, because my MainWindow inherits from GTK.Window and if I create an override method for OnRenderFrame(), the compiler (obviuosly) complaints that there is no OnRenderFrame() method to override. Does anyone have a simple "draw a triangle" example with the GLWidget interacting with other GTK# widgets? Or can anyone pin down the problem with my code?

using System;
using Gtk;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Audio;
using OpenTK.Audio.OpenAL;
using OpenTK.Input;
 
public partial class MainWindow : Gtk.Window
{
	public MainWindow () : base(Gtk.WindowType.Toplevel)
	{
		Build ();
	}
 
	protected void GLWidgetInitialize (object sender, System.EventArgs e)
	{
		int width = 0, height = 0;
		//glwidget7.GdkWindow.GetSize(out width, out height);	
		this.vbox3.GetSizeRequest(out width, out height);
		GL.Viewport(0, 0, width, height);
		GL.ClearColor(1.0f, 1.0f,1.0f,1.0f);
		GL.Clear(ClearBufferMask.ColorBufferBit);
	}
 
	protected void OnDeleteEvent (object sender, DeleteEventArgs a)
	{
		Application.Quit ();
		a.RetVal = true;
	}
 
 
	protected void OnRenderFrameWidget (object sender, System.EventArgs e)
	{
 
		GL.ClearColor(1.0f, 1.0f,1.0f,1.0f); //By the way, tweaking this actually changes the widget's background color
               GL.Begin(BeginMode.Triangles);
 
        	GL.Color3(1.0f, 1.0f, 0.0f); GL.Vertex3(-1.0f, -1.0f, 4.0f);
            GL.Color3(1.0f, 0.0f, 0.0f); GL.Vertex3(1.0f, -1.0f, 4.0f);
            GL.Color3(0.2f, 0.9f, 1.0f); GL.Vertex3(0.0f, 1.0f, 4.0f);
 
        GL.End();
	}
 
}

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
samssonart's picture

Really, no answers? Well, alright, thanks anyway. Guess i'll just have to look for other technology for my project.

gooberking's picture

I am going of memory from a few months ago but I had a couple of snags that kept me from getting visuals when using the widget.

First is you need to be sure, ( and I may be mixing up another issue. I will check later if you are still looking for help) , Open GL is set up accurately. If you don't have the aspect of your window calculated you won't see anything but your draw color which caused me some hassle for a time.

The second thing is the widget render function isn't a performance window. There is another thread detailing the problem, which basically boils down to the event only firing when when GTK decides the screen needs a redraw. The option that you are more than likely going to need is to create your own idle event handler that fires when GTK runs out of events to process. Which basically means if GTK is not busy the Open GL context will be processed instead.

The details for this have been addressed in another thread. if you can't find it just look up GTK# idle event handlers and call it whatever suits you. If you still cant get it I can probably check back in a while and post the code I have working. Once its going its great, and Opentk is a fantastic way to interface with OpenGL via C#.

***edit
Didn't see the aspect code in your OGL init code. Should look something like

float aspect_ratio = glcontext_width_req / glcontext_height_req; 			
		    Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, aspect_ratio, 1.0f, 64.0f);

Anyone only getting a draw color should double check this.

The full code for my init of the widget looks like this. Some of it is probably not needed, but start from here if all else fails

protected virtual void OnGlwidget2Initialized (object sender, System.EventArgs e)
	{
		//gl
 
		 float glcontext_width_req = glwidget2.WidthRequest;
		float glcontext_height_req = glwidget2.HeightRequest;
		float aspect_ratio = glcontext_width_req / glcontext_height_req; 
 
		GL.MatrixMode(MatrixMode.Modelview);
		GL.LoadIdentity();
		GL.ShadeModel(ShadingModel.Smooth);			
		Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, aspect_ratio, 1.0f, 64.0f);
		 GL.MatrixMode(MatrixMode.Projection);			
                GL.LoadMatrix(ref projection);			
        	GL.ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
               GL.ClearDepth(1);	           
              GL.Disable(EnableCap.DepthTest);	
              GL.Enable(EnableCap.Texture2D); 
              GL.Enable(EnableCap.Blend);
               GL.DepthFunc(DepthFunction.Always);		
		GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest); 
 
			//add idle event handler to process rendering whenever and as long as time is availble.
 
			GLib.Idle.Add(new GLib.IdleHandler(OnIdleProcessMain));
 
		//glcontextcreated = true;				
	}
samssonart's picture

Hi gooberking,
Thanks for your help, I think I'm getting closer, here's what I have:

using System;
using Gtk;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Audio;
using OpenTK.Audio.OpenAL;
using OpenTK.Input;
using OpenTK.Platform.Windows;
 
public partial class MainWindow : Gtk.Window
{
	public MainWindow () : base(Gtk.WindowType.Toplevel)
	{
		Build ();
	}
 
	protected virtual void GLWidgetInitialize (object sender, System.EventArgs e)
	{
		int width = 0, height = 0;	
		this.vbox3.GetSizeRequest(out width, out height);
		float aspectRatio = width/ height; 
		GL.Viewport(0, 0, width, height);
		GL.ClearColor(1.0f, 1.0f,1.0f,1.0f);
		GL.Clear(ClearBufferMask.ColorBufferBit);
		GL.MatrixMode(MatrixMode.Modelview);
		GL.LoadIdentity();
		GL.ShadeModel(ShadingModel.Smooth);			
		Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, aspectRatio, 1.0f, 64.0f);
		GL.MatrixMode(MatrixMode.Projection);			
        GL.LoadMatrix(ref projection);			
        GL.ClearDepth(1);	           
        GL.Disable(EnableCap.DepthTest);	
        GL.Enable(EnableCap.Texture2D); 
        GL.Enable(EnableCap.Blend);
        GL.DepthFunc(DepthFunction.Always);		
		GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest); 
		//add idle event handler to process rendering whenever and as long as time is availble.
		GLib.Idle.Add(new GLib.IdleHandler(OnIdleProcessMain));
 
	}
 
	protected void OnDeleteEvent (object sender, DeleteEventArgs a)
	{
		Application.Quit ();
		a.RetVal = true;
	}
 
 
	protected void RenderFrame(){
 
 
		Console.WriteLine("You rang?");
 
		GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
            Matrix4 modelview = Matrix4.LookAt(Vector3.Zero, Vector3.UnitZ, Vector3.UnitY);
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadMatrix(ref modelview);
 
            GL.Begin(BeginMode.Triangles);
 
            	GL.Color3(1.0f, 1.0f, 0.0f); GL.Vertex3(-1.0f, -1.0f, 4.0f);
            	GL.Color3(1.0f, 0.0f, 0.0f); GL.Vertex3(1.0f, -1.0f, 4.0f);
            	GL.Color3(0.2f, 0.9f, 1.0f); GL.Vertex3(0.0f, 1.0f, 4.0f);
	   GL.End();
 
            //SwapBuffers(); This i what I think I'm missing
 
	}
 
	protected bool OnIdleProcessMain ()
	{
 
		Console.WriteLine("Idling");
                RenderFrame();
		return true;
	}
 
}

I see both console outpust, form RenderFrame and from the idle event. But I still don't see my triangle. The reason why I think this is happening is because I'm not swapping buffers. The thing is, I don't know how. I had another look at OpenTK's Game.cs example and apparently GameWindow has it's own SwapBuffers() method, which is of no use to GLWidget. I took a dive and checked OpenTK's docs and apparently GraphicsContext has a SwapBuffers non-static method, so I tried creating a GraphicsContext instance, but I hit brck wall with the IWindowInfo parameter. I just didn't know how to use it. It appears to be an overridable constructor, but WinWindowInfo, which appears to be the one to use for windows, is private.

So, do you think you could shed some light on this matter. Also, if you already have a set up project I could look at, I would greatly apprecite it if you could share it.
Thanks.

gooberking's picture

Sorry I didn't see the post until now but I think you have two problems making it hard to see your triangle.
First problem is yes, you do need to swap buffers manually. Its super simple, one line

OpenTK.Graphics.GraphicsContext.CurrentContext.SwapBuffers();

The second thing that will cause you issues has to do with the stock render event that is hooked into the widget. It ONLY fires when when GTK calls for a redraw. This usually means while you are moving a slider or interacting with a GUI element. Since this is usually undesired you need to make your own render method using GTK's idle event handler. I described this earlier but it basically means if nothing is going on then its time to render.

This line will do just that, which I added into my OGL init code, or whatever other init code you feel it belongs in.

//add idle event handler to process rendering whenever there is free time
GLib.Idle.Add(new GLib.IdleHandler(OnIdleProcessMain));

You will then need to add a method that uses the name you just created -

bool OnIdleProcessMain()
{
 //draw code.
//swap buffers.
}

That method will end up looking something like this

bool OnIdleProcessMain()
	{	
	if(glcontextcreated == false)	 return false;  //make sure we don't draw before OGL init
 
   GL.Clear(ClearBufferMask.ColorBufferBit |    ClearBufferMask.DepthBufferBit);GL.MatrixMode(MatrixMode.Modelview);
			GL.LoadIdentity();
 
  //////some draw code here, like classic triangle
 
           OpenTK.Graphics.GraphicsContext.CurrentContext.SwapBuffers();		   		
 
		return true;
	}

I edited mine quite a bit since it wouldn't make sense but I hope it does well enough. See if that gets you going. Most of these questions I had myself and found answers for in old posts. Use the search on GLWidget and you might find other examples to help you.

samssonart's picture

Success! Now I see the triangle rendering correctly. I'm going to upload my example project once I do a few more tweaks, just for posterity's sake.
Thanks so much gooberking

gooberking's picture
samssonart wrote:

Success! Now I see the triangle rendering correctly. I'm going to upload my example project once I do a few more tweaks, just for posterity's sake.
Thanks so much gooberking

Excellent news. Good luck with whatever comes next.

samssonart's picture

Ok, so for posterity's sake, here's a link to a simple draw-a-triangle project using opentk, GLWidget and other GTK# tools. You may have to update the project references to point to your OpenTK.dll . Enjoy.

http://www.mediafire.com/?obvoxvt6ef13w5t

You may consider this issue as resolved.