2
\$\begingroup\$

I have found the following C++ code in this tutorial to draw a triangle with OpenGL 4:

float points[] = {
   0.0f,  0.5f,  0.0f,
   0.5f, -0.5f,  0.0f,
  -0.5f, -0.5f,  0.0f
};
GLuint vbo = 0;
glGenBuffers (1, &vbo);
glBindBuffer (GL_ARRAY_BUFFER, vbo);
glBufferData (GL_ARRAY_BUFFER, 9 * sizeof (float), points, GL_STATIC_DRAW);

I use C# and OpenTK, so I tried to translate the code:

        float[] points = 
        {
           0.0f,  0.5f,  0.0f,
           0.5f, -0.5f,  0.0f,
          -0.5f, -0.5f,  0.0f
        };
        uint[] vbo = {0};
        GL.GenBuffers(1, vbo);
        GL.BindBuffer(BufferTarget.ArrayBuffer, vbo[0]);
        GL.BufferData(BufferTarget.ArrayBuffer, 9 * sizeof(float), ppoints, BufferUsageHint.StaticDraw);

The problem is that GL.GenBuffers() and GL.BufferData() require pointers (Visual Studio shows *int or out int and ref float*, IntPtr).

I've tried to fix this, but it didn't work:

        float[] points = 
        {
           0.0f,  0.5f,  0.0f,
           0.5f, -0.5f,  0.0f,
          -0.5f, -0.5f,  0.0f
        };
        uint[] vbo = {0};
        GL.GenBuffers(1, vbo);
        GL.BindBuffer(BufferTarget.ArrayBuffer, vbo[0]);

        unsafe
        {
            fixed (float* ppoints = points)
            {
                GL.BufferData(BufferTarget.ArrayBuffer, 9 * sizeof(float), ppoints, BufferUsageHint.StaticDraw);
            }
        }

So my question is how to use these methods in a good C# style?

\$\endgroup\$
2
  • \$\begingroup\$ Have you tried simply adding the out and ref to the parameters in the function call (don't see you mentioning that in your question)? \$\endgroup\$ Commented Oct 7, 2014 at 14:26
  • \$\begingroup\$ Don't allocate a whole array just to return a single value! See my answer below. \$\endgroup\$ Commented Oct 7, 2014 at 15:07

1 Answer 1

5
\$\begingroup\$

The following code should work:

    var points = new float[] 
    {
       0.0f,  0.5f,  0.0f,
       0.5f, -0.5f,  0.0f,
      -0.5f, -0.5f,  0.0f
    };
    int vbo = GL.GenBuffer();
    GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);        
    GL.BufferData(BufferTarget.ArrayBuffer, points.Length * sizeof(float), points, BufferUsageHint.StaticDraw);

OpenTK provides three overloads for each method with typed pointers. For example:

const GLfloat* -> ref float, float[], float* (input)
      GLfloat* -> out float, float[], float* (output)
  1. Use ref/out float if you wish to pass/retrieve a single item.
  2. Use float[] if you wish to pass/retrieve an array of items.
  3. Use float* when writing unsafe code (e.g. a pointer to unmanaged memory or the stack).

Untyped pointers get the same overloads using generics:

const GLvoid* -> ref T, T[], IntPtr (input)
      GLvoid* -> out T, T[], IntPtr (output)

Starting with OpenTK 1.1, Gen* and Delete* methods get one additional overload, to simplify usage from F# (and similar functional languages). This is often the optimal approach:

int buffer = GL.GenBuffer();

Which is equivalent to the more verbose:

int buffer;
GL.GenBuffers(1, out buffer);

Note that unsigned types get both unsigned and signed overloads. For example, GLuint gets both uint and int overloads. The reason is that unsigned integers are not [CLS-Compliant][1] and cannot be used by all .Net languages (e.g. VB.Net). This is something to keep in mind if you are writing a public API to be consumed outside of C#.

[1] http://msdn.microsoft.com/en-us/library/12a7a7h3%28v=vs.110%29.aspx

\$\endgroup\$
9
  • \$\begingroup\$ Good explanations! But unfortunately this line does not work: GL.BufferData(BufferTarget.ArrayBuffer, points.Length * sizeof(float), points, BufferUsageHint.StaticDraw); I think it is, because points.Length * sizeof(float) is not an IntPtr !? \$\endgroup\$ Commented Oct 7, 2014 at 16:14
  • \$\begingroup\$ It works on opentk/develop (version 1.1.5+). For previous versions you need to use new IntPtr(...). \$\endgroup\$ Commented Oct 8, 2014 at 5:33
  • \$\begingroup\$ OK, but where can I download the develop version? I only find the stable release. \$\endgroup\$ Commented Oct 8, 2014 at 7:27
  • \$\begingroup\$ You can download the latest code from github. Simply double-click OpenTK.sln and build in release mode. v1.1.5 will be released this week. \$\endgroup\$ Commented Oct 8, 2014 at 8:54
  • \$\begingroup\$ In the Version.txt stand 1.1.1741.0, not 1.1.5? I have downloaded the ZIP from the link above. \$\endgroup\$ Commented Oct 8, 2014 at 10:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .