Monday, January 30, 2017

OpenGL 4 with OpenTK in C# Part 4: Refactoring and adding error handling


In this post we will look at cleaning up the game window code a little and introduce Shader compile error logging as well as Program linking error logging.

This is part 4 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

As stated in the previous post, I am in no way an expert in OpenGL. I write these posts as a way to learn and if someone else finds these posts useful then all the better :)
The code in this post is from me trying to figure out why my shaders do no work.
This part will build upon the game window and shaders from the previous post.

Refactoring the code

So lets clean up the code a little. First off lets break out each shader compile to a separate method from our CompileShaders method.

private int CompileShader(ShaderType type, string path)
{
    var shader = GL.CreateShader(type);
    var src = File.ReadAllText(path);
    GL.ShaderSource(shader, src);
    GL.CompileShader(shader);
    return shader;
}
This leaves us with the following CreateProgram method, previously known as CompileShaders. Here we store the shaders in a list that we can iterate over instead of duplicating the code for each shader
private int CreateProgram()
{
    var program = GL.CreateProgram();
    var shaders = new List<int>();
    shaders.Add(CompileShader(ShaderType.VertexShader, @"Components\Shaders\1Vert\vertexShaderTriangle.c"));
    shaders.Add(CompileShader(ShaderType.FragmentShader, @"Components\Shaders\5Frag\fragmentShader.c"));
            
    foreach(var shader in shaders)
        GL.AttachShader(program, shader);
    GL.LinkProgram(program);
    foreach (var shader in shaders)
    {
        GL.DetachShader(program, shader);
        GL.DeleteShader(shader);
    }
    return program;
}

Adding shader compile output and program linking output

Edit 2017-02-05: Evidently some drivers write info log even when things are OK. So removed the try catch and changed to debug logging instead of throwing exceptions.

Next step is to add some kind of feedback from OpenGL when we try to compile a shader or link a program that has errors in it.
First off the in the CompileShader method. Here we check with OpenGL if there was anything written to the info log during the compilation of this specific shader with the help of the GL.GetShaderInfoLog. If anything was written, we write it to Debug log.
private int CompileShader(ShaderType type, string path)
{
    var shader = GL.CreateShader(type);
    var src = File.ReadAllText(path);
    GL.ShaderSource(shader, src);
    GL.CompileShader(shader);
    var info = GL.GetShaderInfoLog(shader);
    if (!string.IsNullOrWhiteSpace(info))
        Debug.WriteLine($"GL.CompileShader [{type}] had info log: {info}");
    return shader;
}

In the CreateProgram method we also add a check to see if there was anything written to the info log regarding this specific program with the help of the GL.GetProgramInfoLog method. And same as above, if anything was we write it to Debug log.

private int CreateProgram()
{
    var program = GL.CreateProgram();
    var shaders = new List<int>();
    shaders.Add(CompileShader(ShaderType.VertexShader, @"Components\Shaders\1Vert\simplePipeVert.c"));
    shaders.Add(CompileShader(ShaderType.FragmentShader, @"Components\Shaders\5Frag\simplePipeFrag.c"));

    foreach (var shader in shaders)
        GL.AttachShader(program, shader);
    GL.LinkProgram(program);
    var info = GL.GetProgramInfoLog(program);
    if (!string.IsNullOrWhiteSpace(info))
        Debug.WriteLine($"GL.LinkProgram had info log: {info}");

    foreach (var shader in shaders)
    {
        GL.DetachShader(program, shader);
        GL.DeleteShader(shader);
    }
    return program;
}


Example output in our visual studio debug output view

I've started to compile a list of stuff that I've encountered and how I solved those issues.

For the full source at the end of part 4, go to: https://github.com/eowind/dreamstatecoding

Hope this helps someone out there :)
Thanks for reading. Here's another GIF of 2 of our cats fighting to lighten up your day.

Until next time: Work to Live, Don’t Live to Work

