0
votes

All the tutorials seem to indicate that I am doing things correctly, the vertex shader works, however it fails to recognize any input changes from the main program through the use of the glUniform1f function. I check glGetError after each line, there are no errors. I check glGetShaderiv and glGetShaderInfoLog, there are no issues. I am testing with OpenGL version 2.1 (unknown profile, but assuming the core profile) as reported by SDL.

#if defined(__WINDOWS__) || defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__TOS_WIN__)\
    || defined(__CYGWIN__)
    /* Compiling for Windows */
    #ifndef __WINDOWS__
        #define __WINDOWS__
    #endif
    #include <windows.h>
#endif/* Predefined Windows macros */

#include <SDL2/SDL.h>
#include <GL/GL.h>
#include <stdlib.h>
#include <stdio.h>
#include <error.h>

//return type not verified
void glGenBuffers();
void glBindBuffer();
void glBufferData();
unsigned int glCreateShader();
void glShaderSource();
void glCompileShader();
void glGetShaderiv();
void glGetShaderInfoLog();
unsigned int glCreateProgram();
void glAttachShader();
void glLinkProgram();
void glGetProgramiv();
void glGetProgramInfoLog();
void glVertexAttribPointer();
void glEnableVertexAttribArray();
void glUseProgram();
void glDeleteShader();
void glGenVertexArrays();
void glBindVertexArray();
GLint glGetUniformLocation();
void glUniform1f();
void glDeleteProgram();
void glDeleteBuffers();

