September 03, 2016
On Saturday, 3 September 2016 at 11:02:11 UTC, Lodovico Giaretta wrote:

>
> glGetShaderInfoLog(vertexShader, 512, null, &infoLog[0]);

I prefer:

 glGetShaderInfoLog(vertexShader, 512, null, infoLog.ptr);
September 03, 2016
On Saturday, 3 September 2016 at 11:33:10 UTC, Mike Parker wrote:
> On Saturday, 3 September 2016 at 11:02:11 UTC, Lodovico Giaretta wrote:
>
>>
>> glGetShaderInfoLog(vertexShader, 512, null, &infoLog[0]);
>
> I prefer:
>
>  glGetShaderInfoLog(vertexShader, 512, null, infoLog.ptr);

That is a good tip to know.

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

in one example, or

    glBufferData(GL_ARRAY_BUFFER, vertices.sizeof, cast(void*)vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * GLfloat.sizeof, cast(GLvoid*)0);

in the other might be responsible, since they seem to be related to drawing the triangle and I'm casting arguments in order to get the program to compile.
(In the first line, glBufferData wants an int, and .sizeof returns a uint, apparently.)

I'm sure there's something simple I'm missing but I just don't have the experience to recognise it.
September 03, 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);
    }
}
```

September 03, 2016
On Saturday, 3 September 2016 at 16:01:34 UTC, Mike Parker wrote:

> 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.

One thing I overlooked. In lines where a variable is both declared and initialized, like this one:
GLFWwindow* window = glfwCreateWindow(...);

I normally let the compiler use type inference as I did in the manifest constant declarations:
auto window = glfwCreateWindow(...);

IMO, when you're dealing with long or ugly type names, it makes the code look cleaner.

September 03, 2016
On Saturday, 3 September 2016 at 16:07:52 UTC, Mike Parker wrote:
> On Saturday, 3 September 2016 at 16:01:34 UTC, Mike Parker wrote:
>
>> 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.
>

The dynamic array!  Thank you so much, I changed that on another file and it finally drew the triangle.  And I ran your code and it works brilliantly.  I should now be in a comfortable position to digest all this information now.  Can't thank you enough.

> One thing I overlooked. In lines where a variable is both declared and initialized, like this one:
> GLFWwindow* window = glfwCreateWindow(...);
>
> I normally let the compiler use type inference as I did in the manifest constant declarations:
> auto window = glfwCreateWindow(...);
>
> IMO, when you're dealing with long or ugly type names, it makes the code look cleaner.

Yeah, it is nicer to read.

Now I wonder if I can load shaders from separate files (à la http://www.opengl-tutorial.org/beginners-tutorials/tutorial-2-the-first-triangle/).
September 05, 2016
On Saturday, 3 September 2016 at 17:13:49 UTC, Darren wrote:
> On Saturday, 3 September 2016 at 16:07:52 UTC, Mike Parker wrote:
>>[...]
>
> The dynamic array!  Thank you so much, I changed that on another file and it finally drew the triangle.  And I ran your code and it works brilliantly.  I should now be in a comfortable position to digest all this information now.  Can't thank you enough.
>
>> [...]
>
> Yeah, it is nicer to read.
>
> Now I wonder if I can load shaders from separate files (à la http://www.opengl-tutorial.org/beginners-tutorials/tutorial-2-the-first-triangle/).

see:

https://p0nce.github.io/d-idioms/#Embed-a-dynamic-library-in-an-executable

for `import`ing external files at compile time.
September 05, 2016
On Monday, 5 September 2016 at 05:14:56 UTC, Nicholas Wilson wrote:
> On Saturday, 3 September 2016 at 17:13:49 UTC, Darren wrote:
>>
>> Now I wonder if I can load shaders from separate files (à la http://www.opengl-tutorial.org/beginners-tutorials/tutorial-2-the-first-triangle/).
>
> see:
>
> https://p0nce.github.io/d-idioms/#Embed-a-dynamic-library-in-an-executable
>
> for `import`ing external files at compile time.

It's often useful to be able to reload shaders at runtime.
September 14, 2016
Kind of resurrecting this thread; hope that's okay.

I'm working through this tutorial: http://www.learnopengl.com/#!Getting-started/Textures

It uses SOIL to load images, but I haven't seen any SOIL bindings in dub.  I tried using SDL and SDL_Image but when the program ran it just crashed.  I guess I was doing something wrong.

While googling, the idea seemed to be to create and SDL_Surface* and pass that (or surface.pixels) as the last argument for glTexImage2D.  Didn't work for me, however.

Does anyone have any tips?
September 15, 2016
On Wednesday, 14 September 2016 at 16:49:51 UTC, Darren wrote:

>
> While googling, the idea seemed to be to create and SDL_Surface* and pass that (or surface.pixels) as the last argument for glTexImage2D.  Didn't work for me, however.
>
> Does anyone have any tips?

I'm driving blind here without any of your code to see, but here's some general advice.

The last three arguments to glTexImage2D [1] are what you use to describe the image data you are sending to it (aside from 'width' & 'height', which also set the size of the texture being created).

`format` needs to match the format of your image. For most simple things you do with OpenGL, that's going to be GL_RGB or GL_RGBA. If you don't know the format of your image, you can get it from the SDL_PixelFormatEnum value [2] in surface.format.format. Then you'll just need to send the corresponding GL enum to glTexImage2D. Though, be aware that the way SDL and OGL treat color formats may not always correspond in the way you think they should [3].

`type` is almost always going to be GL_UNSIGNED_BYTE. I don't know that SDL_image supports anything else, like floating point formats, anyway.

`data` needs to be a pointer to the pixel data and nothing else (never SDL_Surface!), so in this case surface.pixels is correct.

If you are getting a crash, check the return of any of the image loading functions you call to make sure the load was successful. That's the first place I'd check.

[1] https://www.opengl.org/sdk/docs/man/html/glTexImage2D.xhtml
[2] https://wiki.libsdl.org/SDL_PixelFormatEnum
[3] https://bugzilla.libsdl.org/show_bug.cgi?id=2111
September 15, 2016
On Thursday, 15 September 2016 at 02:11:03 UTC, Mike Parker wrote:
> //snip

Okay the crashing was my fault, more or less a copy-paste error.  The program now runs but has a black rectangle where a texture should be.

This is the code I'm using: https://dfcode.wordpress.com/2016/09/15/texcodewip/
(The code for the shaders is at the bottom)

For comparison, this is the code I'm trying to make work:
http://www.learnopengl.com/code_viewer.php?code=getting-started/textures