Recycle Bin (move unwanted pages here)

This is the resting place for pages that are no longer necessary.

2.0 OpenGL Windows

OpenGL is basically a procedural language in an event-driven universe. The old plotter had instructions like move pen, pen down, draw line, and pen up. You would run a computation, draw a picture, then end the program. OpenGL is structured in much the same way, though it is vastly more powerful. A standard instruction might be to draw a colored triangle in proper 3d perspective with some lighting on it. Since OpenGL has this simple structure it is widely portable.

The problem with OpenGL is the implementation details which are generally lumped into the question "How do I create an OpenGL window?" The details include creating a graphics context, handling OS level events like window resizing and resolution and aspect ratio adjustments to the monitors, and providing some sort of clock events for animations. It is the job of OpenTK to hide the dirty implementation details so that any code you write will work the same on all flavors of OS X, Windows and Linux. [As an example of just how difficult this is, the current OpenGL SuperBible 4th edition devotes 4 out of 22 chapters to setting up OpenGL on various platforms.]

Here are the types of OpenGL windows (or graphics contexts) that I would like to be able to create.

  1. A full screen area in which graphics instructions are sent directly to the graphics card for maximum speed.
  2. A rectangular black window (with no frame, title bar, or menus) somewhere on the screen. Using this I could cover the screen with a set of graphics windows all doing different things. Of course I would like to get some rendering speed benefit for the user interface concessions.
  3. A graphics window with standard frame allowing menus, resizing, minimization and so on. The client area would generate OpenGL graphics according to user instructions, for example, like Photoshop.
  4. An OpenGL graphics context inside any Windows control. For example, different OpenGL graphics sequences simultaneously animating on multiple buttons. This is not so exotic and it is likely that OpenTK can already do this beyond your wildest dreams.

I found two basic ways to make windows using OpenTK.

First, you can utilize the Windows Forms libraries to create a window, then insert a graphics context in that window using GLControl. You should also be able to insert the GLControl into basically any control in Windows Forms. This approach is most promising for cases 3 and 4 above.

Second, you can create a window with none of the overhead of Windows Forms (or any other GUI) using GameWindow. GameWindow essentially uses the native window capability of the operating system which is encapsulated in its parent class NativeWindow. To this is added a graphics context using the GraphicsContext class which makes OpenGL calls possible. The GameWindow is quite elaborate and may be more powerful than what you need, but it appears to be simple to use. Using a GameWindow is the best approach to cases 1 and 2 above.

Code for these window types follows.

2.1 Full Screen OpenGL Window

Here is the code for a full screen OpenGL window. It uses the powerful GameWindow class. I think the most significant feature is that it does not use Windows Forms. This means you do not need to include the Windows.Forms assembly. It also means that you are responsible for creating everything that appears inside the window using OpenGL.

using System;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
 
class Program
{
 
  static void Main(string[] args)
  {
    MyWindow N = new MyWindow();
    N.Run(100.0);
    N.Dispose();
  }
 
}
 
// This class is a powerful window that can be created without using any GUI library.
public class MyWindow : GameWindow
{
  public MyWindow()
    : base()
  {
    Console.WriteLine("Press any key to exit.");
    KeyPress += HandleKeyPressEvent;
    Load += HandleOnLoadEvent;
    RenderFrame += HandleRenderEvent;
  }
 
  public void HandleKeyPressEvent(object sender, KeyPressEventArgs e)
  {
    Exit();
  }
 
  public void HandleOnLoadEvent(object sender, EventArgs e)
  {
    WindowBorder = WindowBorder.Hidden;
    WindowState = WindowState.Fullscreen;
    GL.Clear(ClearBufferMask.DepthBufferBit | 
                     ClearBufferMask.ColorBufferBit | 
                     ClearBufferMask.AccumBufferBit | 
                     ClearBufferMask.StencilBufferBit);
  }
 
  public void HandleRenderEvent(object sender, FrameEventArgs e)
  {
    GL.ClearColor(new Color4(1, 0, 0, 1));
    SwapBuffers();
  }
 
}

Since I am coding my projects as console applications in Visual Studio, I had to explicitly include the System.Drawing assembly to get this to compile. It is needed to support the Color4 class (see C:\opentk-0.9.9-3\Source\OpenTK\Graphics\Color4.cs). [see Comment below on this issue]

