views:

222

answers:

2

Please excuse the length (and the width; it's for clarity on an IDE) but I thought of showing the full length of the code since the purpose is a simple Hello World in modern VBO and GLSL.

It was initially based on http://people.freedesktop.org/~idr/OpenGL_tutorials/02-GLSL-hello-world.pdf

The main point is no single error message or warning is printed - and you can see the printfs are a lot (actually, almost all of the code is attempted to be caught for errors).

The compilation is done on -std=c99 -pedantic -O0 -g -Wall (with no warnings) so no much room for compiler error either.

I have pin pointed my attention to

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

and

glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));

(the latter is the only part of the code I don't fully understand yet; most obscure func 'ever')

The info log does not print anything and it does print a healthy text normally if the shaders are purposely made invalid. Hence it's neither the shaders string assignment or their compilation.

Can you see something that could make it print a blank screen?

It does print a single dot in the middle if glDrawArrays is used with GL_POINTS and it does change color if glClear is preceded with an appropriate glClearColor.

#include "SDL.h" // Window and program management
#include "Glee.h" // OpenGL management; Notice SDL's OpenGL header is not included
#include <stdbool.h> // C99 bool

void initGL(void);
void drawGL(void);

int main (int argc, char **argv) {

    //  Load the SDL library; Initialize the Video Subsystem
    if (SDL_Init(SDL_INIT_VIDEO) < 0 ) printf("SDL_Init fail: %s\n", SDL_GetError()); 

    /*  Video Subsystem: set up width, height, bits per pixel (0 = current display's);
        Create an OpenGL rendering context */
    if (SDL_SetVideoMode(800, 600, 0, SDL_OPENGL) == NULL) printf("SDL_SetVideoMode fail: %s\n", SDL_GetError()); 

    // Title and icon text of window
    SDL_WM_SetCaption("gl", NULL);

    // Initialize OpenGL ..
    initGL();

    bool done = false;

    // Loop indefinitely unless user quits
    while (!done) { 

        // Draw OpenGL ..
        drawGL();

        // Deal with SDL events
        SDL_Event sdl_event;
        do {
            if (    sdl_event.type == SDL_QUIT || (sdl_event.type == SDL_KEYDOWN && sdl_event.key.keysym.sym == SDLK_ESCAPE)) {
                    done = true;
                    break;
            }
        } while (SDL_PollEvent(&sdl_event));    

    }

    // Clean SDL initialized systems, unload library and return.
    SDL_Quit(); 
    return 0;
}

GLuint program;
GLuint buffer;
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
void initGL(void) {

    // Generate 1 buffer object; point its name (in uint form) to *buffer. 
    glGenBuffers(1, &buffer);       if(glGetError()) printf("glGenBuffers error\n");

    /*  bind the named (by a uint (via the previous call)) buffer object to target GL_ARRAY_BUFFER (target for vertices)
        apparently, one object is bound to a target at a time. */
    glBindBuffer(GL_ARRAY_BUFFER, buffer);      if(glGetError()) printf("glBindBuffer error\n");

    /*  Create a data store for the current object bound to GL_ARRAY_BUFFER (from above), of a size 8*size of GLfloat,
        with no initial data in it (NULL) and a hint to the GrLib that data is going to be modified once and used a 
        lot (STATIC), and it's going to be modified by the app and used by the GL for drawing or image specification (DRAW)
        Store is not mapped yet. */
    glBufferData(   GL_ARRAY_BUFFER, 4 * 2 * sizeof(GLfloat), NULL, GL_STATIC_DRAW);            if(glGetError()) printf("glBufferData error\n");

    /*  Actually map to the GL client's address space the data store currently bound to GL_ARRAY_BUFFER (from above). 
        Write only. */
    GLfloat *data = (GLfloat *) glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);            if (!*data) printf("glMapBuffer error1\n"); if(glGetError()) printf("glMapBuffer error2\n");

    // Apparently, write some data on the object.
    data[0] = -0.75f;   data[1] = -0.75f;   data[2] = -0.75f;   data[3] =  0.75f;
    data[4] =  0.75f;   data[5] =  0.75f;   data[6] =  0.75f;   data[7] = -0.75f;

    // Unmap the data store. Required *before* the object is used.
    if(!glUnmapBuffer(GL_ARRAY_BUFFER)) printf("glUnmapBuffer error\n");

    // Specify the location and data format of an array of generic vertex attributes ..
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));

    // the shaders source
    GLchar *vertex_shader_code[] =      {   "void main(void) { gl_Position = gl_Vertex; }"};
    GLchar *fragment_shader_code[] =        {   "void main(void) { gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); }"};

    /*  Create an empty shader object; used to maintain the source string; intended to run 
        on the programmable vertex processor; GL_SHADER_TYPE is set to  GL_VERTEX_SHADER 
        (e.g. for use on glGetShaderiv)*/
    GLuint vs = glCreateShader(GL_VERTEX_SHADER);           if (!vs) printf("glCreateShader fail\n");

    /*  Set the source code in vs; 1 string; GLchar **vertex_shader_code array of pointers to strings,
        length is NULL, i.e. strings assumed null terminated     */
    glShaderSource(vs, 1, (const GLchar **) &vertex_shader_code, NULL);             if(glGetError()) printf("glShaderSource error\n");

    // Actually compile the shader
    glCompileShader(vs);            GLint compile_status;   glGetShaderiv(vs, GL_COMPILE_STATUS, &compile_status); if (compile_status == GL_FALSE) printf("vertex_shader_code compilation fail\n"); if(glGetError()) printf("glGetShaderiv fail\n");

    // same
    GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);         if (!fs) printf("glCreateShader fail\n");

    // same
    glShaderSource(fs, 1, (const GLchar **) &fragment_shader_code, NULL);           if(glGetError()) printf("glShaderSource error\n");

    // same
    glCompileShader(fs);            glGetShaderiv(fs, GL_COMPILE_STATUS, &compile_status);  if (compile_status == GL_FALSE) printf("fragment_shader_code compilation fail\n"); if(glGetError()) printf("glGetShaderiv fail\n");

    /*  Empty program for later attachment of shaders; it provides management mechanism for them.
        Shaders can be compiled before or after their attachment. */
    program = glCreateProgram();            if(!program) printf("glCreateProgram fail1\n"); if(glGetError()) printf("glCreateProgram fail2\n");

    /*  Attach shaders to program; this could be done before their compilation or their association with code
        Destined to be linked together and form an executable. */
    glAttachShader(program, vs);            if(glGetError()) printf("glAttachShader fail1\n");
    glAttachShader(program, fs);            if(glGetError()) printf("glAttachShader fail2\n");

    //  Link the program; vertex shader objects create an executable for the vertex processor and similarly for fragment shaders.
    glLinkProgram(program);             GLint link_status; glGetProgramiv(program, GL_LINK_STATUS, &link_status); if (!link_status) printf("linking fail\n"); if(glGetError()) printf("glLinkProgram fail\n");

    /*  Get info log, if any (supported by the standard to be empty).
        It does give nice output if compilation or linking fails. */
    GLchar infolog[2048];
    glGetProgramInfoLog(program, 2048, NULL, infolog); printf("%s", infolog); if (glGetError()) printf("glGetProgramInfoLog fail\n");

    /*  Install program to rendering state; one or more executables contained via compiled shaders inclusion. 
        Certain fixed functionalities are disabled for fragment and vertex processors when such executables
        are installed, and executables may reimplement them. See glUseProgram manual page about it. */
    glUseProgram(program);      if(glGetError()) printf("glUseProgram fail\n");
}


