Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

This is the code that I use to setup my shader

char* vertexShaderSource = getResource("vert.shad");
char* fragmentShaderSource = getResource("frag.shad");

vshad = readFile(vertexShaderSource);
fshad = readFile(fragmentShaderSource);

free(vertexShaderSource);
free(fragmentShaderSource);

GLuint getShaderProgram(const char* vshad, const char* fshad)
{
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);

    glShaderSource(vertexShader, 1, &vshad, NULL);
    glCompileShader(vertexShader);

    GLint success;
    GLchar infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);

    if(!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        printf("ERROR VERTEX COMPILATION_FAILED %s\n",infoLog);
        SDL_Quit();
    }

    GLuint fragmentShader  = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fshad, NULL);
    glCompileShader(fragmentShader);

    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);

    if(!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        printf("ERROR FRAGMENT COMPILATION_FAILED %s\n",infoLog);
        SDL_Quit();
    }

    GLuint shaderProgram = glCreateProgram();

    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if(!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        printf("ERROR SHADER PROGRAM COMPILATION_FAILED %s\n",infoLog);
        SDL_Quit();
    }
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    return shaderProgram;
}

then this code sets up 1 vao to render a textured quad

glGenVertexArrays(1, &vao);
    glGenBuffers(1, &verticesBuffer);
    glGenBuffers(1, &colorBuffer);
    glGenBuffers(1, &indicesBuffer);
    glGenBuffers(1, &texCoordBuffer);

    glBindVertexArray(vao); //bind vertex array buffer

    glBindBuffer(GL_ARRAY_BUFFER, verticesBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(r->vertices), r->vertices, GL_STATIC_DRAW);

    //bind n setup indices
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(r->indices), r->indices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind indices

    //bind n setup colors
    glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(r->colors), r->colors, GL_STATIC_DRAW);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(1);
    glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind colors

    //bind n setup texture coords
    glBindBuffer(GL_ARRAY_BUFFER, texCoordBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(r->texCoords), r->texCoords, GL_STATIC_DRAW);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(2);
    glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind texture coords

    glBindVertexArray(0); //unbind vertex array buffer

this to setup my texture

glGenTextures(1, &colorTextureID);
glBindTexture(GL_TEXTURE_2D, colorTextureID);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);


glTexImage2D(GL_TEXTURE_2D, 0, Mode1, colorSurface->w, colorSurface->h, 0, Mode1, GL_UNSIGNED_BYTE, colorSurface->pixels);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
free(colorSurface);

and finally the rendering code

void render()
{
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    glUseProgram(sp);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, colorTextureID);//ourTexture
    ourTexture = getUniformLocation(sp, "ourTexture");
    glUniform1i(ourTexture, 0);

    glBindVertexArray(verticesBuffer);
    viewMat = getUniformLocation(sp, "viewMat");
    modelMat = getUniformLocation(sp, "modelMat");
    projMat = getUniformLocation(sp, "projMat");

    maxIterLoc = getUniformLocation(sp, "maxIterations");
    centerLoc = getUniformLocation(sp, "center");
    scaleLoc = getUniformLocation(sp, "scale");

    glUniformMatrix4fv(viewMat, 1, GL_FALSE, vm.m);
    glUniformMatrix4fv(projMat, 1, GL_FALSE, opm.m);
    glUniformMatrix4fv(modelMat, 1, GL_FALSE, tm.m);

    glUniform1i(maxIterLoc, maxIterations);
    glUniform1f(scaleLoc, scale);
    glUniform2f(centerLoc, cx, cy);

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);



    SDL_GL_SwapWindow(window);
}

This whole setup just to render a textured quad basically a non alpha blended sprite.

I already put the code to create the shader program in a class of it's own but there's still all the other code of setting up the vao, texture and the state setup before rendering.

How are these things architected in bigger systems? Imagine if I had to render a textured, normal mapped, shadow mapped 3d model. This code would get significantly longer.

this sample code below is how I was thinking of generalizing the rendering code. This way I can create a few different types of shaders w/o have so much clutter right in my main class.

** pseudo shader class**

    gluint shader_program = -1;
    glint vao, vBuff, iBuff, cBuff, tBuff;
    glint textures;

    shader_program create_sprite_shader()
    {
     glGenVertexArray(...)
     glGenBuffers(...)
     .... do all bind buffer and buffer data
    }

    void use_shader(shader_program s)
    {
     glUseProgram(s->program);
     glActivateTexture(gl_texture0);
     glBindTexture(sp->texture_type, sp->texture);

     get all uniform and attribute locations from shader..
     bind their values
    }

    render(mat44 model, mat44 view, mat44 proj)
    {
      //pass model view and projection matrices to the shader
    }

    unbind_shader()
    {
     glUseProgram(0);
    }

in my main class

shader_program s_shader;

init_main()
{
  s_shader = create_sprite_shader()
}

while(game_running)
{
  update_game() { .. };
  handle_input() { .. };

  render()
  {
   use_program(s_shader);
   for(0 ... 10)
   {
     s_program->render(sprite[i].modelMatrix, viewMatrix, projMatrix);
   }
   unbind_shader();
  }
}

clean_up() { //clean up resources }

I could have a toon_shader, a metal_shader, etc. Is that the way these parts of the code is architected?

I've seem some reference works looking at Intel, NVidia, etc., but those are usually laid out how my code is currently right now, which doesn't scale well.

share|improve this question

1 Answer 1

up vote 3 down vote accepted

I can give one small piece of advice. Don't do this in your render loop:

viewMat = getUniformLocation(sp, "viewMat");
modelMat = getUniformLocation(sp, "modelMat");
projMat = getUniformLocation(sp, "projMat");

maxIterLoc = getUniformLocation(sp, "maxIterations");
centerLoc = getUniformLocation(sp, "center");
scaleLoc = getUniformLocation(sp, "scale");

You should get the uniform locations only once, usually just after you've compiled your shader and linked it. Then save the locations and just write to them. Getting data from OpenGL tends to be very slow.

Or, as mentioned in the comments, don't even query them at all. In newer versions of OpenGL (3.0 and later, I think), you can specify uniform locations in the shader using layout specifications. Then you don't need to query what they are. It would look something like this:

layout (location = 0) in vec4 vPosition;
layout (location = 1) in vec3 vNormal;
layout (location = 2) in vec3 vTangent;
layout (location = 3) in vec3 vBinormal;
layout (location = 4) in vec2 vTexCoord;
share|improve this answer
1  
Even better, don't query for these things. Specify them as a fixed part of the interface between the host application and the shader, and use layout(location=X) to ensure that the attributes are bound to the same location as the host code will use. –  Sean Middleditch Aug 13 at 6:00
    
Yes! Excellent point. I'll update the answer. –  user1118321 Aug 13 at 13:32
    
okay, seems this is a good start. Thanks! –  user1610950 Aug 13 at 23:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.