Saturday, January 28, 2017

OpenGL various errors with shaders


This is my dump of easy fixes for problems that pop up from time to time. As I am quite the novice with both OpenGL and shaders, they do stop my progress quite so often. So hopefully this will help someone else who is googling for the solutions. :)
I guess that this list will grow over time.

For more on OpenGL, look up my tutorial series starting with:
OpenGL 4 with OpenTK in C# Part 1: Initialize the GameWindow

error C7565

0(18) : error C7565: assignment to varying 'tes_out'
Check that tes_out actually is declared as out. Copying from previous shader one might forget to change it to in in the next.

error C1035

0(18) : error C1035: assignment of incompatible types
Example of faulty code.
in TCS_OUT
{
   vec4 color;
} tes_in[];
out TES_OUT
{
   vec4 color;
} tes_out;
void main(void)
{
   /* threw error */
   tes_out = tes_in[0];
   /* fixed, uncomment */
   /* tes_out.color = tes_in[0].color; */
}

Other errors could be assignment of a vec3 to a vec4.

error C3008

0(4) : error C3008: unknown layout specifier 'max_vertices = 3'
0(4) : error C3008: unknown layout specifier 'points'
I had loaded an geometry shader, but told OpenGL that it was an Tesselation Evaluation Shader, so changing the type to the correct one solved it.

error C3004

0(22) : error C3004: function "void EmitVertex();" not supported in this profile
I had loaded an geometry shader, but told OpenGL that it was an Tesselation Evaluation Shader, so changing the type to the correct one solved it.

error C1048

0(14) : error C1048: invalid character 'Y' in swizzle "Y"
This one was tricky, turned out that all vecX are referenced by lower case letters. Error message was from when trying to reference with upper case. Or any other non-existent letter
vec4 color;
color.A // this is wrong
color.a // this is right



Program linking warning

warning:  two vertex attribute variables (named position and color) were assigned to the same generic vertex attribute
Just as described, had set the location of two attributes to the same (0), solved by assigning correct location i.e. 0 and 1 in this case.
layout (location = 0) in vec4 position;
layout(location = 0) in vec4 color;

Addition of Tessellation Control Shader and Tessellation Evaluation Shader results in black screen

Works fine when running only Vertex Shader and Fragment Shader, but when adding Tesselation, it just stops working. Took me 3 hours of trying to understand what I missed in the examples until I found that if you use Tesselation, you need to change from Triangles to Patches. 
GL.DrawArrays(PrimitiveType.Patches, 0, 3);

OpenTK GL.CompileShader System.AccessViolationException was unhandled


Tried to add another shader (Tesselation Control Shader this time) to my program and received the following exception when compiling it with GL.CompileShader
System.AccessViolationException was unhandled
  HResult=-2147467261
  Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
  Source=OpenTK
  StackTrace:
       at OpenTK.Graphics.OpenGL4.GL.CompileShader(Int32 shader)
       at techdump.opengl.Components.MainWindow.CompileShaders() in C:\tfs\techdump\techdump\techdump.opengl\Components\MainWindow.cs:line 58
       at techdump.opengl.Components.MainWindow.OnLoad(EventArgs e) in C:\tfs\techdump\techdump\techdump.opengl\Components\MainWindow.cs:line 38
       at OpenTK.GameWindow.Run(Double updates_per_second, Double frames_per_second)
       at techdump.opengl.Program.Main() in C:\tfs\techdump\techdump\techdump.opengl\Program.cs:line 11
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

So what went wrong? Looking at the variables in the debug I see that the shader was loaded correctly from the file, GL.ShaderSource did not complain.
Been trying to read up on this for the last hour but no luck.

Last resort. As I am on a laptop and have both an Intel(R) HD Graphics 530 chip and a NVIDIA GeForce GTX 960M, I try to switch and start with the NVidia instead. And it works.