void drawGL(void) {
    // Clear color buffer to default value
    glClear(GL_COLOR_BUFFER_BIT);       if(glGetError()) printf("glClear error\n");

    // Render the a primitive triangle 
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);      if(glGetError()) printf("glDrawArrays error\n");

    SDL_GL_SwapBuffers();
}
+2  A: 
  • In the vertex shader : gl_Position = ftransform(); instead of gl_Vertex. This will multiply the input vector by the modelview matrix (giving the point in camera space) and then by the transformation matrix (giving the point in normalized device coordinates, i.e. its position on the screen)
  • glEnable(GL_VERTEX_ARRAY); before the rendering. cf the glDrawArray reference : "If GL_VERTEX_ARRAY is not enabled, no geometric primitives are generated."

... I don't see anything else

Calvin1602
1st doesn't alter the outcome; 2nd segfaults it (if it's either before glDrawArrays or at the end of init). The backtrace has no code after 4 steps after drawGL().
Lela Dax
+3  A: 

Expanding on Calvin1602's answer:

ftransform supposes matrices, which you do not use. gl_Vertex ought to be fine here, considering the final result is supposed to be the [-1:1]^3 cube, and his data is in that interval. Now, it should be gl_VertexAttrib[0] if you really want to go all GL3.1, but gl_Vertex and gl_VertexAttrib[0] alias(see below).

As for the enable. You use vertex attrib 0, so you need:

glEnableVertexAttribArray(0)

An advice on figuring stuff out in general: don't clear to black, it makes life more difficult to figure out if something black is drawn or if nothing is drawn (use glClearColor to change that).

On the pedantic side, your glShaderSource calls look suspicious, as you cast pointers around. I'd clean it up with

glShaderSource(fs, 1, fragment_shader_code, NULL);

The reason why it currently work with &fragment_shader_code is interesting, but here, I don't see why you don't simplify.

== edit to add ==

Gah, not sure what I was thinking with gl_VertexAttrib. It's been a while I did not look at this, and I just made my own feature...

The standard way to provide non-built-in attributes is actually non-trivial until GL4.1.

// glsl
attribute vec4 myinput;
gl_Position = myinput;

// C-code, rely on linker for location
glLinkProgram(prog);
GLint location = glGetAttribLocation(prog, "myinput");
glEnableVertexAttribArray(location, ...)

// alternative C-code, specify location
glBindAttribLocation(prog, 0, "myinput");
glLinkProgram(prog);
glEnableVertexAttribArray(0, ...)

GL4.1 finally supports specifying the location directly in the shader.

// glsl 4.10
layout (location=0) in vec4 myinput;
Bahbar
oh yeah, glEnableVertexAttribArray. And you definitely should use matrices. Not using them makes the code smaller but not simpler (to understand, at least).
Calvin1602
thanks a lot for the input; the glEnableVertexAttribArray(0) inclusion is spot on and it made it render the shape. thanks for the advice on Clearing, I also don't like stuff that aren't necessary. gl_VertexAttrib[0] does not appear to be recognized by the driver compiler '0(1) : error C1008: undefined variable "gl_VertexAttrib"' in brackets or in parentheses form. The weird array for a string came naturally, don't ask why, I probably read a lot on pointers.
Lela Dax
[edit time passed] I suspect that's because of the context being from SDL1.2 (concerning gl_VertexAttrib).
Lela Dax