using System; using OpenTK.Graphics.OpenGL; using OpenTK.Mathematics; using static OpenTK.Graphics.OpenGL.GL; using OpenTK.Windowing.Common; using OpenTK.Windowing.Desktop; namespace OpenTKCourse { public class Game : GameWindow { private int _vertexBuffer; private int _indexBuffer; private int _vertexArray; private int _shaderProgram; public Game(string title = "Tutorial", int width = 1080, int height = 720) : base(new GameWindowSettings(), new NativeWindowSettings { Title = title, Size = new Vector2i(width, height), WindowBorder = WindowBorder.Fixed, StartVisible = false, StartFocused = true, API = ContextAPI.OpenGL, Profile = ContextProfile.Core, APIVersion = new Version(3, 3) }) {} protected override void OnLoad() { ClearColor(new Color4(0.3f, 0.4f, 0.5f, 1.0f)); float[] vertices = { // X, Y, Z; R, G, B, A -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, -0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, }; int[] indices = { 0, 1, 2, 0, 2, 3 }; _vertexBuffer = GenBuffer(); BindBuffer(BufferTarget.ArrayBuffer, _vertexBuffer); BufferData(BufferTarget.ArrayBuffer, vertices.Length * sizeof(float), vertices, BufferUsageHint.StaticDraw); BindBuffer(BufferTarget.ArrayBuffer, 0); _indexBuffer = GenBuffer(); BindBuffer(BufferTarget.ElementArrayBuffer, _indexBuffer); BufferData(BufferTarget.ElementArrayBuffer, indices.Length * sizeof(int), indices, BufferUsageHint.StaticDraw); BindBuffer(BufferTarget.ElementArrayBuffer, 0); _vertexArray = GenVertexArray(); BindVertexArray(_vertexArray); BindBuffer(BufferTarget.ArrayBuffer, _vertexBuffer); VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 7 * sizeof(float), 0); EnableVertexAttribArray(0); VertexAttribPointer(1, 4, VertexAttribPointerType.Float, false, 7 * sizeof(float), 3 * sizeof(float)); EnableVertexAttribArray(1); BindBuffer(BufferTarget.ArrayBuffer, 0); BindVertexArray(0); string vertex = @" #version 330 core layout (location = 0) in vec3 aPosition; layout (location = 1) in vec4 aColor; out vec4 fColor; void main() { fColor = aColor; gl_Position = vec4(aPosition, 1.0f); } "; string fragment = @" #version 330 core in vec4 fColor; out vec4 color; void main() { color = fColor; } "; int vertexHandle = CreateShader(ShaderType.VertexShader); int fragmentHandle = CreateShader(ShaderType.FragmentShader); ShaderSource(vertexHandle, vertex); ShaderSource(fragmentHandle, fragment); CompileShader(vertexHandle); CompileShader(fragmentHandle); string vertexError = GetShaderInfoLog(vertexHandle); if (vertexError != String.Empty) Console.Error.WriteLine(vertexError); string fragmentError = GetShaderInfoLog(fragmentHandle); if (fragmentError != String.Empty) Console.Error.WriteLine(fragmentError); _shaderProgram = CreateProgram(); AttachShader(_shaderProgram, vertexHandle); AttachShader(_shaderProgram, fragmentHandle); LinkProgram(_shaderProgram); DetachShader(_shaderProgram, vertexHandle); DetachShader(_shaderProgram, fragmentHandle); DeleteShader(vertexHandle); DeleteShader(fragmentHandle); base.OnLoad(); IsVisible = true; } protected override void OnUnload() { BindBuffer(BufferTarget.ArrayBuffer, 0); DeleteBuffer(_vertexBuffer); BindBuffer(BufferTarget.ElementArrayBuffer, 0); DeleteBuffer(_indexBuffer); BindVertexArray(0); DeleteVertexArray(_vertexArray); UseProgram(0); DeleteProgram(_shaderProgram); base.OnUnload(); } protected override void OnResize(ResizeEventArgs e) { Viewport(0, 0, Size.X, Size.Y); base.OnResize(e); } protected override void OnRenderFrame(FrameEventArgs args) { Clear(ClearBufferMask.ColorBufferBit); UseProgram(_shaderProgram); BindVertexArray(_vertexArray); BindBuffer(BufferTarget.ElementArrayBuffer, _indexBuffer); DrawElements(PrimitiveType.Triangles, 6, DrawElementsType.UnsignedInt, 0); Context.SwapBuffers(); base.OnRenderFrame(args); } } }