Search code examples
c#openglopentk

How to draw a line in OpenGL without glBegin


I looked at the code in How to draw line in OpenGl? but glBegin and glEnd are marked as deprecated. How are you supposed to draw a line in the current OpenGL version? I found articles that talk about using VBO, and articles that talk about glVertexPointer and glColorPointer, but there's so much framework around building these methods with the shader program compiling and linking and the vertex attribute bit twiddling. Isn't there a simple way to draw a line without using deprecated functions?

I tried this without success:

OpenTK.Vector2[] linepts = { new Vector2(0, 0), new Vector2(1, 1), new Vector2(50, 0), new Vector2(0, 50) };
int h = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, h);
GL.BufferData<Vector2>(BufferTarget.ArrayBuffer, 16, linepts, BufferUsageHint.StreamDraw);
GL.DrawArrays(PrimitiveType.LineStrip, 0, 4);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.DeleteBuffer(h);

I don't know if I'm even in the right ballpark using DrawArrays or if that method requires a whole mess of framework to go along with it, so I don't necessarily want to make this code work. I just want to find the simplest code for drawing a line that's advisable to use in modern OpenGL.


Solution

  • This is the simplest program (using OpenTK) that I can create to draw a line.

    using System;
    using OpenTK;
    using OpenTK.Graphics;
    using OpenTK.Graphics.OpenGL;
    
    namespace OpenGLLine
    {
       static class Program
       {
          static OpenTK.GameWindow gw;
          static int shaderProgram;
          static int vertexInfo;
          static int lineVertexBuffer;
          static int vertexCount;
    
          [STAThread]
          static void Main()
          {
             gw = new OpenTK.GameWindow(800, 600, OpenTK.Graphics.GraphicsMode.Default, "Game", OpenTK.GameWindowFlags.FixedWindow);
             Initialize();
             gw.RenderFrame += Gw_RenderFrame;
             gw.Closed += Gw_Closed;
             gw.Run(60);
          }
    
          private static void Gw_Closed(object sender, EventArgs e)
          {
             CleanUp();
          }
    
          private static void Initialize()
          {
             int vshader = GL.CreateShader(ShaderType.VertexShader);
             GL.ShaderSource(vshader, @"#version 130
                in vec2 vPosition;
                void main()
                {
                   gl_Position = vec4(vPosition, -1.0, 1.0);
                }");
             GL.CompileShader(vshader);
             int fshader = GL.CreateShader(ShaderType.FragmentShader);
             GL.ShaderSource(fshader, @"#version 130
                out vec4 fragColor;
                void main()
                {
                   fragColor = vec4(1.0, 1.0, 1.0, 1.0);
                }");
             GL.CompileShader(fshader);
             shaderProgram = GL.CreateProgram();
             GL.AttachShader(shaderProgram, vshader);
             GL.AttachShader(shaderProgram, fshader);
             GL.LinkProgram(shaderProgram);
             GL.DetachShader(shaderProgram, vshader);
             GL.DetachShader(shaderProgram, fshader);
             GL.UseProgram(shaderProgram);
             lineVertexBuffer = GL.GenBuffer();
             Vector2[] lineVertices = { new Vector2(0, 0), new Vector2(.5f, .5f) };
             vertexCount = lineVertices.Length;
             GL.BindBuffer(BufferTarget.ArrayBuffer, lineVertexBuffer);
             GL.BufferData(BufferTarget.ArrayBuffer, System.Runtime.InteropServices.Marshal.SizeOf(lineVertices[0]) * vertexCount,
                lineVertices, BufferUsageHint.StreamDraw);
             vertexInfo = GL.GenVertexArray();
             GL.BindVertexArray(vertexInfo);
             int locVPosition = GL.GetAttribLocation(shaderProgram, "vPosition");
             GL.EnableVertexAttribArray(locVPosition);
             GL.VertexAttribPointer(locVPosition, 2, VertexAttribPointerType.Float, false,
                System.Runtime.InteropServices.Marshal.SizeOf(lineVertices[0]), 0);
             GL.BindVertexArray(0);
             GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
             GL.UseProgram(0);
          }
    
          static void CleanUp()
          {
    
             GL.DeleteProgram(shaderProgram);
             GL.DeleteVertexArray(vertexInfo);
             GL.DeleteBuffer(lineVertexBuffer);
          }
    
          private static void Gw_RenderFrame(object sender, OpenTK.FrameEventArgs e)
          {
             GL.ClearColor(Color4.Black);
             GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
             GL.BindBuffer(BufferTarget.ArrayBuffer, lineVertexBuffer);
             GL.UseProgram(shaderProgram);
             GL.BindVertexArray(vertexInfo);
             GL.DrawArrays(PrimitiveType.LineStrip, 0, vertexCount);
             GL.BindVertexArray(0);
             GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
             GL.UseProgram(0);
             gw.SwapBuffers();
          }
       }
    }