1

Im getting an Access Violation when ever I run this code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
using System.IO;

namespace OpenTKTutorial1
{
    class Game : GameWindow
    {
        int pgmID;
        int vsID;
        int fsID;

        int attribute_vcol;
        int attribute_vpos;
        int uniform_mview;

        int vbo_position;
        int vbo_color;
        int vbo_mview;

        Vector3[] vertdata;
        Vector3[] coldata;
        Matrix4[] mviewdata;

        void initProgram()
        {
            pgmID = GL.CreateProgram();

            loadShader("vs.glsl", ShaderType.VertexShader, pgmID, out vsID);
            loadShader("fs.glsl", ShaderType.FragmentShader, pgmID, out fsID);

            GL.LinkProgram(pgmID);
            Console.WriteLine(GL.GetProgramInfoLog(pgmID));

            attribute_vpos = GL.GetAttribLocation(pgmID, "vPosition");
            attribute_vcol = GL.GetAttribLocation(pgmID, "vColor");
            uniform_mview = GL.GetUniformLocation(pgmID, "modelview");

            if (attribute_vpos == -1 || attribute_vcol == -1 || uniform_mview == -1)
            {
                Console.WriteLine("Error binding attirbutes");
            }

            GL.GenBuffers(1, out vbo_position);
            GL.GenBuffers(1, out vbo_color);
            GL.GenBuffers(1, out vbo_mview);
        }

        void loadShader(String filename, ShaderType type, int program, out int address)
        {
            address = GL.CreateShader(type);
            using (StreamReader sr = new StreamReader(filename))
            {
                GL.ShaderSource(address, sr.ReadToEnd());
            }
            GL.CompileShader(address);
            GL.AttachShader(program, address);
            Console.WriteLine(GL.GetShaderInfoLog(address));
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            initProgram();

            vertdata = new Vector3[]{
                new Vector3(-0.8f, -0.8f, 0f),
                new Vector3(0.8f, -0.8f, 0f),
                new Vector3(0f, 0.8f, 0f)};

            coldata = new Vector3[]{
                new Vector3(1f, 0f, 0f),
                new Vector3(0f, 0f, 1f),
                new Vector3(0f, 1f, 0f)};


            mviewdata = new Matrix4[]{
                Matrix4.Identity};

            Title = "Title";
            GL.ClearColor(Color.CornflowerBlue);
            GL.PointSize(5f);
        }

        protected override void OnRenderFrame(FrameEventArgs e)
        {
            base.OnRenderFrame(e);

            GL.Viewport(0, 0, Width, Height);
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
            GL.Enable(EnableCap.DepthTest);

            GL.EnableVertexAttribArray(attribute_vpos);
            GL.EnableVertexAttribArray(attribute_vcol);

            GL.DrawArrays(PrimitiveType.Triangles, 0, 3);

            GL.DisableVertexAttribArray(attribute_vpos);
            GL.DisableVertexAttribArray(attribute_vcol);

            GL.Flush();

            //Everything before this
            SwapBuffers();
        }

        protected override void OnUpdateFrame(FrameEventArgs e)
        {
            base.OnUpdateFrame(e);

            GL.BindBuffer(BufferTarget.ArrayBuffer, vbo_position);
            GL.BufferData<Vector3>(BufferTarget.ArrayBuffer, (IntPtr)(vertdata.Length * Vector3.SizeInBytes), vertdata, BufferUsageHint.StaticDraw);
            GL.VertexAttribPointer(attribute_vpos, 3, VertexAttribPointerType.Float, false, 0, 0);

            GL.BindBuffer(BufferTarget.ArrayBuffer, vbo_color);
            GL.BufferData<Vector3>(BufferTarget.ArrayBuffer, (IntPtr)(coldata.Length * Vector3.SizeInBytes), coldata, BufferUsageHint.StaticDraw);
            GL.VertexAttribPointer(attribute_vcol, 3, VertexAttribPointerType.Float, true, 0, 0);

            GL.UniformMatrix4(uniform_mview, false, ref mviewdata[0]);

            GL.UseProgram(pgmID);

            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
        }
    }
}

