Tuesday, January 24, 2017

OpenGL 4 with OpenTK in C# Part 1: Initialize the GameWindow


I've had this dream of building my own game ever since I first started coding. Most attempts have been very basic in command line, various 2D libraries, silverlight etc..
So now that I am on a sick-leave for 2 weeks, I bought a book called OpenGL SuperBible, Seventh Edition and I try to read it at a pace that suites me. Currently pretty slow as I really don't have that much energy and feel more like napping than reading or writing :)


The thing is that all the examples in the book are in C++ and I don't really want to do this in C++ as I have a lot of utility code written in C# that I want to be able to reuse. So after looking around I found this neat wrapper called OpenTK that basically wraps the OpenGL API as is and lets you use it from C#.
So, while trying to figure out OpenGL I will try to write down how to do things in OpenTK. Hopefully this process forces me to learn at least a little. : )

This is part 1 of my series on OpenGL4 with OpenTK.
For other posts in this series:
OpenGL 4 with OpenTK in C# Part 1: Initialize the GameWindow
OpenGL 4 with OpenTK in C# Part 2: Compiling shaders and linking them
OpenGL 4 with OpenTK in C# Part 3: Passing data to shaders
OpenGL 4 with OpenTK in C# Part 4: Refactoring and adding error handling
OpenGL 4 with OpenTK in C# Part 5: Buffers and Triangle
OpenGL 4 with OpenTK in C# Part 6: Rotations and Movement of objects
OpenGL 4 with OpenTK in C# Part 7: Vectors and Matrices
OpenGL 4 with OpenTK in C# Part 8: Drawing multiple objects
OpenGL 4 with OpenTK in C# Part 9: Texturing
OpenGL 4 with OpenTK in C# Part 10: Asteroid Invaders
Basic bullet movement patterns in Asteroid Invaders
OpenGL 4 with OpenTK in C# Part 11: Mipmap
OpenGL 4 with OpenTK in C# Part 12: Basic Moveable Camera
OpenGL 4 with OpenTK in C# Part 13: IcoSphere
OpenGL 4 with OpenTK in C# Part 14: Basic Text
OpenGL 4 with OpenTK in C# Part 15: Object picking by mouse

Get a working game window

So step 1 I guess is to get a working game window that we can extend upon.

I assume you know how to create a new Solution and find the new Project menu in Visual Studio :)

Update November 2017
If you do not have Visual Studio installed, you can get the Community Edition (that is free) directly from Microsoft over here. There is no real reason for you to not start coding games anymore!

In Visual Studio, create a new Windows Forms project, I guess you could go console as well but this is what I did.

Be sure to change your build options to x64 if you downloaded the x64 version of OpenTK.
Add OpenTK.dll as a reference.

Delete the Form1 class in the Solution Explorer.

Add a new class called MainWindow. (I placed it in a Components folder)
using OpenTK;
using OpenTK.Graphics.OpenGL4;
namespace techdump.opengl.Components
{
    public sealed class MainWindow : GameWindow
    {
    }
}

Adding the 'using OpenTK.Graphics.OpenGL4;' statement tells OpenTK that we want to use OpenGL 4 and not see all the old APIs. Just gives us a cleaner environment.

Open Program.cs and remove all content of the Main method and write this instead
static class Program
{
    [STAThread]
    static void Main()
    {
        new MainWindow().Run(60);
    }
}

The Run(60) tells OpenTK that you want to run at 60 fps.
If you run the application at this point a window should appear that looks like this:


Setup overrides

OpenTK provides some nice methods that can be used by overriding them in your MainWindow.

Adding a constructor and setting up your window
public MainWindow()
    : base(1280, // initial width
        720, // initial height
        GraphicsMode.Default,
        "dreamstatecoding",  // initial title
        GameWindowFlags.Default,
        DisplayDevice.Default,
        4, // OpenGL major version
        0, // OpenGL minor version
        GraphicsContextFlags.ForwardCompatible)
{
    Title += ": OpenGL Version: " + GL.GetString(StringName.Version);
}

So basically what this does is to setup the initial state of our window. Again we tell OpenTK that we want to use OpenGL 4. For sanitys sake we then overwrite the window Title with the actual OpenGL version used in the body of the constructor.

Overriding the OnResize method to be able to reset our ViewPort if the user decides to resize the window
protected override void OnResize(EventArgs e)
{
 GL.Viewport(0, 0, Width, Height);
}
OpenTK wraps the OpenGL API in the GL static class. so the above GL.Viewport corresponds to glViewport. So basically you can read the OpenGL API documentation and figure out what OpenTK method name is.

Next up the OnLoad method. This gets executed once when our window loads. Perfect for initializing stuff.
protected override void OnLoad(EventArgs e)
{
 CursorVisible = true;
}

