Rendering a simple rectangle with OpenGL 3 in D language
Asked Answered
A

1

12

I'm going insane because I can't make a simple set of triangles appear in my screen.

I'm using OpenGL3 (without the deprecated fixed pipeline) using the derelict bindings for the D programming language.

Can you spot the error in the following program? It compiles just fine and doesn't throw any OpenGL/GLSL error. It just shows a blank screen with the clear color I set.

import std.string;
import std.conv;
import derelict.opengl3.gl3;
import derelict.sdl2.sdl2;

immutable string minimalVertexShader = `
#version 120
attribute vec2 position;
void main(void)
{
    gl_Position = vec4(position, 0, 1);
}
`;

immutable string minimalFragmentShader = `
#version 120
void main(void)
{
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;

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

    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        throw new Exception("Failed to initialize SDL: " ~ to!string(SDL_GetError()));
    }

    // Set OpenGL version
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);

    // Set OpenGL attributes
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);

    auto sdlwindow = SDL_CreateWindow("D App",
        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        640, 480, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);

    if (!sdlwindow)
        throw new Exception("Failed to create a SDL window: " ~ to!string(SDL_GetError()));

    SDL_GL_CreateContext(sdlwindow);
    DerelictGL3.reload();

    float[] vertices = [ -1, -1,  1, -1,  -1, 1,  1, 1];
    ushort[] indices = [0, 1, 2, 3];
    uint vbo, ibo;
    // Create VBO
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, vertices.sizeof, vertices.ptr, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // Create IBO
    glGenBuffers(1, &ibo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.sizeof, indices.ptr, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    // Program
    auto program = glCreateProgram();
    // Vertex Shader
    auto vsh = glCreateShader(GL_VERTEX_SHADER);
    auto vshSrc = minimalVertexShader.toStringz;
    glShaderSource(vsh, 1, &vshSrc, null);
    glCompileShader(vsh);
    glAttachShader(program, vsh);
    // Fragment Shader
    auto fsh = glCreateShader(GL_FRAGMENT_SHADER);
    auto fshSrc = minimalFragmentShader.toStringz;
    glShaderSource(fsh, 1, &fshSrc, null);
    glCompileShader(fsh);
    glAttachShader(program, fsh);

    glLinkProgram(program);
    glUseProgram(program);

    auto position = glGetAttribLocation(program, "position");
    auto run = true;

    while (run) {
        SDL_Event event;
        while (SDL_PollEvent(&event)) {
            switch (event.type) {
                case SDL_QUIT:
                    run = false;
                default:
                    break;
            }
        }

        glClearColor(1, 0.9, 0.8, 1);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glEnableVertexAttribArray(position);
        glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, vertices.sizeof, null);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
        glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, null);
        glDisableVertexAttribArray(position);

        SDL_GL_SwapWindow(sdlwindow);
    }
}
Austronesian answered 6/3, 2012 at 4:11 Comment(4)
I can't tell you right off what the problem is, but it will almost certainly help if you actually check for OpenGL errors by using glGetError(). Check out the enforce function in std.exception and how it uses a lazy parameter--you could adapt it to an enforceGL() function to make it easier to catch OpenGL errors.Saire
I made a version of this code where I checked every gl call with a assert(glGetError() == 0); line... Nothing raised an error.Austronesian
Why are you reloading Derelict? :oEstrus
Hi Jeroen, I'm reloading Derelict in order to create a GL3 context. It's the way to do that apparently.Austronesian
S
14

On this line:

glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, vertices.sizeof, null);

are you sure that you want vertices.sizeof, which has a value of 16? In D, a dynamic array is a struct with two members (ptr and length). You probably want either float.sizeof or float.sizeof * 2.

And the same goes for your BufferData calls.

Saire answered 7/3, 2012 at 0:56 Comment(4)
Thanks for the answer! I changed the declaration to make them static arrays (I thought as they were defined with a literal they will be static) and now .sizeof is 32 (length * float.sizeof) for vertices and 8 for indices. But still I don't get anything drawn. :(Austronesian
Oh wait, you're awesome. I replaced vertices.sizeof with vertices.length * float.sizeof in the glBufferData call, the same with indices. But in glVertexAttribPointer I needed 2 * float.sizeof as the stride parameter. It works!! Thank you!Austronesian
@SantiagoV. Hey, I was able to use your example to help get me started(not using sdl). I know this is old but when I did it, I just a window that was colored... as if the triangle was way bigger than the window. Have any ideas on that?Arcuate
@Arcuate sorry, didn't see your question... from what I see of my code, there's no projection or view matrix, so probably yeah, the rectangle is the size of the window.Austronesian

© 2022 - 2024 — McMap. All rights reserved.