To try this, open up your build folder in windows explorer, right click and select, run with graphics processor and then select your NVidia card.
Turns out that NVidia tries to save energy and starting things with the Intel chip if its not a game. Good for battery life, less so for games development :)
This also turns out to solve the issue with version compatibility from a previous post where the work around was to use an older version of OpenGL.

So how to setup so that your visual studio runs with the correct GPU as default?

This seems to be harder than I imagined. But thanksfully there is a solution to this over at drivenbynostalgia.com. Basically they provide a class that you add to your application that registers it with your NVidia drivers and states that it is a game. So go to their site and find the 'sop - setoptimusprofile' section.


Also to note, the SOP solution is x86 only. I got the following exception when trying to run it in 64-bit mode.

System.TypeLoadException was unhandled
  HResult=-2146233054
  Message=Could not load type 'Setting' from assembly 'techdump.opengl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset 4 that is incorrectly aligned or overlapped by a non-object field.
  Source=techdump.opengl
  TypeName=Setting
  StackTrace:
       at techdump.opengl.Components.SOP.SOP_SetProfile(String profileName, String applicationName)
       at techdump.opengl.Program.HandleSop() in C:\tfs\techdump\techdump\techdump.opengl\Program.cs:line 21
       at techdump.opengl.Program.Main() in C:\tfs\techdump\techdump\techdump.opengl\Program.cs:line 12
  InnerException: 

So no x64. So I had to go back to 32 bits. I guess I can live with that :)

Update 2017-01-28
Seems that if you do not close the program correctly X times, the above exception starts throwing again. Trying to start it with Intel chip this time works. After a reboot the NVidia chip works as well.. The OpenTK override Exit does not seem to trigger if you close the window manually. Can be solved by adding following event handler to your OnLoad override.
protected override void OnLoad(EventArgs e)
{
    /// other init code
    Closed += OnClosed;
}

private void OnClosed(object sender, EventArgs eventArgs)
{
    Exit();
}


Hope this helps someone out there :)

Thursday, January 26, 2017

OpenGL 4 with OpenTK in C# Part 3: Passing data to shaders



In this post we will look passing data from your application code to the shaders using OpenTK.

This is part 3 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

As stated in the previous post, I am in no way an expert in OpenGL. I write these posts as a way to learn, if you want to have all the theory behind why things are done in a certain way I recommend reading OpenGL SuperBible, Seventh Edition :)
This part will build upon the game window and shaders from the previous post.

Defining in parameters to our Vertex Shader

For starters a reminder of our OnRenderFrame method from the previous posts. Added _time to hold total time elapsed as OpenTK seems to be giving the delta time only in the FrameEventArgs.
private double _time;
protected override void OnRenderFrame(FrameEventArgs e)
{
    _time += e.Time;
    Title = $"{_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);

    GL.UseProgram(_program);

    // add shader attributes here

    GL.DrawArrays(PrimitiveType.Points, 0, 1);
    GL.PointSize(10);
    SwapBuffers();
}

Float parameter

So, lets modify our vertex shader to take a parameter, time in this case and calculate a color and forward it to the fragment shader. I.e. out parameter of vertex shader matches the in parameter of fragment shader.

Vertex Shader
#version 440 core

layout (location = 0) in float time;
out vec4 frag_color;

void main(void)
{
 gl_Position = vec4( 0.25, -0.25,  0.5,  1.0);
 frag_color = vec4(sin(time) * 0.5 + 0.5, cos(time) * 0.5 + 0.5, 0.0, 0.0);
}

Fragment Shader
#version 440 core

in vec4 frag_color;
out vec4 color;

void main(void)
{
 color = frag_color;
}

And in our OnRenderFrame we add the following to pass along our float time to the shader.
    // add shader attributes here
    GL.VertexAttrib1(0, _time);

This should result in the vertex blending in color over time. Key here is that the first parameter of GL.VertexAttrib1 should match the location definition in our shader.


