Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Chapter1/1-CreatingAWindow/1-CreatingAWindow.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
<OutputType>WinExe</OutputType>
<RootNamespace>LearnOpenTK</RootNamespace>
<AssemblyName>LearnOpenTK</AssemblyName>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="OpenTK" Version="4.7.4" />
<PackageReference Include="OpenTK" Version="4.9.4" />
<PackageReference Include="StbImageSharp" Version="2.30.15" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion Chapter1/1-CreatingAWindow/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ private static void Main()
{
var nativeWindowSettings = new NativeWindowSettings()
{
Size = new Vector2i(800, 600),
ClientSize = new Vector2i(800, 600),
Title = "LearnOpenTK - Creating a Window",
// This is needed to run on macos
Flags = ContextFlags.ForwardCompatible,
Expand Down
18 changes: 3 additions & 15 deletions Chapter1/2-HelloTriangle/2-HelloTriangle.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,15 @@
<OutputType>WinExe</OutputType>
<RootNamespace>LearnOpenTK</RootNamespace>
<AssemblyName>LearnOpenTK</AssemblyName>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<None Include="Shaders/**" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="OpenTK" Version="4.7.4" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\Common\Common.csproj" />
</ItemGroup>

<ItemGroup>
<None Update="Shaders\shader.frag">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Shaders\shader.vert">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<PackageReference Include="OpenTK" Version="4.9.4" />
<PackageReference Include="StbImageSharp" Version="2.30.15" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion Chapter1/2-HelloTriangle/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ private static void Main()
{
var nativeWindowSettings = new NativeWindowSettings()
{
Size = new Vector2i(800, 600),
ClientSize = new Vector2i(800, 600),
Title = "LearnOpenTK - Creating a Window",
// This is needed to run on macos
Flags = ContextFlags.ForwardCompatible,
Expand Down
1 change: 1 addition & 0 deletions Chapter1/2-HelloTriangle/Shaders/shader.frag
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ out vec4 outputColor;

void main()
{
// Set the pixel color to RGB (1, 1, 0), a yellow color.
outputColor = vec4(1.0, 1.0, 0.0, 1.0);
}
8 changes: 4 additions & 4 deletions Chapter1/2-HelloTriangle/Shaders/shader.vert
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@
// shader(vertex)


// This defines our input variable, aPosition.
// This defines our input variable, aPos.
// It starts with the line "layout(location = 0)". This defines where this input variable will be located, which is needed for GL.VertexAttribPointer.
// However, you can omit it, and replace this with just "in vec3 aPosition". If you do that, you'll have to replace the 0 in GL.VertexAttribPointer with
// However, you can omit it, and replace this with just "in vec3 aPos". If you do that, you'll have to replace the 0 in GL.VertexAttribPointer with
// a call to GL.GetAttribLocation(shaderHandle, attributeName)
// Next, the keyword "in" defines this as an input variable. We'll have an example of the "out" keyword in the next tutorial.
// Then, the keyword "vec3" means this is a vector with 3 floats inside.

layout(location = 0) in vec3 aPosition;
layout(location = 0) in vec3 aPos;


// Like C, we have an entrypoint function. In this case, it takes void and returns void, and must be named main.
Expand All @@ -37,5 +37,5 @@ layout(location = 0) in vec3 aPosition;

void main(void)
{
gl_Position = vec4(aPosition, 1.0);
gl_Position = vec4(aPos, 1.0);
}
88 changes: 75 additions & 13 deletions Chapter1/2-HelloTriangle/Window.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
using LearnOpenTK.Common;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.GraphicsLibraryFramework;
using OpenTK.Windowing.Desktop;
using OpenTK.Windowing.GraphicsLibraryFramework;
using System;
using System.IO;

namespace LearnOpenTK
{
Expand Down Expand Up @@ -34,7 +35,7 @@ public class Window : GameWindow
// This class is a wrapper around a shader, which helps us manage it.
// The shader class's code is in the Common project.
// What shaders are and what they're used for will be explained later in this tutorial.
private Shader _shader;
private int _shader;

public Window(GameWindowSettings gameWindowSettings, NativeWindowSettings nativeWindowSettings)
: base(gameWindowSettings, nativeWindowSettings)
Expand Down Expand Up @@ -112,13 +113,13 @@ protected override void OnLoad()
// Modern OpenGL makes this pipeline very free, giving us a lot of freedom on how vertices are turned to pixels.
// The drawback is that we actually need two more programs for this! These are called "shaders".
// Shaders are tiny programs that live on the GPU. OpenGL uses them to handle the vertex-to-pixel pipeline.
// Check out the Shader class in Common to see how we create our shaders, as well as a more in-depth explanation of how shaders work.
// Check out the CompileProgram function to see how we create our shaders, as well as a more in-depth explanation of how shaders work.
// shader.vert and shader.frag contain the actual shader code.
_shader = new Shader("Shaders/shader.vert", "Shaders/shader.frag");
_shader = CompileProgram(File.ReadAllText("Shaders/shader.vert"), File.ReadAllText("Shaders/shader.frag"));

// Now, enable the shader.
// Just like the VBO, this is global, so every function that uses a shader will modify this one until a new one is bound instead.
_shader.Use();
GL.UseProgram(_shader);

// Setup is now complete! Now we move to the OnRenderFrame function to finally draw the triangle.
}
Expand All @@ -140,7 +141,7 @@ protected override void OnRenderFrame(FrameEventArgs e)
// and then calling an OpenGL function to render.

// Bind the shader
_shader.Use();
GL.UseProgram(_shader);

// Bind the VAO
GL.BindVertexArray(_vertexArrayObject);
Expand Down Expand Up @@ -176,13 +177,13 @@ protected override void OnUpdateFrame(FrameEventArgs e)
}
}

protected override void OnResize(ResizeEventArgs e)
protected override void OnFramebufferResize(FramebufferResizeEventArgs e)
{
base.OnResize(e);
base.OnFramebufferResize(e);

// When the window gets resized, we have to call GL.Viewport to resize OpenGL's viewport to match the new size.
// If we don't, the NDC will no longer be correct.
GL.Viewport(0, 0, Size.X, Size.Y);
GL.Viewport(0, 0, e.Width, e.Height);
}

// Now, for cleanup.
Expand All @@ -197,7 +198,7 @@ protected override void OnResize(ResizeEventArgs e)
// longer used for whatever reason (e.g. a new scene is loaded that doesn't use a texture).
// This would free up video ram (VRAM) that can be used for new textures.
//
// The coming chapters will not have this code.
// The coming chapters will not have this cleanup code.
protected override void OnUnload()
{
// Unbind all the resources by binding the targets to 0/null.
Expand All @@ -209,9 +210,70 @@ protected override void OnUnload()
GL.DeleteBuffer(_vertexBufferObject);
GL.DeleteVertexArray(_vertexArrayObject);

GL.DeleteProgram(_shader.Handle);
GL.DeleteProgram(_shader);

base.OnUnload();
}

private static int CompileProgram(string vertexSource, string fragmentSource)
{
// Compile vertex shader.
int vertexShader = CompileShader(ShaderType.VertexShader, vertexSource);

// We do the same for the fragment shader.
int fragmentShader = CompileShader(ShaderType.FragmentShader, fragmentSource);

// These two shaders must then be merged into a shader program, which can then be used by OpenGL.
// To do this, create a program...
int handle = GL.CreateProgram();

// Attach both shaders...
GL.AttachShader(handle, vertexShader);
GL.AttachShader(handle, fragmentShader);

// And then link them together.
GL.LinkProgram(handle);

// Check for linking errors
GL.GetProgram(handle, GetProgramParameterName.LinkStatus, out var code);
if (code != (int)All.True)
{
// We can use `GL.GetProgramInfoLog(program)` to get information about the error.
string infoLog = GL.GetProgramInfoLog(handle);
throw new Exception($"Error occurred whilst linking Program({handle}):\n{infoLog}");
}

// When the shader program is linked, it no longer needs the individual shaders attached to it; the compiled code is copied into the shader program.
// Detach them, and then delete them.
GL.DetachShader(handle, vertexShader);
GL.DetachShader(handle, fragmentShader);
GL.DeleteShader(fragmentShader);
GL.DeleteShader(vertexShader);

return handle;
}

private static int CompileShader(ShaderType type, string source)
{
// GL.CreateShader will create an empty shader. The ShaderType enum denotes which type of shader will be created.
int shader = GL.CreateShader(type);

// Upload the GLSL source code.
GL.ShaderSource(shader, source);

// Try to compile the shader
GL.CompileShader(shader);

// Check for compilation errors
GL.GetShader(shader, ShaderParameter.CompileStatus, out var code);
if (code != (int)All.True)
{
// We can use `GL.GetShaderInfoLog(shader)` to get information about the error.
var infoLog = GL.GetShaderInfoLog(shader);
throw new Exception($"Error occurred whilst compiling Shader({shader}):\n{infoLog}");
}

return shader;
}
}
}
9 changes: 3 additions & 6 deletions Chapter1/3-ElementBufferObjects/3-ElementBufferObjects.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,15 @@
<OutputType>WinExe</OutputType>
<RootNamespace>LearnOpenTK</RootNamespace>
<AssemblyName>LearnOpenTK</AssemblyName>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<None Include="Shaders/**" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="OpenTK" Version="4.7.4" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\Common\Common.csproj" />
<PackageReference Include="OpenTK" Version="4.9.4" />
<PackageReference Include="StbImageSharp" Version="2.30.15" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion Chapter1/3-ElementBufferObjects/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ private static void Main()
{
var nativeWindowSettings = new NativeWindowSettings()
{
Size = new Vector2i(800, 600),
ClientSize = new Vector2i(800, 600),
Title = "LearnOpenTK - Element Buffer Objects",
// This is needed to run on macos
Flags = ContextFlags.ForwardCompatible,
Expand Down
4 changes: 2 additions & 2 deletions Chapter1/3-ElementBufferObjects/Shaders/shader.vert
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#version 330 core

layout(location = 0) in vec3 aPosition;
layout(location = 0) in vec3 aPos;

void main(void)
{
gl_Position = vec4(aPosition, 1.0);
gl_Position = vec4(aPos, 1.0);
}
67 changes: 57 additions & 10 deletions Chapter1/3-ElementBufferObjects/Window.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
using LearnOpenTK.Common;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.GraphicsLibraryFramework;
using OpenTK.Windowing.Desktop;
using OpenTK.Windowing.GraphicsLibraryFramework;
using System;
using System.IO;

namespace LearnOpenTK
{
Expand Down Expand Up @@ -38,7 +39,7 @@ public class Window : GameWindow

private int _vertexArrayObject;

private Shader _shader;
private int _shader;

// Add a handle for the EBO
private int _elementBufferObject;
Expand Down Expand Up @@ -76,8 +77,8 @@ protected override void OnLoad()
GL.BufferData(BufferTarget.ElementArrayBuffer, _indices.Length * sizeof(uint), _indices, BufferUsageHint.StaticDraw);
// The EBO has now been properly setup. Go to the Render function to see how we draw our rectangle now!

_shader = new Shader("Shaders/shader.vert", "Shaders/shader.frag");
_shader.Use();
_shader = CompileProgram(File.ReadAllText("Shaders/shader.vert"), File.ReadAllText("Shaders/shader.frag"));
GL.UseProgram(_shader);
}

protected override void OnRenderFrame(FrameEventArgs e)
Expand All @@ -86,7 +87,7 @@ protected override void OnRenderFrame(FrameEventArgs e)

GL.Clear(ClearBufferMask.ColorBufferBit);

_shader.Use();
GL.UseProgram(_shader);

// Because ElementArrayObject is a property of the currently bound VAO,
// the buffer you will find in the ElementArrayBuffer will change with the currently bound VAO.
Expand Down Expand Up @@ -115,10 +116,56 @@ protected override void OnUpdateFrame(FrameEventArgs e)
}
}

