Introduction
The Open Toolkit is an advanced, low-level C# library that wraps OpenGL, OpenCL and OpenAL. It is suitable for games, scientific applications and any other project that requires 3D graphics, audio or compute functionality. In short, its called OpenTK.
Background
It is not the fast C# implementation of OpenGL, but it is the best. There are some previous ones like csgl, taoframework, etc., but they are incomplete and bound by some limitation. And now, they are completely unable to keep with .NET Framework.
Every OpenGL function we can call by GL class like “glVertex2f(-2.0,-2.0)” of opengl used in OpenTk as “GL.Vertex2(-2.0,-2.0)”.
It has a very nice and flexible GUI options Cross-platform GLControl (Windows.Forms) which can easily add in Visual Studio toolbox, GLWidget which is another rich and useful component for (GTK#) and WPFControl classes. And there is also a native, high-performance GameWindow which is designed specifically for games. You can develop a game faster than you think.
It also has a very useful API collection like 3D math toolkit supplies Vector, Matrix, Quaternion and Bezier structs. Input API provides Keyboard, Mouse and Joystick interfaces. Display API for multiple monitors. OpenTK.Compatibility supports Tao framework applications.
And if you want to think about platform in dependency, it supports 32- and 64-bit versions of Windows, Linux and Mac OS X. No need for mismanaged libraries – compile once, run everywhere. and the gr8 thing is that you are free to use, modify and redistribute the source code. It is suitable for open- and closed-source projects alike.
Using the Code
You don’t need to have any prior knowledge in OpenGL or C# graphics to learn OpenTk. Only some basics of windows from design is more than enough.
For using opentk, you need to add two DLLs in your Visual Studio reference. They are OpenTK.dll and OpenTK.Graphics.OpenGL.dll. Both can be found easily here.
We are not going to use well known gamewindow for OpenTk, as I guess you are familiar with Windows Form design. We are just using a normal Windows Form. OpenTk provides a very nice control/tool. For that, you need to add it in your Visual Studio toolbox, it is called Glcontrol and you find it here. For that, first click toolbox and Choose item, then browse and then add the DLL for this control. Now you can use it like here.
To begin with, create a Form on which you will place your GLControl. Right click in some empty space of the Toolbox, pick “Choose Items…” and browse for OpenTK.GLControl.dll. Make sure you can find the “GLControl” listed in the “.NET Framework Components”, as in the image below.

Then you can add the GLControl to your form as any .NET control. A GLControl named glControl1 will be added to your Form.
So, first add this control and named “glControl1” in your port and write the below code. Also add this method in this control load event. For further details, you can go here.
private void glControl1_Resize(object sender, EventArgs e)
{ int w = glControl1.Width;
int h = glControl1.Height;
glControl1.MakeCurrent();
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.ClearColor(Color.SkyBlue);
GL.Ortho(-w / 2, w / 2, -h / 2, h / 2, -1, 1);
GL.Viewport(0, 0, w, h);
GL.End();
glControl1.SwapBuffers();
}
If we run it, we will find a from like below:

So how is it done? It's easy. First, we see:
glControl1.MakeCurrent();
It makes all the next GL commands enabled for this control.
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
We make that matrixmode in projection and then load the identity. There are four types of modes, for 2d projection is perfect, if you want to know more about these modes, you can see them here.
Now, the next command is very much important to understand. For that, first we need to be good OpenGL citizens and setup an orthographic projection matrix using GL.Ortho(). We need to call GL.Viewport() also.
GL.Ortho(-w / 2, w / 2, -h / 2, h / 2, -1, 1);
This makes center of the gl box 0,0 for axis x,y. because w is the width and h is the height of the gl box. If you want to make Bottom-left corner pixel as 0,0, you can write.
GL.Ortho(0, w, 0, h, -1, 1)
GL.Viewport(0, 0, w, h);
Viewport is used to select the painting area in the control.
GL.ClearColor(Color.SkyBlue);
and it makes it blue. For command disposal and window buffer, we have to write:
GL.End();
glControl1.SwapBuffers();
Now, at first, we have to draw a circle in our glcontrol. For draw method, we have to use paint method in paint event in glcontrol, like below:
private void glControl1_Paint(object sender, PaintEventArgs e)
{
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit)
drawclock();
glControl1.SwapBuffers();
}
void Draw_clock()
{
drawCircle(80); Draw_digit();
}
For drawcircle, I use the following code:
void drawCircle(float radius)
{
GL.Color3(Color.White);
GL.Begin(BeginMode.TriangleFan);
for (int i = 0; i < 360; i++)
{
double degInRad = i * 3.1416/180;
GL.Vertex2(Math.Cos(degInRad) * radius, Math.Sin(degInRad) * radius);
}
GL.End;
}