The main program creates a GameWindow, starts the rendering loop, then finally disposes of any system-dependent (non-managed) baggage before closing.

I used the NativeWindow properties to get rid of the window border and make the window full screen. You'll find the WindowBorder and WindowState classes in C:\opentk-0.9.9-3\Source\OpenTK.

A lot of this code depends on event handling which is a basic, but difficult, feature of C#. You can find out about the available events by looking in C:\opentk-0.9.9-3\Source\OpenTK\GameWindow.cs (Load and RenderFrame) and C:\opentk-0.9.9-3\Source\OpenTK\NativeWindow.cs (KeyPress). Particular attention should be paid to the UpdateFrame event which I didn't need for this example.

The SwapBuffers call is necessary because double buffering is built into the GameWindow class. (BTW, that's a good thing.)

When I ran this on Windows Xp SP3 it worked mostly OK. I am slightly concerned that the background color of the window is black, not red. Another minor issue was the cursor which seemed to want to remain as an hourglass, not an arrow. I am quite happy that the Winkey is ignored.

Cubo Perspectiva

using System;
using System.Drawing;
 
using OpenTK;
using OpenTK.Input;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
 
using Tao.FreeGlut;
using System.Threading;
 
public class OpenTK_cubo:GameWindow
{	
	const float rotation = 180.0f;
	float angle;
 
	public OpenTK_cubo(): base(500, 500)
	{
		Keyboard.KeyDown += teclado;
	}
 
	public void teclado(object lanzador, KeyboardKeyEventArgs e)
	{
		if(e.Key == Key.Escape)
		{
			base.Exit();
		}
		if(e.Key == Key.F)
		{
			if(this.WindowState == OpenTK.WindowState.Normal)
			{
				this.WindowState = OpenTK.WindowState.Fullscreen;
			}
			else
			{
				this.WindowState = OpenTK.WindowState.Normal;
			}
		}
	}
 
	protected override void OnLoad (EventArgs e)
	{
		base.OnLoad (e);
		GL.ClearColor(Color.CornflowerBlue);
		GL.Enable(EnableCap.DepthTest);
	}
 
	protected override void OnRenderFrame (FrameEventArgs e)
	{
		base.OnRenderFrame (e);
		GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
		Matrix4 lookAt =  Matrix4.LookAt(0,5,5,0,0,0,0,1,0);
		GL.MatrixMode(MatrixMode.Modelview);
		GL.LoadMatrix(ref lookAt);
 
		angle += rotation * (float)e.Time;
		GL.Rotate(angle, 0.0f, 1.0f, 0.0f);
 
		DrawCube();
 
		base.SwapBuffers();
		Thread.Sleep(1);
	}
	protected override void OnResize (EventArgs e)
	{
		base.OnResize (e);
		double aspec_ratio = Width / (double)Height;
		GL.Viewport(0, 0, Width, Height);
		OpenTK.Matrix4 perspective = OpenTK.Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, (float) aspec_ratio, 1, 64);
		GL.MatrixMode(MatrixMode.Projection);
		GL.LoadMatrix(ref perspective);
	}
 
	private void DrawCube()
        {
            GL.Begin(BeginMode.Quads);
 
            GL.Color3(Color.Blue);
            GL.Vertex3(-1.0f, -1.0f, -1.0f);
            GL.Vertex3(-1.0f, 1.0f, -1.0f);
            GL.Vertex3(1.0f, 1.0f, -1.0f);
            GL.Vertex3(1.0f, -1.0f, -1.0f);
 
            GL.Color3(Color.Green);
            GL.Vertex3(-1.0f, -1.0f, -1.0f);
            GL.Vertex3(1.0f, -1.0f, -1.0f);
            GL.Vertex3(1.0f, -1.0f, 1.0f);
            GL.Vertex3(-1.0f, -1.0f, 1.0f);
 
            GL.Color3(Color.Red);
 
            GL.Vertex3(-1.0f, -1.0f, -1.0f);
            GL.Vertex3(-1.0f, -1.0f, 1.0f);
            GL.Vertex3(-1.0f, 1.0f, 1.0f);
            GL.Vertex3(-1.0f, 1.0f, -1.0f);
 
            GL.Color3(Color.Purple);
            GL.Vertex3(-1.0f, -1.0f, 1.0f);
            GL.Vertex3(1.0f, -1.0f, 1.0f);
            GL.Vertex3(1.0f, 1.0f, 1.0f);
            GL.Vertex3(-1.0f, 1.0f, 1.0f);
 
            GL.Color3(Color.Violet);
            GL.Vertex3(-1.0f, 1.0f, -1.0f);
            GL.Vertex3(-1.0f, 1.0f, 1.0f);
            GL.Vertex3(1.0f, 1.0f, 1.0f);
            GL.Vertex3(1.0f, 1.0f, -1.0f);
 
            GL.Color3(Color.ForestGreen);
            GL.Vertex3(1.0f, -1.0f, -1.0f);
            GL.Vertex3(1.0f, 1.0f, -1.0f);
            GL.Vertex3(1.0f, 1.0f, 1.0f);
            GL.Vertex3(1.0f, -1.0f, 1.0f);
 
            GL.End();
        }
}
 