Vector4 parameter

Vertex Shader
Here we add a new in attribute, position that is a vec4. And we just set the gl_Position to whatever value is supplied by our game code.
#version 440 core

layout (location = 0) in float time;
layout (location = 1) in vec4 position;
out vec4 frag_color;

void main(void)
{
 gl_Position = position;
 frag_color = vec4(sin(time) * 0.5 + 0.5, cos(time) * 0.5 + 0.5, 0.0, 0.0);
}

And in our OnRenderFrame we add the following

    Vector4 position;
    position.X = (float)Math.Sin(_time) * 0.5f;
    position.Y = (float)Math.Cos(_time) * 0.5f;
    position.Z = 0.0f;
    position.W = 1.0f;
    GL.VertexAttrib4(1, position);

See that the location definition and the first parameter of the GL.VertexAttrib4 match.

This should give an output similar to the picture below (or watch at https://youtu.be/na_96BMN-EA), The dot should be moving on an elliptical path around the center of the window and it should still be changing colors as it moves.

There are a lot of overload versions for the GL.VertexAttrib function. I guess so that we can pass through all that we could possibly need. Just look around and see what overload to use that matches your needs. Head over to the OpenGL API documentation for a full list, and check your Intellisense to figure out what OpenTK overload to use.


Hope this helps someone out there :)
Thanks for reading. Here's another video of 2 of our cats fighting to lighten up your day.

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! :)

Wednesday, January 25, 2017

OpenGL 4 with OpenTK in C# Part 2: Compiling shaders and linking them


Now that we have a game window, lets look at loading and compiling shaders and getting things on screen.

This is part 2 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

As stated in the previous post, I am in no way an expert in OpenGL. I write these posts as a way to learn, if you want to have all the theory behind why things are done in a certain way I recommend reading OpenGL SuperBible, Seventh Edition :)
This part will build upon the game window from the previous post.

Updated 2017-05-17
Clarified how to use the shaders described in this article.

Compiling shaders and linking them

I will not go into details about shaders in this post as I do not really know much of them yet, maybe I'll write about them in detail in the future. At this point I just want to be able to use them.

The following function does just that. It tells OpenGL to create a new shader object with the
GL.CreateShader method. It the populates that shader object with the shader source code from a file with the GL.ShaderSource call. Using System.IO.File.ReadAllText to load the contents of the shader file and then a call to GL.CompileShader to compile it.
The minimum shaders needed to get something to the screen are the VertexShader and the FragmentShader, so the function loads both.
After that, we create a new program by calling GL.CreateProgram, attach the shaders with GL.AttachShader and then link the program with GL.LinkProgram. Pretty straight forward.
After the linking it is OK to remove the shaders by calling GL.DetachShader and GL.DeleteShader. Always keep a tidy shop :)

private int CompileShaders()
{
    var vertexShader = GL.CreateShader(ShaderType.VertexShader);
    GL.ShaderSource(vertexShader, File.ReadAllText(@"Components\Shaders\vertexShader.vert"));
    GL.CompileShader(vertexShader);

    var fragmentShader = GL.CreateShader(ShaderType.FragmentShader);
    GL.ShaderSource(fragmentShader, File.ReadAllText(@"Components\Shaders\fragmentShader.frag"));
    GL.CompileShader(fragmentShader);

    var program = GL.CreateProgram();
    GL.AttachShader(program, vertexShader);
    GL.AttachShader(program, fragmentShader);
    GL.LinkProgram(program);

    GL.DetachShader(program, vertexShader);
    GL.DetachShader(program, fragmentShader);
    GL.DeleteShader(vertexShader);
    GL.DeleteShader(fragmentShader);
    return program;
}

Call this from the OnLoad method and store the program id in a member variable in the gamewindow so that we can find it later. Also bind the Closed event to a handler and call Exit() manually from there to ensure that cleanup is triggered when user closes the application.