Now, it looks like it happens so easily.
GL.Begin(BeginMode.TriangleFan);
This mode draws a triangle and fills it with white color using provided vertexes point, all these triangles made the circle, like triangle pizza pieces makes the circle pizza
.
If you want to know GL.Begin, see here. You must remember to write GL.End(); after GL.Begin(); otherwise nothing will happen and the compiler can't give you an error for that.
Now we have to draw a digit and two lines for minute and hour.
Write simple code of normal vertex operation like that. Remember that the radius of the circle is 80.
void Draw_digit()
{
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.Color3(Color.Red);
GL.Begin(BeginMode.TriangleFan);
GL.Vertex2(0, +5);
GL.Vertex2(0, -5);
GL.Vertex2(70, 0);
GL.Vertex2(70, 0);
GL.Color3(Color.Red);
GL.End();
GL.Begin(BeginMode.TriangleFan);
GL.Vertex2(+5, 0);
GL.Vertex2(-5, 0);
GL.Vertex2(-65, 40);
GL.Vertex2(-65, 40);
GL.End();
GL.Color3(Color.Black);
GL.Begin(BeginMode.Lines);
GL.Vertex2(5, 60);
GL.Vertex2(5, 70);
GL.Vertex2(0, 60);
GL.Vertex2(0, 70);
GL.Vertex2(-5, 70);
GL.Vertex2(-15, 60);
GL.Vertex2(-15, 70);
GL.Vertex2(-5, 60);
GL.End();
GL.Color3(Color.Black);
GL.Begin(BeginMode.Lines);
GL.Vertex2(60,0);
GL.Vertex2(60,8);
GL.Vertex2(70,0);
GL.Vertex2(70,8);
GL.Vertex2(65, 0);
GL.Vertex2(65, 8);
GL.End();
GL.Color3(Color.Black);
GL.Begin(BeginMode.Lines);
GL.Vertex2(10, -60);
GL.Vertex2(10, -70);
GL.Vertex2(0, -60);
GL.Vertex2(0, -70);
GL.Vertex2(5, -60);
GL.Vertex2(0, -70);
GL.Vertex2(5, -60);
GL.Vertex2(0, -70);
GL.End();
GL.Color3(Color.Black);
GL.Begin(BeginMode.Lines);
GL.Vertex2(-75,-5);
GL.Vertex2(-75,-15);
GL.Vertex2( -70,-5);
GL.Vertex2(-60,-15);
GL.Vertex2(- 70,-15);
GL.Vertex2(-60,-5);
}
Here normal one vertex to another vertex connected code. For details, you can see openGL similar functions for that.
After drawing that, we see our output form is as shown below:
Now, we have to create a timer event for that, so first add a timer select interval at 1000 for 1s, enable it and add this event at timer tick:
;private void timer1_Tick(object sender, EventArgs e)
{
glControl2.MakeCurrent();
PaintEventArgs p = null;
glControl2_Paint(sender,p);
GL.End();}
Now the paint method will be called after one second. You have to draw line for second there, so paint event will be like:
private void glControl2_Paint(object sender, PaintEventArgs e)
{
glControl2.MakeCurrent();
GL.End();
glControl2.SwapBuffers();
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
Draw_clock();
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.End();
glControl2.SwapBuffers();
drawsecond();
glControl2.SwapBuffers();
}
Here for draw second, we need a static variable. For changing the coordinate of seconds line vertex position, we take:
static int i = 0;
Now drawsecond() function:
void drawsecond()
{
GL.Color3(Color.Red);
GL.Begin(BeginMode.Quads);
GL.Vertex2(5, 0);
GL.Vertex2(-5, 5);
double degInRad = i * 3.1416 / 180;
GL.Vertex2(Math.Cos(degInRad) * 80, Math.Sin(degInRad) * 80);
GL.Vertex2(Math.Cos(degInRad) * 85, Math.Sin(degInRad) * 85);
i = i - 6;
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.End();
}
Here static variable is subtracted for rotating in clockwise and subtracted by 6 because 360/6 equal to 60 which we need to round the circle.
So the seconds line is rotating now:

Points of Interest
So for C#, I am sure that you can't find anything better than OpenTK to replace OpenGL. But if you want to develop a really professional level game, I have to tell you that you are not in the right track. C++ is far better than C# for that. And if you directly want to do that in C#, use direct x or XNA.
History
- 23rd December, 2010: Initial post