objarni's picture

My little using()-trick to ease the burden on the programmer..

My GL-drawing code got completely scrambled today because I forgot to put an GL.End() after my GL.Vertex2f-code.

So, I thought, can't I do something to relieve me of the burden of matching GL.Begin-End pairs all the time..?

This is what I came up with, thought I'd share it for anyone else to use in case you also forget those evil GL.End()-lines every now and then!

Update: After Kamujins complaint about allocating objects every frame, I changed the class to this which allocates only one object per application run:

     class GLDraw : IDisposable
    {
      private GLDraw() { }
      private static GLDraw drawer = new GLDraw();
      public static GLDraw Begin(BeginMode mode)
      {
        GL.Begin(mode);
        return drawer;
      }
      public void Dispose()
      {
        GL.End();
      }
    }
 
    ....
    using (GLDraw.Begin(BeginMode.Quads))
    {
      GL.Vertex2(0, 0);
      GL.Vertex2(size, 0);
      GL.Vertex2(size, size);
      GL.Vertex2(0, size);
    }

Happy coding,


Comments

Comment viewing options

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

Interesting idea with the using statement, just for completeness this should be mentioned as an option aswell:

GL.Begin(BeginMode.Quads))
    {
      GL.Vertex2(0, 0);
      GL.Vertex2(size, 0);
      GL.Vertex2(size, size);
      GL.Vertex2(0, size);
    }
GL.End();

Note the curly braces.

the Fiddler's picture

True :)

But the using trick does make sense if you want to maintain some basic guarantees when exceptions can be thrown (not likely in this example, but think of buffer mapping/unmapping).

himek's picture

Hi, I've came about the same idea about a month ago. I did it with structs and generics to avoid boxing...
It's pretty convenient to bind textures and shaders. BTW, is there a way to push/pop shaders?

public abstract class AbstractTexture : Resource, IBindableExplicitUse {
	...
 
	public void Bind() {
		GL.PushAttrib(AttribMask.TextureBit);
		GL.BindTexture(TextureTarget.Texture2D, handle);
	}
 
	public void Unbind() {
		GL.PopAttrib();
	}
 
	public Binder Use() {
		return new Binder(this);
	}
}
...
Mesh mesh = new Mesh("../../mesh.trianglestrip");
Texture2D brush = new Texture2D("../../brush.png");
Texture2D depth = new Texture2D(brush.Width, brush.Height, PixelInternalFormat.DepthComponent24);
Texture2D temp = new Texture2D(256,256);
brush.WrapS = TextureWrapMode.ClampToBorder;
brush.WrapT = TextureWrapMode.ClampToBorder;
...
using (brush.Use()) {
	GL.Viewport(0,0,temp.Width,temp.Height);
	mesh.Draw();
	using (temp.Use()) {
		GL.CopyTexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb8,
			0, 0, temp.Width, temp.Height, 0);
	}
}

I'm attaching my version. Warning: ugly hacks!

ps. OpenTK rules!

AttachmentSize
IBindable.cs3.2 KB
the Fiddler's picture

This is a very Interesting approach, especially the IBindable and implicit / explicit use interfaces. Thanks for sharing!

One snag is that structs are autoboxed when cast to an interface (IDisposable in this case), which means they approach does generate garbage. This may or may not have an effect in real use, but it's something to be aware of.

Have you considered using an object pool of Binders instead? If you are especially worried about GC performance, this could completely eliminate allocations.

himek's picture

For structs there's the IBindableExplicitUse interface. It does not make any heap allocations. For instance you can do semething like this:

	public struct Matrix4 : IBindableExplicitUse<Matrix> {
		public Binder<Matrix> Use() {
			return new Binder<Matrix>();
		}
 
		public void Bind() {
			GL.PushMatrix();
			GL.MultMatrix(this);
		}
 
 
		public void Unbind() {
			GL.PopMatrix();
		}
 
	}

For static state usage like glBegin/glEnd and glPush/glPos the above GLDraw class pattern is probably most optimal, but the IBindable pattern has an advantage because the Binder struct can contain the state object to be cleaned up and/or the old one to be restored.

Now I'm going to sleep... ^c^ ...work... *c*

the Fiddler's picture

I just re-read your code and the generic Binder struct manages to avoid the cast-to-interface entirely. That's some awesome work, kudos!

Please ignore my previous post, I understood your code wrongly.

Hangar's picture

The IBinder interface is a really good idea. I've used the using pattern for a long time, but never thought of combining it with extension methods.

I think I found an improvement: instead of the the explicit versions, you can just use a generic extension method and do it implicitly.

public interface IBindable
{
	void Bind();
	void Unbind();
}
 
public static class BindableImplicitUseExtensions
{
	public static Binder<T> Use<T>(this T bindable)
		where T : IBindable
	{
		return new Binder<T>(bindable);
	}
}
 
public struct Binder<T> : IDisposable where T : IBindable
{
	private readonly T _bindable;
 
	public Binder(T bindable)
	{
		_bindable = bindable;
		bindable.Bind();
	}
 
	public void Dispose()
	{
		_bindable.Unbind();
	}
}
himek's picture

I didn't know it was possible, thanks, works like a charm :)
If you want to "use" matrices without modifying OpenTK's code...

using System;
using OpenTK.Graphics;
using OpenTK.Math;
 
public static class Matrix4ImplicitUseExtensions
{
	public class MatrixPopper : IDisposable
	{
		public void Dispose()
		{
			GL.PopMatrix();
		}
	}
 
	private static readonly MatrixPopper popper = new MatrixPopper();
 
	public static MatrixPopper Push(this Matrix4 matrix)
	{
		GL.PushMatrix();
		GL.LoadMatrix(ref matrix);
		return popper;
	}
 
	public static MatrixPopper PushMult(this Matrix4 matrix)
	{
		GL.PushMatrix();
		GL.MultMatrix(ref matrix);
		return popper;
	}
}

usage:

Matrix4 m;
...
using (Matrix4.Identity.Push()) {
	...
}
 
using (m.PushMult()) {
	...
}