It makes it to rendering the background then crashes.

I'm quite new to OpenTK and OpenGL so I'm not 100% sure what the problem is.

The error is thrown at

GL.DrawArrays(PrimitiveType.Triangles, 0, 3);
LAK132
  • 193
  • 1
  • 10
  • I'm not familiar with the languages/toolkits in play here, but the way you define and use `vertdata` and `coldata` looks suspicious. At least in other languages, they would be arrays of pointers/references. The data you pass to `glBufferData()` needs to be a flat buffer/array of float values. Unless something magically flattens the array, this is probably not what is passed here. – Reto Koradi Dec 28 '14 at 05:05
  • The problems might come from calling binding the buffers in the OnUpdateFrame method. There is no guarantee that this Update is called before RenderFrame, since RenderFrame is called as often as possible and UpdateFrame is called at a fixed rate. Read [this](http://stackoverflow.com/questions/23542591/open-tk-difference-onrenderframe-and-onupdateframe) for more details. – BDL Dec 28 '14 at 11:40
  • Additionally, uploading the data to the gpu in every frame is not a good idea from the performance point of view. – BDL Dec 28 '14 at 11:40
  • @RetoKoradi: Vector3 is basically an array of three floats and is designed to be used with these methods. Have a look at [this](http://www.opentk.com/files/doc/struct_open_t_k_1_1_vector3.html#details) – BDL Dec 28 '14 at 11:44
  • @BDL I'm not concerned about the `Vector3` itself, but how the array of vectors is allocated. If you look at how `vertdata` is initialized, will this result in a contiguous sequence of floats? Can it safely be passed to `BufferData`? – Reto Koradi Dec 28 '14 at 17:52
  • @RetoKoradi: How else would you initialize an array of structs in C#? As far as I know this is the only way. Just for completeness: It's also the way how it is done in the [official tutorial](http://www.opentk.com/node/1039). – BDL Dec 28 '14 at 19:16
  • I think I'll just give up on this piece of code. Are there any good introductions to OpenTK and OpenGL for someone who knows nothing about them? This was a pretty good tutorial but Windows 8 and OpenTK 1.1 apparently broke it – LAK132 Dec 29 '14 at 03:39
  • One problem is that `UniformMatrix4` needs to be after `UseProgram`. But I don't think that would cause it to crash. – Reto Koradi Dec 29 '14 at 05:27
  • Has nothing to do with Windows 8 and OpenTK, your exact code is working for me after I made up the shaders. – Gigo Dec 29 '14 at 07:40
  • @Gigo ok. I'll give it another go – LAK132 Dec 29 '14 at 08:21

1 Answers1

2

There are a few minor issues with your code, but it works for me without changes.

Regardless, I have made a few changes and added commentary to explain why, maybe something fixes it for you. If not please post your shaders and more detail on the exact exception, if there is any.

using System;
using System.Drawing;
using System.IO;
using OpenTK;
using OpenTK.Graphics.OpenGL;

namespace OpenTKTutorial1
{
    public class Game
        : GameWindow
    {
        int pgmID;
        int vsID;
        int fsID;

        int attribute_vcol;
        int attribute_vpos;
        int uniform_mview;

        int vbo_position;
        int vbo_color;
        int vbo_mview;

        Vector3[] vertdata;
        Vector3[] coldata;
        Matrix4[] mviewdata;

        public Game()
        {
            // better use the events instead of overriding the inherited methods
            // at least thats what the documentation on Update- and RenderFrame says
            Load += OnLoad;
            UpdateFrame += OnUpdateFrame;
            RenderFrame += OnRenderFrame;
        }

        void InitProgram()
        {
            pgmID = GL.CreateProgram();

            LoadShader("vs.glsl", ShaderType.VertexShader, pgmID, out vsID);
            LoadShader("fs.glsl", ShaderType.FragmentShader, pgmID, out fsID);

            GL.LinkProgram(pgmID);
            Console.WriteLine(GL.GetProgramInfoLog(pgmID));

            attribute_vpos = GL.GetAttribLocation(pgmID, "vPosition");
            attribute_vcol = GL.GetAttribLocation(pgmID, "vColor");
            uniform_mview = GL.GetUniformLocation(pgmID, "modelview");

            if (attribute_vpos == -1 || attribute_vcol == -1 || uniform_mview == -1)
            {
                Console.WriteLine("Error binding attributes");
            }

            GL.GenBuffers(1, out vbo_position);
            GL.GenBuffers(1, out vbo_color);

            // what is this buffer for?
            //GL.GenBuffers(1, out vbo_mview);
        }

        void LoadShader(String filename, ShaderType type, int program, out int address)
        {
            address = GL.CreateShader(type);
            using (StreamReader sr = new StreamReader(filename))
            {
                GL.ShaderSource(address, sr.ReadToEnd());
            }
            GL.CompileShader(address);
            GL.AttachShader(program, address);
            Console.WriteLine(GL.GetShaderInfoLog(address));
        }

        protected void OnLoad(object sender, EventArgs eventArgs)
        {
            InitProgram();

            vertdata = new Vector3[]{
                new Vector3(-0.8f, -0.8f, 0f),
                new Vector3(0.8f, -0.8f, 0f),
                new Vector3(0f, 0.8f, 0f)};

            coldata = new Vector3[]{
                new Vector3(1f, 0f, 0f),
                new Vector3(0f, 0f, 1f),
                new Vector3(0f, 1f, 0f)};


            mviewdata = new Matrix4[]{
                Matrix4.Identity};

            Title = "Title";
            GL.ClearColor(Color.CornflowerBlue);
            GL.PointSize(5f);
        }

        protected void OnRenderFrame(object sender, FrameEventArgs frameEventArgs)
        {
            // if you only have one viewport you can safely move this to the OnResize event
            GL.Viewport(0, 0, Width, Height);

            // if the state never changes move it to OnLoad
            GL.Enable(EnableCap.DepthTest);

            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

            GL.EnableVertexAttribArray(attribute_vpos);
            GL.EnableVertexAttribArray(attribute_vcol);

            // always make sure the program is enabled ..
            GL.UseProgram(pgmID);
            // .. before you set any uniforms 
            GL.UniformMatrix4(uniform_mview, false, ref mviewdata[0]);
            // .. or draw anything
            GL.DrawArrays(PrimitiveType.Triangles, 0, 3);

            GL.DisableVertexAttribArray(attribute_vpos);
            GL.DisableVertexAttribArray(attribute_vcol);

            // do not call glFlush unless you have a very good reason to
            // it can result in significant slow downs
            //GL.Flush();

            SwapBuffers();
        }

        protected void OnUpdateFrame(object sender, FrameEventArgs frameEventArgs)
        {
            // your vertex and color data never changes, thus everything you do here
            // could be moved to OnLoad instead of having it repeated all the time
            GL.BindBuffer(BufferTarget.ArrayBuffer, vbo_position);
            GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertdata.Length * Vector3.SizeInBytes), vertdata, BufferUsageHint.StaticDraw);
            GL.VertexAttribPointer(attribute_vpos, 3, VertexAttribPointerType.Float, false, 0, 0);

            GL.BindBuffer(BufferTarget.ArrayBuffer, vbo_color);
            GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(coldata.Length * Vector3.SizeInBytes), coldata, BufferUsageHint.StaticDraw);
            GL.VertexAttribPointer(attribute_vcol, 3, VertexAttribPointerType.Float, true, 0, 0);

            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
        }
    }
}
Gigo
  • 3,188
  • 3
  • 29
  • 40
  • Moving everything from `OnUpdateFrame` to `OnLoad` fixed the crash. Thank you very much (You may want to put that in your answer for future readers) – LAK132 Dec 29 '14 at 08:44