/** * Copyright (c) 2021 Dominic Msters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "shader.h" void shaderInit(shader_t *shader, char *vertexShaderSource, char* fragmentShaderSource ) { int32_t isSuccess, maxLength, i, texture; char *error; GLuint shaderVertex, shaderFragment, shaderProgram; GLint size; // size of the variable GLsizei length; // name length GLchar const* filesVertex[] = { vertexShaderSource }; GLchar const* filesFragment[] = { fragmentShaderSource }; // Load the vertex shader first shaderVertex = glCreateShader(GL_VERTEX_SHADER); glShaderSource(shaderVertex, 1, filesVertex, 0); glCompileShader(shaderVertex); // Validate glGetShaderiv(shaderVertex, GL_COMPILE_STATUS, &isSuccess); if(!isSuccess) { glGetShaderiv(shaderVertex, GL_INFO_LOG_LENGTH, &maxLength); error = malloc(maxLength); glGetShaderInfoLog(shaderVertex, maxLength, &maxLength, error); printf("Failed to compile vertex shader %s\n", error); free(error); return; } // Now load the Frag shader shaderFragment = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(shaderFragment, 1, filesFragment, 0); glCompileShader(shaderFragment); glGetShaderiv(shaderFragment, GL_COMPILE_STATUS, &isSuccess); if(!isSuccess) { glGetShaderiv(shaderFragment, GL_INFO_LOG_LENGTH, &maxLength); error = malloc(maxLength); glGetShaderInfoLog(shaderFragment, maxLength, &maxLength, error); printf("Failed to compile fragment shader %s\n", error); free(error); glDeleteShader(shaderVertex); return; } // Now create the shader program. shaderProgram = glCreateProgram(); glAttachShader(shaderProgram, shaderVertex); glAttachShader(shaderProgram, shaderFragment); //Bind, Verify & Use the shader program glLinkProgram(shaderProgram); glGetProgramiv(shaderProgram, GL_LINK_STATUS, &isSuccess); if(!isSuccess) { glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &maxLength); error = malloc(maxLength); glGetProgramInfoLog(shaderProgram, maxLength, &maxLength, error); printf("Failed to load shader program %s\n", error); free(error); glDeleteShader(shaderVertex); glDeleteShader(shaderFragment); return; } // Everything is okay, let's create the encapsulated shader. shader->shaderVertex = shaderVertex; shader->shaderFrag = shaderFragment; shader->shaderProgram = shaderProgram; // Extract uniforms glGetProgramiv(shaderProgram, GL_ACTIVE_UNIFORMS, &shader->uniformCount); texture = 0; for(i = 0; i < shader->uniformCount; i++) { shader->uniformNames[i] = ( shader->uniformBuffer + (i * SHADER_UNIFORM_NAME_MAX) ); glGetActiveUniform( shaderProgram, (GLuint)i, SHADER_UNIFORM_NAME_MAX, &length, &size, shader->types + i, shader->uniformNames[i] ); // TODO: Reset uniforms to zero. if(shader->types[i] == GL_SAMPLER_2D) shader->textureSlots[i] = texture++; } // Bind the shader shaderUse(shader); } shaderuniform_t shaderGetUniform(shader_t *shader, char *name) { int32_t i; for(i = 0; i < shader->uniformCount; i++) { if(strcmp(shader->uniformNames[i], name) == 0) return i; } return (shaderuniform_t)0xFFFFFFFF; } void shaderGetUniformArray( shader_t *shader, shaderuniform_t *uniformSet, char **uniforms, int32_t uniformCount ) { int32_t i; for(i = 0; i < uniformCount; i++) { uniformSet[i] = shaderGetUniform(shader, uniforms[i]); } } void shaderDispose(shader_t *shader) { glDeleteProgram(shader->shaderProgram); glDeleteShader(shader->shaderVertex); glDeleteShader(shader->shaderFrag); } void shaderUse(shader_t *shader) { glUseProgram(shader->shaderProgram); } void shaderUseTexture( shader_t *shader, shaderuniform_t uniform, texture_t *texture ) { int32_t i = shader->textureSlots[(int32_t)uniform]; // TODO: I need to be able to get the texture ID glActiveTexture(GL_TEXTURE0 + i); glBindTexture(GL_TEXTURE_2D, texture->id); glUniform1i(uniform, i); } void shaderUseMatrix( shader_t *shader, shaderuniform_t uniform, matrix_t *matrix ) { glUniformMatrix4fv(uniform, 1, GL_FALSE, matrix->internalMatrix[0]); } void shaderUseColor(shader_t *shader, shaderuniform_t uniform, pixel_t color) { glUniform4f(uniform, (float)color.r / 255.0f, (float)color.g / 255.0f, (float)color.b / 255.0f, (float)color.a / 255.0f ); } void shaderUsePosition( shader_t *shader, shaderuniform_t uniform, float x, float y, float z, float pitch, float yaw, float roll ) { matrix_t matrix; matrixIdentity(&matrix); matrixTranslate(&matrix, x, y, z); // Rotation (YZX order) matrixRotate(&matrix, yaw, 0, 1, 0); matrixRotate(&matrix, roll, 0, 0, 1); matrixRotate(&matrix, pitch, 1, 0, 0); shaderUseMatrix(shader, uniform, &matrix); } void shaderUsePositionAndScale( shader_t *shader, shaderuniform_t uniform, float x, float y, float z, float pitch, float yaw, float roll, float scaleX, float scaleY, float scaleZ ) { matrix_t matrix; matrixIdentity(&matrix); matrixTranslate(&matrix, x, y, z); // Rotation (YZX order) matrixRotate(&matrix, yaw, 0, 1, 0); matrixRotate(&matrix, roll, 0, 0, 1); matrixRotate(&matrix, pitch, 1, 0, 0); matrixScale(&matrix, scaleX, scaleY, scaleZ); shaderUseMatrix(shader, uniform, &matrix); } void shaderUseCamera( shader_t *shader, shaderuniform_t uniformView, shaderuniform_t uniformProjection, camera_t *camera ) { shaderUseMatrix(shader, uniformView, &camera->view); shaderUseMatrix(shader, uniformProjection, &camera->projection); }