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);
    }
}
```

Reply via email to