protected override void OnResize(ResizeEventArgs e)
protected override void OnFramebufferResize(FramebufferResizeEventArgs e)
{
base.OnFramebufferResize(e);

GL.Viewport(0, 0, e.Width, e.Height);
}

private static int CompileProgram(string vertexSource, string fragmentSource)
{
base.OnResize(e);
GL.Viewport(0, 0, Size.X, Size.Y);
int vertexShader = CompileShader(ShaderType.VertexShader, vertexSource);
int fragmentShader = CompileShader(ShaderType.FragmentShader, fragmentSource);

int handle = GL.CreateProgram();

GL.AttachShader(handle, vertexShader);
GL.AttachShader(handle, fragmentShader);

GL.LinkProgram(handle);

GL.GetProgram(handle, GetProgramParameterName.LinkStatus, out var code);
if (code != (int)All.True)
{
string infoLog = GL.GetProgramInfoLog(handle);
throw new Exception($"Error occurred whilst linking Program({handle}):\n{infoLog}");
}

GL.DetachShader(handle, vertexShader);
GL.DetachShader(handle, fragmentShader);
GL.DeleteShader(fragmentShader);
GL.DeleteShader(vertexShader);

return handle;
}

private static int CompileShader(ShaderType type, string source)
{
int shader = GL.CreateShader(type);

GL.ShaderSource(shader, source);

GL.CompileShader(shader);

GL.GetShader(shader, ShaderParameter.CompileStatus, out var code);
if (code != (int)All.True)
{
var infoLog = GL.GetShaderInfoLog(shader);
throw new Exception($"Error occurred whilst compiling Shader({shader}):\n{infoLog}");
}

return shader;
}
}
}
Loading