int fixSDLconsole() {
    FILE *console = freopen("stdout.txt", "a",stdout);
    if (console == NULL) {return errno;}
    console = freopen("stdout.txt", "a",stderr);
    if (console == NULL) {return errno;}
    return 0;
}
void printGLVersionNumber() {
    int majorVersion;
    int minorVersion;
    int profile;
    SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &majorVersion);
    SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minorVersion);
    SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile);
    fprintf(stderr,"GL version %d.%d ",majorVersion,minorVersion);
    switch (profile) {
        case SDL_GL_CONTEXT_PROFILE_CORE: fprintf(stderr,"core (%d)\n",profile);break;
        case SDL_GL_CONTEXT_PROFILE_COMPATIBILITY: fprintf(stderr,"compatibility (%d)\n",profile);break;
        case SDL_GL_CONTEXT_PROFILE_ES: fprintf(stderr,"E.S. (%d)\n",profile);break;
        default: fprintf(stderr, "unknown profile: %d\n",profile);break;
    }
    return;
}
#define checkGlError(label) {int error = glGetError();if (error != GL_NO_ERROR) {error_at_line(0,0,__FILE__,__LINE__,"error=%d", error);goto label;}}
int main(int argc, char **argv) {
    SDL_Window *window = NULL;
    SDL_GLContext context = NULL;
    GLuint verticesGlIds[] = {0,0};
    GLuint vertexShaderGlId = 0;
    GLuint shaderProgramGlId = 0;
    if (fixSDLconsole()) {
        return errno;
    }
    if (SDL_Init(SDL_INIT_VIDEO) != 0) {
        error_at_line(1,0,__FILE__,__LINE__,"Unable to initialize SDL: %s",SDL_GetError());
        goto error;
    }
    printGLVersionNumber();

    window = SDL_CreateWindow("Window Title",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,640,640,SDL_WINDOW_OPENGL);
    if (window == NULL) {
        error_at_line(0,0,__FILE__,__LINE__,"Could not create window: %s", SDL_GetError());
        goto error;
    }
    context = SDL_GL_CreateContext(window);
    if (context == NULL) {
        error_at_line(0,0,__FILE__,__LINE__,"Could not create OpenGL context: %s", SDL_GetError());
        goto error;
    }

    glViewport(0,0,640,640);checkGlError(error);
    glClearColor(.9f,.9f,.9f,1.f);checkGlError(error);
    glEnableClientState(GL_VERTEX_ARRAY);checkGlError(error);
    glEnableClientState(GL_COLOR_ARRAY);checkGlError(error);

    float vertices[] = {
        -.5f,0.f,0.f,
        0.f,.5f,0.f,
        0.f,-.5f,0.f,
        0.f,.5f,0.f,
        .5f,.5f,0.f,
        0.f,0.f,0.f
    };
    float colors[] = {
        1.f,0.f,0.f,//red
        .5f,0.f,0.f,//red
        0.f,1.f,0.f,//green
        0.f,.5f,0.f,//green
        0.f,0.f,1.f,//blue
        0.f,0.f,.5f//blue
    };
    glGenBuffers(2, &verticesGlIds);checkGlError(error);

    glBindBuffer(GL_ARRAY_BUFFER, verticesGlIds[0]);checkGlError(error);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);checkGlError(error);

    glBindBuffer(GL_ARRAY_BUFFER, verticesGlIds[1]);checkGlError(error);
    glBufferData(GL_ARRAY_BUFFER,sizeof(colors),colors, GL_STATIC_DRAW);checkGlError(error);

    char *vertexShader =
        "#version 120\n"\
        "attribute vec3 aPos;\n"\
        "uniform float i;\n"\
        "void main() {\n"\
        "gl_FrontColor=gl_Color;\n"\
        "gl_Position = vec4(aPos.x+i/2,aPos.y,aPos.z,1.0);\n"\
        "}\n";
    vertexShaderGlId = glCreateShader(GL_VERTEX_SHADER);checkGlError(error);
    if (vertexShaderGlId == 0) {error_at_line(0,0,__FILE__,__LINE__,"vertex shader could not be created");goto error;}
    glShaderSource(vertexShaderGlId, 1, &vertexShader, NULL);checkGlError(error);
    glCompileShader(vertexShaderGlId);checkGlError(error);
    {
        GLint success;
        glGetShaderiv(vertexShaderGlId, GL_COMPILE_STATUS, &success);checkGlError(error);
        if (success == GL_FALSE) {
            char infoLog[512];
            glGetShaderInfoLog(vertexShaderGlId, 512, NULL, infoLog);checkGlError(error);
            error_at_line(0,0,__FILE__,__LINE__,"Vertex Shader problem: %s", infoLog);
            goto error;
        }
    }

    shaderProgramGlId = glCreateProgram();checkGlError(error);
    if (shaderProgramGlId == 0) {error_at_line(0,0,__FILE__,__LINE__,"shader program could not be created");goto error;}
    glAttachShader(shaderProgramGlId, vertexShaderGlId);checkGlError(error);
    glLinkProgram(shaderProgramGlId);checkGlError(error);
    {
        int success;
        glGetProgramiv(shaderProgramGlId, GL_LINK_STATUS, &success);checkGlError(error);
        if (!success) {
            char infoLog[512];
            glGetProgramInfoLog(shaderProgramGlId, 512, NULL, infoLog);checkGlError(error);
            error_at_line(0,0,__FILE__,__LINE__,"Shader program problem: %s", infoLog);
        }
    }

    glDeleteShader(vertexShaderGlId);checkGlError(error);

    GLint iLocation = glGetUniformLocation(shaderProgramGlId, "i");checkGlError(error);
    if (iLocation == -1) {error_at_line(0,0,__FILE__,__LINE__,"uniform i not found in shader");goto error;}
    error_at_line(0,0,__FILE__,__LINE__,"iLocation: %d", iLocation);

    for (int frame = 0; frame < 100; ++frame) {
        glClear(GL_COLOR_BUFFER_BIT);checkGlError(error);
        glUseProgram(shaderProgramGlId);checkGlError(error);

        glBindBuffer(GL_ARRAY_BUFFER, verticesGlIds[0]);    checkGlError(error);
        glVertexPointer(3,GL_FLOAT,0,0);    checkGlError(error);
        glBindBuffer(GL_ARRAY_BUFFER, verticesGlIds[1]);    checkGlError(error);
        glColorPointer(3,GL_FLOAT,0,0); checkGlError(error);
        glUniform1f(iLocation, (float) (frame%2));  checkGlError(error);
        glDrawArrays(GL_TRIANGLES, 0,sizeof(vertices)/sizeof(float)/3); checkGlError(error);
        glBindBuffer(GL_ARRAY_BUFFER, 0);   checkGlError(error);
        SDL_GL_SwapWindow(window);
        SDL_Delay(100);
    }
    glDeleteProgram(shaderProgramGlId);
    glDeleteShader(vertexShaderGlId);
    glDeleteBuffers(sizeof(verticesGlIds)/sizeof(GLuint), verticesGlIds);
    SDL_GL_DeleteContext(context);
    SDL_Delay(3000);
    SDL_DestroyWindow(window);
    SDL_Quit();
    return EXIT_SUCCESS;
    error:
    glDeleteProgram(shaderProgramGlId);
    glDeleteShader(vertexShaderGlId);
    glDeleteBuffers(sizeof(verticesGlIds)/sizeof(GLuint), verticesGlIds);
    if (context != NULL) SDL_GL_DeleteContext(context);
    if (window != NULL) SDL_DestroyWindow(window);
    SDL_Quit();
    return EXIT_FAILURE;
}
#if defined(__WINDOWS__)
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
    char *argv[1] = {(char *) 0};
    return main(0, argv);
}
#endif