The OnUpdateFrame method is where all updates should be placed. This is called every frame.
protected override void OnUpdateFrame(FrameEventArgs e)
{
 HandleKeyboard();
}
private void HandleKeyboard()
{
 var keyState = Keyboard.GetState();

 if (keyState.IsKeyDown(Key.Escape))
 {
  Exit();
 }
}
I threw in a HandleKeyboard method here as well so that we can kill the window easily by hitting the Escape key.

The last override is the OnRenderFrame. This is where all the drawing will happen. Also called for every frame. the FrameEventArgs contains a Time property telling us how many seconds elapsed since the last frame.
protected override void OnRenderFrame(FrameEventArgs e)
{
    Title = $"(Vsync: {VSync}) FPS: {1f / e.Time:0}";

    Color4 backColor;
    backColor.A = 1.0f;
    backColor.R = 0.1f;
    backColor.G = 0.1f;
    backColor.B = 0.3f;
    GL.ClearColor(backColor);
    GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

    SwapBuffers();
}

The GL.ClearColor takes a Color4 struct. There are a lot of color predefined in the Color4 struct for example: Color4.AliceBlue
Running this should show a dark blue window and an fps counter in the title stuck around 60fps as seen at the top of this post.

Hope this helps someone out there :)
Thanks for reading. Here's a video of 2 of our cats fighting.

All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment or share a link on social media, not required but appreciated! :)

23 comments:

  1. Finally, a real OpenGL 4 tutorial for OpenTK, without any outdated functions and example code in a repository. Thank you so much!

    ReplyDelete
    Replies
    1. Hi there, thanks for commenting and I'm glad you found this useful :)

      Delete
  2. It is a great pleasure for me to find this tutorial,Thank you! I try use OpenTK create a 3d surface(7*7 datatable)!

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. Holy cow. I had no idea OpenTK even supported OpenGL 4. Thank you so much!

    ReplyDelete
    Replies
    1. Thanks for commenting! OpenTK is pretty neat!

      Delete
  5. One of the worst tutorials i ever seeing: do this, do that, all rightyyyyyyy. WHAT?? For example, where i should add SETUP OVERRIDES code part? to Form1.cs or to Program.cs, or if i dont want to use constructor is any way to create object and manually set properties what i want? =.=

    ReplyDelete
    Replies
    1. Sorry to hear that you dislike this tutorial. I've just written down my progress while trying to learn openGL with openTK.
      In part 5 there is a link to a GitHub repository with working samples. There are numerous ways to write code and there is always room for improvement. In later parts there will be some refactoring of the code, maybe it is more to your liking. Take what works for you and rewrite the rest.
      Anyhow, good luck with your journey to openGL :)

      Delete
  6. As a total newbee I would like to write here some things I struggled ;)

    1. namespace techdump.opengl.Components dont allow me to use MainWindow constr. in Program.cs, I had to change that for namespace as in the Program.cs.
    2. At MainWindow.cs "using OpenTK.Graphics;" was added, as GraphicsMode and GraphicsContextFlags corresponds to it.
    3. Using override over OnResize and using EventArgs type needs "using System;" in MainWindow.cs
    4. Handle keyboard part needs "using OpenTK.Input;"

    Nice tutorial anyway, thanks for sharing ;)

    ReplyDelete
    Replies
    1. Hi there! Thanks for taking the time to help out. I tend to leave out the usings a bit too often when I copy code to the blog! :)

      Delete
  7. Bless your soul. Probably the best modern OpenTK tutorial out there. Super easy to follow, tons of content, and plenty of examples to get you going. Thank you so much for your work.

    ReplyDelete
    Replies
    1. Oh and the cat video was just great haha

      Delete
  8. Thank you, very useful lesson.

    ReplyDelete
    Replies
    1. Hi there, thanks for taking the time to comment. I'm glad you found this tutorial useful!

      Delete
  9. This is the tutorial that I was looking for. I am learning MonoGame too, but as programmer, I would like to know more about game development in depth. Your tutorial is very good, just some observations:

    ReplyDelete
    Replies
    1. Your observations didn't make it into the posted comment.. Any chance that you could try post them again, always interested in ways to improve these tutorials!

      Delete
    2. Nevermind, just when create new code or modify some file, please, refer to that file because sometimes we need to guess which file is that is modified.

      Delete
  10. Absolutely great! Finally a clear introduction on getting an OpenGL project up and running. Some small issues:
    (1) I had to add a "using OpenTK.Graphics;" to access GraphicsMode and DisplayDevice
    (2) got a Keyboard is deprecated warning. Instead used: var keyState = OpenTK.Input.Keyboard.GetState();

    ReplyDelete
  11. Hey :) Really nice Tutorial, this helped me a lot. Do you think you coul update some of the parts to OpenTK 4?

    ReplyDelete