luca-piccioni / OpenGL.Net

Modern OpenGL bindings for C#.
MIT License
578 stars 110 forks source link

memory access violation with Gl.DrawArrays but not with Gl.Begin/Gl.End #32

Closed ghost closed 7 years ago

ghost commented 7 years ago

Installed OpenGL.Net version: 0.3.2

The following code causes memory protection fault (but not always):

        vertexList.Add(cell.gridPoint.x - offset); vertexList.Add(cell.gridPoint.y - offset);       //  bl
        vertexList.Add(cell.gridPoint.x - offset); vertexList.Add(cell.gridPoint.y + offset);       //  tl
        vertexList.Add(cell.gridPoint.x + offset); vertexList.Add(cell.gridPoint.y + offset);       //  tr

        vertexList.Add(cell.gridPoint.x - offset); vertexList.Add(cell.gridPoint.y - offset);       //  bl
        vertexList.Add(cell.gridPoint.x + offset); vertexList.Add(cell.gridPoint.y - offset);       //  br
        vertexList.Add(cell.gridPoint.x + offset); vertexList.Add(cell.gridPoint.y + offset);       //  tr

        var vertexArray = vertexList.ToArray();
        using (MemoryLock vertexArrayLock = new MemoryLock(vertexArray))
        {
            Gl.VertexPointer(2, VertexPointerType.Float, 0, vertexArrayLock.Address);
            Gl.EnableClientState(EnableCap.VertexArray);

            Gl.DrawArrays(PrimitiveType.Triangles, 0, vertexArray.Length);
        }

The following code works fine:

    Gl.Begin(PrimitiveType.Triangles);
    Gl.Vertex2(cell.gridPoint.x - offset, cell.gridPoint.y - offset);
    Gl.Vertex2(cell.gridPoint.x - offset, cell.gridPoint.y + offset);
    Gl.Vertex2(cell.gridPoint.x + offset, cell.gridPoint.y + offset);

    Gl.Vertex2(cell.gridPoint.x - offset, cell.gridPoint.y - offset);
    Gl.Vertex2(cell.gridPoint.x + offset, cell.gridPoint.y - offset);
    Gl.Vertex2(cell.gridPoint.x + offset, cell.gridPoint.y + offset);
    Gl.End();

When the faulty code does not crash, from some point on massive visual artifacts appear.

Please check the attached project conway-set.zip .

luca-piccioni commented 7 years ago

At the first sight everything seems correct: 6 vec2 elements for 2 triangles, packed into an array of floats.

The vanilla example is running correctly on your machine?

luca-piccioni commented 7 years ago

I was able to reproduce the problem, and actually I solved it with few actions.

First, you should really care about the overload of the function you use. For example, Gl.Ortho(-1, 1, -aspect, aspect, 0, 1); will select the glOrthof function, which is a GL ES 1 function. The correct overload is glOrtho(double,double,double,double,double,double); indeed the correct code is Gl.Ortho(-1.0, 1.0, (double)-aspect, (double)aspect, 0.0, 1.0);. Sadly, the function call throws an AccessViolationException: quite strange. Indeed I worked around it by playing with LoadMatrix:

OrthoProjectionMatrix projectionMatrix = new OrthoProjectionMatrix(-1.0f / this.scale, 1.0f / this.scale, -aspect / this.scale, aspect / this.scale, 0.0f, 1.0f);
Gl.LoadMatrix(projectionMatrix.ToArray());

The next exception if the one you described: InvalidAccessExceptionat Gl.DrawArrays. I converted the list in List<Vertex2f>: from that point the program is currently working without exceptions.

List<Vertex2f> vertexList = new List<Vertex2f>();

vertexList.Add(new Vertex2f(cell.gridPoint.x - offset, cell.gridPoint.y - offset));       //  bl
vertexList.Add(new Vertex2f(cell.gridPoint.x - offset, cell.gridPoint.y + offset));       //  tl
vertexList.Add(new Vertex2f(cell.gridPoint.x + offset, cell.gridPoint.y + offset));       //  tr

vertexList.Add(new Vertex2f(cell.gridPoint.x - offset, cell.gridPoint.y - offset));       //  bl
vertexList.Add(new Vertex2f(cell.gridPoint.x + offset, cell.gridPoint.y - offset));       //  br
vertexList.Add(new Vertex2f(cell.gridPoint.x + offset, cell.gridPoint.y + offset));       //  tr

That changes the .Length property, specifying the correct number of elements to draw (i.e. 6 for 2 triangles, not 12).

At the end, cool animation.

luca-piccioni commented 7 years ago

Another note on glOrthocall: avoid calling directly on SizeChangedevent handler before ContextCreatedevent handler is run (that's the behavior on my machine, running NVIDIA/Intel driver). Probably the driver suppose a context created and current for calling Gl.Ortho, and glControl_SizeChanged is called one time before glControl_ContextCreated.

ghost commented 7 years ago

Grazie mille :) Yep, the trick is to use Vertex2f instead of plain float. I am quite new to OpenGL and am focusing on the cool animation (thank you :) ). So I used mainly online opengl examples in cpp and there was no mentioning of Vertex2f :) Thanks for the cool project, it saved me lots of time! Good luck!

luca-piccioni commented 7 years ago

Well, you can still use float[]arrays as vertex arrays: it is sufficient to pass the correct vertex elements count to Gl.DrawArrays (in your case Array.Length / 2). The use of Vertex2f structure it's just a way to be explicit on the vertex input format, making the code more elegant and readable.

Vertex* structures are very specific to this library, but they are complete and very useful for passing simple vertex attributes to OpenGL.

ghost commented 7 years ago

Yes, they surely are :)