private int _program;
protected override void OnLoad(EventArgs e)
{
    CursorVisible = true;
    _program = CompileShaders();
    Closed += OnClosed;
}
private void OnClosed(object sender, EventArgs eventArgs)
{
    Exit();
}

And a little cleanup in the OnExit method
public override void Exit()
{
 GL.DeleteProgram(_program);
 base.Exit();
}

And when executed, the screen is still dark blue. So nothing.

Drawing things

So.. Evidently we need shaders. So I'll just provide two simple ones
VertexShader
A basic Vertex Shader that sets the position of a vertex. Copy paste into a text editor and save as vertexShader.vert in a subfolder called shaders. Change the properties of the file to Copy Always so that it ends up in your build folder.

#version 440 core

void main(void)
{
 gl_Position = vec4( 0.25, -0.25,  0.5,  1.0);
}

FragmentShader
A basic Fragment Shader that sets the color of the fragment. Copy paste into a text editor and save as fragmentShader.frag in the same folder as the vertex shader and change to copy always here as well!

#version 440 core

out vec4 color;

void main(void)
{
 color = vec4(1.0, 0.0, 0.0, 1.0);
}

Changes to our program
In the OnLoad method, lets add a vertex buffer initialization so that we can bind it so that we can use it.

private int _program;
private int _vertexArray;
protected override void OnLoad(EventArgs e)
{
    CursorVisible = true;
    _program = CompileShaders();
    GL.GenVertexArrays(1, out _vertexArray);
    GL.BindVertexArray(_vertexArray);
    Closed += OnClosed;
}

More cleanup in our OnExit method
public override void Exit()
{
    GL.DeleteVertexArrays(1, ref _vertexArray);
    GL.DeleteProgram(_program);
    base.Exit();
}

And then to actually do some output on the screen in OnRenderFrame method by adding GL.UseProgramGL.DrawArrays and GL.PointSize. The last so that the point is bigger then just 1 pixel.
protected override void OnRenderFrame(FrameEventArgs e)
{
    Title = $"{_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);

    GL.UseProgram(_program);

    GL.DrawArrays(PrimitiveType.Points, 0, 1);
    GL.PointSize(10);
    SwapBuffers();
}

This should give an output similar to the header (without the white text, i.e. a red dot on blue background)
If for some reason the shader doesn't work after compiling, check the versions.

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! :)

Tuesday, January 24, 2017

Where did my shader go?


If you for the world can't figure out why a shader won't bite. Try checking that you are not trying to use a version that is not supported on your computer.

#version 450 core

On my computer, any shader with that line doesn't load. And the

GL.CompileShader(fragmentShader);

doesn't provide any feedback on what could be wrong.
After an hour of trying to figure out what was wrong I finally looked at what version of OpenGL that actually was running by the following line in the GameWindow constructor:

Title += "dreamstatecoding.blogspot.com: OpenGL Version: " + GL.GetString(StringName.Version);

Turned out I was running OpenGL Version: 4.4.0 - Build 21.20.16.4534.
So I changed the version in the shader to

#version 440 core

and all of a sudden the shaders kick in.

Update 2017-01-28
Turns out that I was using my built in Intel chip and not the NVidia when running my game window. After changing to NVidia, the 450 core version started to work as well.

Hope this helps someone out there :)

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! :)

Saturday, January 21, 2017

Where did my unit tests go? X64


Yesterday I added some native X64 libraries to my project and got a lot of BadImageFormatException  so I decided to google a little on it and found that I should change my build configuration from AnyCPU to X64 as well. And it just works.



Today I noticed that my unit tests are not loading nor running. Just an empty list in the test explorer. After a bit of an headache I finally found the correct options to change to get them to work in X64 mode.


In Visual Studio 2015:
Go to the menu: Test>Test Settings>Default Processor Architecture
select X64

Rebuild your solution and the test explorer should be populated.

Hope this helps someone out there :)