diff --git a/Engine/engine/constants.hpp b/Engine/engine/constants.hpp index adca746..7012aff 100644 --- a/Engine/engine/constants.hpp +++ b/Engine/engine/constants.hpp @@ -33,6 +33,35 @@ namespace constants GLfloat alpha = 1.0f; } LEARN_OPEN_GL_COLOR; + inline const std::string_view VERTEX_SHADER_OUTPUT_FILE { + "./shaders/vertexShaderOutput.vs" + }; + + inline const std::string_view VERTEX_FIRST_SHADER { + "./shaders/firstShader.vs" + }; + + inline const std::string_view VERTEX_WITH_COLOR { + "./shaders/vertexWithColor.vs" + }; + + inline const std::string_view FRAGMENT_YELLOW { + "./shaders/yellow.fs" + }; + + inline const std::string_view FRAGMENT_ORANGE { + "./shaders/orange.fs" + }; + + inline const std::string_view FRAGMENT_COLOR_INPUT { + "./shaders/fragmentColorInput.fs" + }; + + inline const std::string_view FRAGMENT_UNIFORMS { + "./shaders/fragmentUniforms.fs" + }; + + // we send output from vertex shader (vertexColor)... inline const char *VERTEX_SHADER_COLOR { "#version 330 core\n" "layout (location = 0) in vec3 aPos;\n" diff --git a/Engine/engine/draw.cpp b/Engine/engine/draw.cpp index 0daccb6..431fcb4 100644 --- a/Engine/engine/draw.cpp +++ b/Engine/engine/draw.cpp @@ -15,41 +15,35 @@ int drawFigure(const int whatToDraw) switch (whatToDraw) { case 0: - return drawTriangle(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, constants::VERTEX_SHADER_SOURCE, constants::FRAGMENT_SHADER_SOURCE, false); + return drawTriangle(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, constants::VERTEX_FIRST_SHADER, constants::FRAGMENT_ORANGE, false); case 1: - return drawSquare(constants::VERTEX_SHADER_SOURCE, constants::FRAGMENT_SHADER_SOURCE); + return drawSquare(constants::VERTEX_FIRST_SHADER, constants::FRAGMENT_ORANGE); case 2: // Try to draw 2 triangles next to each other using glDrawArrays by adding more vertices to your data. - return drawTriangle(constants::TRIANGLES_VERTICES, constants::TRIANGLES_VERTICES_SIZE, constants::VERTEX_SHADER_SOURCE, constants::FRAGMENT_SHADER_SOURCE, false); + return drawTriangle(constants::TRIANGLES_VERTICES, constants::TRIANGLES_VERTICES_SIZE, constants::VERTEX_FIRST_SHADER, constants::FRAGMENT_ORANGE, false); case 3: // Now create the same 2 triangles using two different VAOs and VBOs for their data - return (drawTriangle(constants::TRIANGLE_ONE, constants::TRIANGLE_ONE_SIZE, constants::VERTEX_SHADER_SOURCE, constants::FRAGMENT_SHADER_SOURCE, false) == -1 || drawTriangle(constants::TRIANGLE_TWO, constants::TRIANGLE_TWO_SIZE, constants::VERTEX_SHADER_SOURCE, constants::FRAGMENT_SHADER_SOURCE, false) == -1); + return (drawTriangle(constants::TRIANGLE_ONE, constants::TRIANGLE_ONE_SIZE, constants::VERTEX_FIRST_SHADER, constants::FRAGMENT_ORANGE, false) == -1 || drawTriangle(constants::TRIANGLE_TWO, constants::TRIANGLE_TWO_SIZE, constants::VERTEX_FIRST_SHADER, constants::FRAGMENT_ORANGE, false) == -1); case 4: // Create two shader programs where the second program uses a different fragment shader that outputs the color yellow; draw both triangles again where one outputs the color yellow - return (drawTriangle(constants::TRIANGLE_ONE, constants::TRIANGLE_ONE_SIZE, constants::VERTEX_SHADER_SOURCE, constants::FRAGMENT_SHADER_SOURCE, false) == -1 || drawTriangle(constants::TRIANGLE_TWO, constants::TRIANGLE_TWO_SIZE, constants::VERTEX_SHADER_SOURCE, constants::FRAGMENT_SHADER_SOURCE_YELLOW, false) == -1); + return (drawTriangle(constants::TRIANGLE_ONE, constants::TRIANGLE_ONE_SIZE, constants::VERTEX_FIRST_SHADER, constants::FRAGMENT_ORANGE, false) == -1 || drawTriangle(constants::TRIANGLE_TWO, constants::TRIANGLE_TWO_SIZE, constants::VERTEX_FIRST_SHADER, constants::FRAGMENT_YELLOW, false) == -1); case 5: // Get color from vertex shader to fragment shader - return drawTriangle(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, constants::VERTEX_SHADER_COLOR, constants::FRAGMENT_SHADER_COLOR_FROM_VERTEX, false); + return drawTriangle(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, constants::VERTEX_WITH_COLOR, constants::FRAGMENT_COLOR_INPUT, false); case 6: // set color from opengl code to uniform value in fragment shader - return drawTriangle(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, constants::VERTEX_SHADER_COLOR, constants::FRAGMENT_SHADER_UNIFORMS, false); + return drawTriangle(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, constants::VERTEX_WITH_COLOR, constants::FRAGMENT_UNIFORMS, false); case constants::MAX_DRAW_CALL: // set color from opengl code to uniform value in fragment shader - return drawTriangle(constants::TRIANGLE_COLORS, constants::TRIANGLE_COLORS_SIZE, constants::VERTEX_SHADER_VERTICE_COLOR, constants::FRAGMENT_SHADER_COLOR_FROM_VERTEX, true); + return drawTriangle(constants::TRIANGLE_COLORS, constants::TRIANGLE_COLORS_SIZE, constants::VERTEX_WITH_COLOR, constants::FRAGMENT_COLOR_INPUT, true); default: throw "No function for this draw call"; } } -int drawSquare(const char* vertexShaderSource, const char* fragmentShaderSource) +int drawSquare(const std::string_view vertexShaderSource, const std::string_view fragmentShaderSource) { - const std::pair shaders = compileShaders(vertexShaderSource, fragmentShaderSource); - if (shaders.first == 0 || shaders.second == 0) - return -1; - - const unsigned int shaderProgram = linkShaderObjectsShaderProgram(shaders.first, shaders.second); - if (shaderProgram == 0) - return -1; + Shader ourShader(vertexShaderSource, fragmentShaderSource); const unsigned int VAO = generateBindVAO(); copyVerticesMemory(constants::SQUARE_VERTICES, constants::SQUARE_VERTICES_SIZE, GL_ARRAY_BUFFER); @@ -58,65 +52,48 @@ int drawSquare(const char* vertexShaderSource, const char* fragmentShaderSource) // set vertex attribute pointers configureVertexAttribute(false); - doDrawElements(shaderProgram, VAO, GL_TRIANGLES, GL_UNSIGNED_INT, std::size(constants::SQUARE_INDICES)); + doDrawElements(ourShader, VAO, GL_TRIANGLES, GL_UNSIGNED_INT, std::size(constants::SQUARE_INDICES)); return 0; } -void doDrawElements(const unsigned int shaderProgram, const unsigned int vertexArrayObject, const GLenum drawArrayMode, const GLenum drawType, const int numberOfElementsToDraw) +void doDrawElements(const Shader Shader, const unsigned int vertexArrayObject, const GLenum drawArrayMode, const GLenum drawType, const int numberOfElementsToDraw) { - glUseProgram(shaderProgram); + Shader.use(); glBindVertexArray(vertexArrayObject); glDrawElements(drawArrayMode, numberOfElementsToDraw, drawType, 0); glBindVertexArray(0); } -int drawTriangle(const float triangleVertices[], const size_t triangleVerticesSize, const char* vertexShaderSource, const char* fragmentShaderSource, const bool colorIncluded) +int drawTriangle(const float triangleVertices[], const size_t triangleVerticesSize, const std::string_view vertexShaderSource, const std::string_view fragmentShaderSource, const bool colorIncluded) { const unsigned int vertexBufferObject = copyVerticesMemory(triangleVertices, triangleVerticesSize, GL_ARRAY_BUFFER); - const std::pair shaders = compileShaders(vertexShaderSource, fragmentShaderSource); - if (shaders.first == 0 || shaders.second == 0) - return -1; - - const unsigned int shaderProgram = linkShaderObjectsShaderProgram(shaders.first, shaders.second); - if (shaderProgram == 0) - return -1; + Shader ourShader(vertexShaderSource, fragmentShaderSource); const unsigned int vertexArrayObject = generateBindVAO(); copyVerticesArray(vertexBufferObject, triangleVertices, triangleVerticesSize, GL_ARRAY_BUFFER); // set vertex attribute pointers configureVertexAttribute(colorIncluded); - doDrawArrays(shaderProgram, vertexArrayObject, GL_TRIANGLES, 0, triangleVerticesSize); + doDrawArrays(ourShader, vertexArrayObject, GL_TRIANGLES, 0, triangleVerticesSize); return 0; } -void updateUniformColor(const unsigned int shaderProgram, const GLchar* uniformName) +GLfloat updateUniformColor() { // update the uniform color const float timeValue = glfwGetTime(); // retrieve running time const float greenValue = sin(timeValue) / 2.0f + 0.5f; // vary the color from 0.0 to 1.0 using sin - const int vertexColorLocation = glGetUniformLocation(shaderProgram, uniformName); // query the location of our uniform - if(vertexColorLocation != -1) // if glGetUniformLocation returns -1 it could not find the location - { - glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f); /* we set the uniform value using glUniform4f - 4f means that it expects 4 floats - few of possible postfixes: - f: the function expects a float as its value. - i: the function expects an int as its value. - ui: the function expects an unsigned int as its value. - 3f: the function expects 3 floats as its value. - fv: the function expects a float vector/array as its value. - */ - } + return greenValue; } -void doDrawArrays(const unsigned int shaderProgram, const unsigned int vertexArrayObject, const GLenum drawArrayMode, const int firstIndex, const unsigned int numberOfIndicesToBeRendered) +void doDrawArrays(const Shader Shader, const unsigned int vertexArrayObject, const GLenum drawArrayMode, const int firstIndex, const unsigned int numberOfIndicesToBeRendered) { // use shader program to render an object - glUseProgram(shaderProgram); - updateUniformColor(shaderProgram, "ourColor"); + Shader.use(); + Shader.setFloat("ourColor", updateUniformColor()); + glBindVertexArray(vertexArrayObject); // From left: // primitive type we want to draw diff --git a/Engine/engine/draw.hpp b/Engine/engine/draw.hpp index a4e4bc6..20a4464 100644 --- a/Engine/engine/draw.hpp +++ b/Engine/engine/draw.hpp @@ -4,10 +4,10 @@ #include int drawFigure(const int whatToDraw); -int drawSquare(const char* vertexShaderSource, const char* fragmentShaderSource); +int drawSquare(const std::string_view vertexShaderSource, const std::string_view fragmentShaderSource); void doDrawElements(const unsigned int shaderProgram, const unsigned int vertexArrayObject, const GLenum drawArrayMode, const GLenum drawType, const int numberOfElementsToDraw); -int drawTriangle(const float triangleVertices[], const size_t triangleVerticesSize, const char* vertexShaderSource, const char* fragmentShaderSource, const bool colorIncluded); -void updateUniformColor(const unsigned int shaderProgram, const GLchar* uniformName); -void doDrawArrays(const unsigned int shaderProgram, const unsigned int vertexArrayObject, const GLenum drawArrayMode, const int firstIndex, const unsigned int numberOfIndicesToBeRendered ); +int drawTriangle(const float triangleVertices[], const size_t triangleVerticesSize, const std::string_view vertexShaderSource, const std::string_view fragmentShaderSource, const bool colorIncluded); +GLfloat updateUniformColor(); +void doDrawArrays(const Shader Shader, const unsigned int vertexArrayObject, const GLenum drawArrayMode, const int firstIndex, const unsigned int numberOfIndicesToBeRendered ); #endif \ No newline at end of file diff --git a/Engine/engine/match b/Engine/engine/match old mode 100755 new mode 100644 index f73c15a..ba363de Binary files a/Engine/engine/match and b/Engine/engine/match differ diff --git a/Engine/engine/misc.cpp b/Engine/engine/misc.cpp index e3a8bae..0deae85 100644 --- a/Engine/engine/misc.cpp +++ b/Engine/engine/misc.cpp @@ -1,10 +1,26 @@ #ifndef MISC_CPP #define MISC_CPP #include +#include +#include #include "misc.hpp" void print(const std::string s) { std::cout << s << std::endl; } +std::string fileBufferToString(const std::string filePath, std::ifstream &file) +{ + std::string sourceCode; + // open files + file.open(filePath); // read file's buffer contents into streams + std::stringstream fileStream; + fileStream << file.rdbuf(); + // close file handlers + file.close(); + // convert stream into string + sourceCode = fileStream.str(); + return sourceCode; +} + #endif \ No newline at end of file diff --git a/Engine/engine/misc.hpp b/Engine/engine/misc.hpp index 1aeec16..f7eef94 100644 --- a/Engine/engine/misc.hpp +++ b/Engine/engine/misc.hpp @@ -3,4 +3,5 @@ #include void print(const std::string s); +std::string fileBufferToString(const std::string filePath, std::ifstream &file); #endif \ No newline at end of file diff --git a/Engine/engine/shader.cpp b/Engine/engine/shader.cpp new file mode 100644 index 0000000..76ab064 --- /dev/null +++ b/Engine/engine/shader.cpp @@ -0,0 +1,107 @@ +#ifndef SHADER_CPP +#define SHADER_CPP +#include +#include +#include "shader.hpp" +#include "misc.hpp" + +unsigned int Shader::linkShaderObjectsShaderProgram(const unsigned int vertexShaders, const unsigned int fragmentShader) const +{ + // link shader objects into shader program + // will store shader program id + // creates program + const unsigned int shaderProgram = glCreateProgram(); + + // attachShaders + glAttachShader(shaderProgram, vertexShaders); + glAttachShader(shaderProgram, fragmentShader); + + // link shaders + glLinkProgram(shaderProgram); + if (!shaderSuccessful(shaderProgram, false)) + return 0; + + // delete shaders (they are linked into shaderProgram and we do not need them anymore) + glDeleteShader(vertexShaders); + glDeleteShader(fragmentShader); + if (shaderProgram == 0) + print("Shader Program Linking Failed"); + return shaderProgram; +} + +unsigned int Shader::compileShader(const GLenum shaderType, const char *shaderSource) const +{ + // we create vertex shader and assign its id to shader variable + const unsigned int shaderID = glCreateShader(shaderType); + + // attach shader source code to shader object + // from left: shader object to compile, how many strings as source code, actual source code (we leave the 4th as NULL) + glShaderSource(shaderID, 1, &shaderSource, NULL); + // compile shader + glCompileShader(shaderID); + if (!shaderSuccessful(shaderID, true)) + return 0; + return shaderID; +} + +const char* Shader::getSourceCode(const std::string_view sourcePath) const +{ + // 1. retrieve the vertex/fragment source code from filePath + std::string sourceCode; + std::ifstream sourceFile; + // ensure ifstream objects can throw exceptions: + sourceFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); + try + { + sourceCode = fileBufferToString(sourcePath, sourceFile); + } + // https://stackoverflow.com/a/62030396 + catch(std::ifstream::failure const& e) + { + std::cerr << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ for sourcePath: " << sourcePath << std::endl; + } + const char* cSourceCode = sourceCode.c_str(); + return cSourceCode; +} + +void Shader::use() +{ + glUseProgram(ID); +} + +void Shader::setBool(const std::string_view &name, const bool value) const +{ + const int vertexColorLocation = glGetUniformLocation(ID, name.c_str()); + if(vertexColorLocation != -1) { + glUniform1i(vertexColorLocation, (int)value); + } +} + +void Shader::setInt(const std::string_view &name, const int value) const +{ + const int vertexColorLocation = glGetUniformLocation(ID, name.c_str()); + if(vertexColorLocation != -1) { + glUniform1i(vertexColorLocation, value); + } +} + +void Shader::setFloat(const std::string_view &name, const float value) const +{ + const int vertexColorLocation = glGetUniformLocation(ID, name.c_str()); + if(vertexColorLocation != -1) { + glUniform1f(vertexColorLocation, value); + } +} + + + +Shader::Shader(const std::string_view vertexPath, const std::string_view fragmentPath) +{ + const char* vShaderCode = getSourceCode(vertexPath); + const char* fShaderCode = getSourceCode(fragmentPath); + const int vectorShaderID = compileShader(GL_VERTEX_SHADER, vShaderCode); + const int fragmentShaderID = compileShader(GL_FRAGMENT_SHADER, fShaderCode); + ID = linkShaderObjectsShaderProgram(vectorShaderID, fragmentShaderID); +} + +#endif // SHADER_CPP \ No newline at end of file diff --git a/Engine/engine/shader.hpp b/Engine/engine/shader.hpp new file mode 100644 index 0000000..7314a3f --- /dev/null +++ b/Engine/engine/shader.hpp @@ -0,0 +1,29 @@ +#ifndef SHADER_HPP +#define SHADER_HPP +#include + +#include +#include +#include +#include + +class Shader +{ +public: + // the program ID + unsigned int ID; + unsigned int linkShaderObjectsShaderProgram(const unsigned int vertexShaders, const unsigned int fragmentShader) const; + int shaderSuccessful(const unsigned int shader, const bool compilation) const; + unsigned int compileShader(const GLenum shaderType, const char *shaderSource) const; + const char *getSourceCode(const std::string_view sourcePath) const; + // constructor reads and builds the shader + Shader(const std::string_view vertexPath, const std::string_view fragmentPath); + // use/activate the shader + void use(); + // utility uniform functions + void setBool(const std::string_view &name, const bool value) const; + void setInt(const std::string_view &name, const int value) const; + void setFloat(const std::string_view &name, const float value) const; +}; + +#endif \ No newline at end of file diff --git a/Engine/engine/shaders.hpp b/Engine/engine/shaders.hpp index 29b7d46..1843bdd 100644 --- a/Engine/engine/shaders.hpp +++ b/Engine/engine/shaders.hpp @@ -3,6 +3,7 @@ #include #include #include +#include "misc.hpp" unsigned int linkShaderObjectsShaderProgram(const unsigned int vertexShaders, const unsigned int fragmentShader); std::pair compileShaders(const char* vertexShaderSource, const char* fragmentShaderSource); diff --git a/Engine/engine/shaders/firstShader.vs b/Engine/engine/shaders/firstShader.vs new file mode 100644 index 0000000..5d16282 --- /dev/null +++ b/Engine/engine/shaders/firstShader.vs @@ -0,0 +1,6 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +void main() +{ + gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); +} \ No newline at end of file diff --git a/Engine/engine/shaders/fragmentColorInput.fs b/Engine/engine/shaders/fragmentColorInput.fs new file mode 100644 index 0000000..9dfc305 --- /dev/null +++ b/Engine/engine/shaders/fragmentColorInput.fs @@ -0,0 +1,7 @@ +#version 330 core +out vec4 FragColor; +in vec3 vertexColor; +void main() +{ + FragColor = vec4(vertexColor, 1.0); +} \ No newline at end of file diff --git a/Engine/engine/shaders/fragmentUniforms.fs b/Engine/engine/shaders/fragmentUniforms.fs new file mode 100644 index 0000000..8abcfd3 --- /dev/null +++ b/Engine/engine/shaders/fragmentUniforms.fs @@ -0,0 +1,8 @@ +#version 330 core +out vec4 FragColor; +uniform vec1 ourColor; +void main() +{ + + FragColor = (0.0f, ourColor, 0.0f, 1.0f); +} \ No newline at end of file diff --git a/Engine/engine/shaders/orange.fs b/Engine/engine/shaders/orange.fs new file mode 100644 index 0000000..c3616c9 --- /dev/null +++ b/Engine/engine/shaders/orange.fs @@ -0,0 +1,6 @@ +#version 330 core +out vec4 FragColor; +void main() +{ + FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); +} \ No newline at end of file diff --git a/Engine/engine/shaders/vertexShaderOutput.vs b/Engine/engine/shaders/vertexShaderOutput.vs new file mode 100644 index 0000000..2076649 --- /dev/null +++ b/Engine/engine/shaders/vertexShaderOutput.vs @@ -0,0 +1,8 @@ +#version 330 core\n +layout (location = 0) in vec3 aPos; +out vec3 vertexColor; +void main() +{ + gl_Position = vec4(aPos, 1.0); + vertexColor = vec3(0.5, 0.0, 0.0); +} \ No newline at end of file diff --git a/Engine/engine/shaders/vertexWithColor.vs b/Engine/engine/shaders/vertexWithColor.vs new file mode 100644 index 0000000..260e6a3 --- /dev/null +++ b/Engine/engine/shaders/vertexWithColor.vs @@ -0,0 +1,9 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec3 aColor; +out vec3 vertexColor; +void main() +{ + gl_Position = vec4(aPos, 1.0); + vertexColor = aColor; +} \ No newline at end of file diff --git a/Engine/engine/shaders/yellow.fs b/Engine/engine/shaders/yellow.fs new file mode 100644 index 0000000..4561264 --- /dev/null +++ b/Engine/engine/shaders/yellow.fs @@ -0,0 +1,6 @@ +#version 330 core +out vec4 FragColor; +void main() +{ + FragColor = vec4(1.0f, 1.0f, 0.0f, 1.0f); +} \ No newline at end of file