note that I am not familiar with OpenGL's extension function loading issues and routines such as SDL's SDL_GL_LoadLibrary and SDL_GL_GetProcAddress I just manually define the method signatures at the top of the file and import GL through the linker. I don't expect this to be an issue but it is the only issue, I am aware of, that I haven't looked into, that may be causing my problems.

2
This should work. Are you sure it varies with time?user253751
I dont see any draw call. Did you omit it or it is simply not there?Nadir
Your code snippet is missing something important: The actual drawing commands. Without seeing where drawing happens in relation to the rest of the OpenGL operations it's nigh impossible to tell, what the problem is.datenwolf
@datenwolf edited to include missing draw commanduser8578151
@immibis yes, even passing in different constant values to glUniform1f results in no change to the displayed triangles, it is as if the vertex shader thinks the uniform i is always 0, but when I change the vertex shader directly by varying -1 to -0.5 I can see the difference so I know the shader is working.... I will edit the question with a compilable version within 12 hours.user8578151

2 Answers

0
votes

gl_Position expects Clip-space coordinates, which are a hiper-cube of size [2w,2w,2w,w].
For vec4(x, y, z, w) if any of the [x,y,z] is outside of [-w,w] range, then the vertex is clipped.
The coordinates will be automatically converted by the GPU to NDC-space x/w, y/w, z/w, 1 (aka "perspective division") before the fragment shader.

Your GLSL code gl_Position = vec4(aPos.x+i/2,aPos.y,aPos.z,1.0); uses the uniform i.
You update it by glUniform1f(iLocation, (float) (frame%2));

First issue is frame%2. Only 0 or 1 is passed to the GPU. With your current vertices data, only two pairs of triangles should be drawn.

Second issue is that frame is a value 0 <= frame < 100. So, if you pass frame instead of frame%2, then for most values aPos.x + i/2 will fall outside the Clip space and you will see only the first two triangle-pairs, or parts of them.

0
votes

So you declare the function like this:

void glUniform1f();

By omitting any parameters, the compiler will assume that all arguments are of type int. For most other GL functions, this works by chance, because those arguments are just integer types in most cases anyway, but for glUniform1f, it will mean that the function argument is converted to integer, but the resulting bit-pattern is implicitely re-interpreted as GLfloat by the function since the actual prototype for glUniform1f is something like this

void glUniform1f(int location, GLfloat value);

note that I am not familiar with OpenGL's extension function loading issues and routines such as SDL's SDL_GL_LoadLibrary and SDL_GL_GetProcAddress I just manually define the method signatures at the top of the file and import GL through the linker.

You shouldn't do this. The GL functions you try to access might not even be exported by the library at all. If you do not want to manually deal with loading every function pointer, you can use one of the existing OpenGL loaders.