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.