class MainClass
{
	public static void Main (string[] args)
	{
		OpenTK_cubo ventana = new OpenTK_cubo();
		ventana.Title = String.Format("OpenTK Cubo");
		ventana.Run();
	}
}

Full Screen OpenGL Window

Here is the code for a full screen OpenGL window. It uses the powerful GameWindow class. I think the most significant feature is that it does not use Windows Forms. This means you do not need to include the Windows.Forms assembly. It also means that you are responsible for creating everything that appears inside the window using OpenGL.

using System;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
 
class Program
{
 
  static void Main(string[] args)
  {
    MyWindow N = new MyWindow();
    N.Run(100.0);
    N.Dispose();
  }
 
}
 
// This class is a powerful window that can be created without using any GUI library.
public class MyWindow : GameWindow
{
  public MyWindow()
    : base()
  {
    Console.WriteLine("Press any key to exit.");
    KeyPress += HandleKeyPressEvent;
    Load += HandleOnLoadEvent;
    RenderFrame += HandleRenderEvent;
  }
 
  public void HandleKeyPressEvent(object sender, KeyPressEventArgs e)
  {
    Exit();
  }
 
  public void HandleOnLoadEvent(object sender, EventArgs e)
  {
    WindowBorder = WindowBorder.Hidden;
    WindowState = WindowState.Fullscreen;
    GL.Clear(ClearBufferMask.DepthBufferBit | 
                     ClearBufferMask.ColorBufferBit | 
                     ClearBufferMask.AccumBufferBit | 
                     ClearBufferMask.StencilBufferBit);
  }
 
  public void HandleRenderEvent(object sender, FrameEventArgs e)
  {
    GL.ClearColor(new Color4(1, 0, 0, 1));
    SwapBuffers();
  }
 
}

Since I am coding my projects as console applications in Visual Studio, I had to explicitly include the System.Drawing assembly to get this to compile. It is needed to support the Color4 class (see C:\opentk-0.9.9-3\Source\OpenTK\Graphics\Color4.cs). [see Comment below on this issue]

The main program creates a GameWindow, starts the rendering loop, then finally disposes of any system-dependent (non-managed) baggage before closing.

I used the NativeWindow properties to get rid of the window border and make the window full screen. You'll find the WindowBorder and WindowState classes in C:\opentk-0.9.9-3\Source\OpenTK.

A lot of this code depends on event handling which is a basic, but difficult, feature of C#. You can find out about the available events by looking in C:\opentk-0.9.9-3\Source\OpenTK\GameWindow.cs (Load and RenderFrame) and C:\opentk-0.9.9-3\Source\OpenTK\NativeWindow.cs (KeyPress). Particular attention should be paid to the UpdateFrame event which I didn't need for this example.

The SwapBuffers call is necessary because double buffering is built into the GameWindow class. (BTW, that's a good thing.)

When I ran this on Windows Xp SP3 it worked mostly OK. I am slightly concerned that the background color of the window is black, not red. Another minor issue was the cursor which seemed to want to remain as an hourglass, not an arrow. I am quite happy that the Winkey is ignored.