Tushar Pandey
Tushar Pandey

Reputation: 59

OpenGL: glDrawElements gives unhandled exception: System.AccessViolationException

Using OpenTK with VB.Net.

My render method:

 ' clear the screen
    GL.ClearColor(Color4.Purple)
    GL.Clear(ClearBufferMask.ColorBufferBit Or ClearBufferMask.DepthBufferBit)

    ' activate shader program and set uniforms
    shaderProgram.Use()
    projectionMatrix.Set(shaderProgram)

    ' bind vertex buffer and array objects
    vertexBuffer.Bind()
    vertexArray.Bind()

    ' upload vertices to GPU and draw them
    vertexBuffer.BufferData()
    vertexArray.enableAll()
    vertexBuffer.Draw()

    ' reset state for potential further draw calls (optional, but good practice)
    vertexArray.DisableAll()
    GL.BindVertexArray(0)
    GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0)
    GL.BindBuffer(BufferTarget.ArrayBuffer, 0)
    GL.UseProgram(0)

    ' swap backbuffer
    SwapBuffers()

All these functions are abstracted and have the original gl{whatever} commands in them.(Yes, I shamelessly copied the code from here.)

My vertexbuffer's draw code:

Public Sub Bind()
    ' make this the active array buffer
    GL.BindBuffer(BufferTarget.ArrayBuffer, Me.handle)
End Sub

Public Sub BufferData()
    ' copy contained vertices to GPU memory
    GL.BufferData(BufferTarget.ArrayBuffer, New IntPtr(Me.vertexSize * Me.count), Me.vertices, BufferUsageHint.StreamDraw)
End Sub

Public Sub Draw()
    ' draw buffered vertices as triangles
    'GL.DrawArrays(PrimitiveType.Triangles, 0, Me.count)     <--commented
    GL.DrawElements(PrimitiveType.Triangles, 6, DrawElementsType.UnsignedInt, 0) '<--line 44
End Sub

This gives me the error:

Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. at OpenTK.Graphics.OpenGL.GL.DrawElements(PrimitiveType mode, Int32 count, DrawElementsType type, Int32 indices) at VertexBuffer`1.Draw() in C:\Users\Tushar\Desktop\genericgamedev-opentk-intro-master\vb\src\Ver texBuffer.vb:line 44

I read somewhere that you need to disable vertexarrays after each draw so I did that too but no avail. I saw this question but it didn't help me either(newbie).

Instead, using glDrawArrays in the draw method of vertex buffer renders perfectly.But I do not want to use glDrawArrays.

Public Sub Draw()
    ' draw buffered vertices as triangles
    GL.DrawArrays(PrimitiveType.Triangles, 0, count)
    ' commented line -->  GL.DrawElements(PrimitiveType.Triangles, 5, DrawElementsType.UnsignedInt, 0)
End Sub

Upvotes: 2

Views: 1237

Answers (1)

Tushar Pandey
Tushar Pandey

Reputation: 59

Got it!

Thanks to this gentleman:DeathByAlgorithm

glDrawElements requires you specify an index buffer, which my code was lacking. So I created a simple ibo wrapper:

Class IndexBuffer
    Private handle%
    Private data As UInteger()
    Sub New(ParamArray Indices As UInteger())
        handle = GL.GenBuffer()
        data = Indices
    End Sub
    Public Sub Bind()
        GL.BindBuffer(BufferTarget.ElementArrayBuffer, handle)
    End Sub
    Public Sub BufferData()
        GL.BufferData(Of UInteger)(BufferTarget.ElementArrayBuffer, CType(Marshal.SizeOf(New UInteger) * data.Length, System.IntPtr), data, BufferUsageHint.StaticDraw)
    End Sub
End Class

,made a field "indexbuffer" in the gamewindow class, and inititalised it:

indexbuffer = New IndexBuffer({0, 1, 2, 3, 4, 5})

then binded and buffered the data in the indexbuffer. My final render code:

        ' clear the screen
    GL.ClearColor(Color4.Purple)
    GL.Clear(ClearBufferMask.ColorBufferBit Or ClearBufferMask.DepthBufferBit)

    ' activate shader program and set uniforms
    shaderProgram.Use()
    projectionMatrix.Set(shaderProgram)

    ' bind vertex buffer and array objects
    vbo.Bind()
    vertexArray.Bind()
    indexbuffer.Bind()

    ' upload vertices to GPU and draw them
    vbo.BufferData()
    indexbuffer.BufferData()

    GL.EnableClientState(ArrayCap.VertexArray) 'works without this line

    vbo.Draw()

    ' reset state for potential further draw calls (optional, but good practice)
    GL.BindVertexArray(0)
    GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0)
    GL.BindBuffer(BufferTarget.ArrayBuffer, 0)
    GL.DisableClientState(ArrayCap.VertexArray) 'works without this line
    GL.UseProgram(0)

    ' swap backbuffer
    SwapBuffers()

Everything works now!

Upvotes: 2

Related Questions