Using OpenGL

Mike Parker via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sat Sep 3 09:01:34 PDT 2016


On Saturday, 3 September 2016 at 12:40:58 UTC, Darren wrote:

>
> I went through another tutorial. Changed the source code and 
> left out the shaders.  I get another coloured background but 
> still no triangle.  I have a feeling that
>
>     glBufferData(GL_ARRAY_BUFFER, 
> cast(int)g_vertex_buffer_data.sizeof,
>                  cast(void*)g_vertex_buffer_data, 
> GL_STATIC_DRAW);

Your vertices array is declared as a dynamic array. That means 
vertices.sizeof gives you the size of the *array reference*, not 
the data it contains. For a static array, you get the cumulative 
size of the data. See my changes in the code below.


> (In the first line, glBufferData wants an int, and .sizeof 
> returns a uint, apparently.)

That's irrelevant in this case. But sizeof is size_t, which is 
uint on 32-bit systems and long on 64-bit systems.

>
> I'm sure there's something simple I'm missing but I just don't 
> have the experience to recognise it.

The following compiles, runs, and shows the triangle. It's the 
code you posted above with the corrected call to glBufferData 
along with more D style (as I would write it anyway) and less C. 
Comments are inline. Probably best if you copy and paste it into 
an editor.

```
import std.stdio,
        std.format;
import derelict.glfw3.glfw3;
import derelict.opengl3.gl3;

// Match the Derelict decleration of GLFW callbacks
// 
https://github.com/DerelictOrg/DerelictGLFW3/blob/master/source/derelict/glfw3/types.d#L319
extern(C) nothrow {
     // Setting an error handler will let you get better error 
messages from GLFW
     // when something fails.
     // 
http://www.glfw.org/docs/latest/intro_guide.html#error_handling
     void onError(int error, const(char)* msg) {
         import std.conv : to;
         try {
             // The callback is nothrow, but format is not, so the
             // try...catch
             errMsg = format("GLFW Error #%s: %s", error, 
to!string(msg));
         }
         catch(Exception e) {}
     }
     void key_callback(GLFWwindow* window, int key, int scancode, 
int action, int mode) {
         if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
             glfwSetWindowShouldClose(window, GL_TRUE);
     }
}

// This will save the error message from the callback
private auto errMsg = "No Error";

// Use manifest constants rather than const
// https://dlang.org/spec/enum.html#manifest_constants
enum WIDTH = 800;
enum HEIGHT = 600;

// Rather than using multiple string literals with manual 
newlines, use
// WYSIWYG strings as manifest constants. Looks cleaner (but 
requires an
// extra step when calling glShaderSource).
enum vertexShaderSource =
`#version 330 core
layout (location = 0) in vec3 position;
void main()
{
gl_Position = vec4(position.x, position.y, position.z, 1.0);
}`;
enum fragmentShaderSource =
`#version 330 core
out vec4 color;
void main()
{
color = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}`;

void main()
{
     DerelictGLFW3.load();
     DerelictGL3.load();

     // Set the error callback before calling glfwInit so that a 
useful message
     // can be reported on failure
     glfwSetErrorCallback(&onError);

     // Always check for failure
     if(!glfwInit()) throw new Exception("Failed to init GLFW: " ~ 
errMsg);

     // Ensure that glfwTerminate is called even when an exception 
is thrown
     scope(exit) glfwTerminate();

     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
     glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
     glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
     // Optonal: Remove deprecated functionality
     glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, 1);
     glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

     // Always check for failure
     GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, 
"LearnOpenGL", null, null);
     if(!window) throw new Exception("Failed to create window");

     glfwMakeContextCurrent(window);

     DerelictGL3.reload();

     glfwSetKeyCallback(window, &key_callback);

     int width, height;
     glfwGetFramebufferSize(window, &width, &height);
     glViewport(0, 0, width, height);

     GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);

     // Because I switched the shader source to D strings, a 
slight adjustment
     // is needed here:
     const(char)* srcPtr = vertexShaderSource.ptr;
     glShaderSource(vertexShader, 1, &srcPtr, null);
     glCompileShader(vertexShader);

     GLint result;

     // Use dynamic arrays for the info logs so that you can always
     // ensure you have enough room. And throw exceptions on 
failure.
     glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &result);
     if (!result) {
         glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &result);
         auto infoLog = new char[](result);
         glGetShaderInfoLog(vertexShader, 512, null, infoLog.ptr);
         throw new Exception(format("Failed to compile vertex 
shader:\n\t%s", infoLog));
     }

     GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
     srcPtr = fragmentShaderSource.ptr;
     glShaderSource(fragmentShader, 1, &srcPtr, null);
     glCompileShader(fragmentShader);

     glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &result);
     if (!result) {
         glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &result);
         auto infoLog = new char[](result);
         glGetShaderInfoLog(vertexShader, 512, null, infoLog.ptr);
         throw new Exception(format("Failed to compile fragment 
shader:\n\t%s", infoLog));
     }

     GLuint shaderProgram = glCreateProgram();
     glAttachShader(shaderProgram, vertexShader);
     glAttachShader(shaderProgram, fragmentShader);
     glLinkProgram(shaderProgram);

     glGetProgramiv(shaderProgram, GL_LINK_STATUS, &result);
     if (!result) {
         glGetProgramiv(shaderProgram, GL_LINK_STATUS, &result);
         auto infoLog = new char[](result);
         glGetProgramInfoLog(shaderProgram, 512, null, 
infoLog.ptr);
         throw new Exception(format("Failed to link shader 
program:\n\t%s", infoLog));
     }
     glDeleteShader(vertexShader);
     glDeleteShader(fragmentShader);

     GLfloat[] vertices = [
         -0.5f, -0.5f, 0.0f,
          0.5f, -0.5f, 0.0f,
          0.0f,  0.5f, 0.0f
     ];
     GLuint VBO, VAO;
     glGenVertexArrays(1, &VAO);
     glGenBuffers(1, &VBO);

     // Ensure these objects are always deleted on exit
     scope(exit) {
         glDeleteVertexArrays(1, &VAO);
         glDeleteBuffers(1, &VBO);
     }
     glBindVertexArray(VAO);
     glBindBuffer(GL_ARRAY_BUFFER, VBO);

     // You've declared vertices as a dynamic array, not a static 
array, so
     // vertices.sizeof is *not* going to give you the result you 
want -- it's
     // giving you the size of an array reference. To get the size 
of the data,
     // you need to use vertices.length * float.sizeof (which is 
always 4, so you
     // could use that instead).
     glBufferData(GL_ARRAY_BUFFER, vertices.length * float.sizeof, 
vertices.ptr, GL_STATIC_DRAW);

     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * 
GLfloat.sizeof, cast(GLvoid*)0);
     glEnableVertexAttribArray(0);

     // No need for this in this simple program, where you only 
have one VAO and
     // one VBO. Just leave them bound. You only need to reset 
when you are using
     // multiple buffers.
/*
     glBindBuffer(GL_ARRAY_BUFFER, 0);
     glBindVertexArray(0);
*/
     while (!glfwWindowShouldClose(window)) {
         glfwPollEvents();
         glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
         glClear(GL_COLOR_BUFFER_BIT);
         glUseProgram(shaderProgram);
         //glBindVertexArray(VAO);
         glDrawArrays(GL_TRIANGLES, 0, 3);
         //glBindVertexArray(0);
         glfwSwapBuffers(window);
     }
}
```



More information about the Digitalmars-d-learn mailing list