diff --git a/.vscode/settings.json b/.vscode/settings.json index f3822df..6512136 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -77,5 +77,8 @@ "ctime": "cpp", "ratio": "cpp" }, - "C_Cpp.errorSquiggles": "Disabled" + "C_Cpp.errorSquiggles": "Disabled", + "cSpell.words": [ + "VERTICE" + ] } \ No newline at end of file diff --git a/Engine/engine/constants.hpp b/Engine/engine/constants.hpp index c40e10f..adca746 100644 --- a/Engine/engine/constants.hpp +++ b/Engine/engine/constants.hpp @@ -33,6 +33,16 @@ namespace constants GLfloat alpha = 1.0f; } LEARN_OPEN_GL_COLOR; + // we send output from vertex shader (vertexColor)... + inline const char *VERTEX_SHADER_COLOR { "#version 330 core\n" + "layout (location = 0) in vec3 aPos;\n" + "out vec3 vertexColor;\n" // color output to fragment shader + "void main()\n" + "{\n" + " gl_Position = vec4(aPos, 1.0);\n" // we directly give xyz of aPos as an argument + " vertexColor = vec3(0.5, 0.0, 0.0);\n" // dark red color + "}\0" } ; + // we write vertex shader // version of glsl (since ogl 3.3 same as ogl so we pick 330) // in this shader we just forward input data to shader output @@ -43,6 +53,38 @@ namespace constants " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" "}\0" } ; + inline const char *VERTEX_SHADER_VERTICE_COLOR { "#version 330 core\n" + "layout (location = 0) in vec3 aPos;\n" // position has attribute position 0 + "layout (location = 1) in vec3 aColor;\n" // color has attribute position 1 + "out vec3 vertexColor;\n" // output a color to fragment shader + "void main()\n" + "{\n" + " gl_Position = vec4(aPos, 1.0);\n" + " vertexColor = aColor;\n" + "}\0" } ; + + // ... to fragment shader (vertexColor) + inline const char *FRAGMENT_SHADER_COLOR_FROM_VERTEX { + "#version 330 core\n" + "out vec4 FragColor;\n" + "in vec3 vertexColor;\n" // from vertex + "void main()\n" + "{\n" + "FragColor = vec4(vertexColor, 1.0);\n" + "}\0" + }; + + // uniforms + inline const char *FRAGMENT_SHADER_UNIFORMS { + "#version 330 core\n" + "out vec4 FragColor;\n" + "uniform vec4 ourColor;\n" // set in OGL code + "void main()\n" + "{\n" + "FragColor = ourColor;\n" + "}\0" + }; + // write fragment shader // we set the color of each pixel to be orange inline const char *FRAGMENT_SHADER_SOURCE { @@ -105,6 +147,15 @@ namespace constants inline constexpr size_t TRIANGLE_TWO_SIZE = { sizeof(TRIANGLE_TWO) }; + inline constexpr float TRIANGLE_COLORS[] { + // positions // colors + 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom right + -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // bottom left + 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // top + }; + + inline constexpr size_t TRIANGLE_COLORS_SIZE = { sizeof(TRIANGLE_COLORS) }; + // compare with square done with only vertices: /* @@ -136,7 +187,7 @@ namespace constants inline constexpr size_t SQUARE_VERTICES_SIZE = { sizeof(SQUARE_VERTICES) }; - inline constexpr int MAX_DRAW_CALL = { 4 }; + inline constexpr int MAX_DRAW_CALL = { 7 }; } diff --git a/Engine/engine/draw.cpp b/Engine/engine/draw.cpp index 563aaf9..0daccb6 100644 --- a/Engine/engine/draw.cpp +++ b/Engine/engine/draw.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "draw.hpp" #include "renderLoop.hpp" #include "shaders.hpp" @@ -14,18 +15,27 @@ 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); + return drawTriangle(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, constants::VERTEX_SHADER_SOURCE, constants::FRAGMENT_SHADER_SOURCE, false); case 1: return drawSquare(constants::VERTEX_SHADER_SOURCE, constants::FRAGMENT_SHADER_SOURCE); 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); + return drawTriangle(constants::TRIANGLES_VERTICES, constants::TRIANGLES_VERTICES_SIZE, constants::VERTEX_SHADER_SOURCE, constants::FRAGMENT_SHADER_SOURCE, 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) == -1 || drawTriangle(constants::TRIANGLE_TWO, constants::TRIANGLE_TWO_SIZE, constants::VERTEX_SHADER_SOURCE, constants::FRAGMENT_SHADER_SOURCE) == -1); - case constants::MAX_DRAW_CALL: + 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); + 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) == -1 || drawTriangle(constants::TRIANGLE_TWO, constants::TRIANGLE_TWO_SIZE, constants::VERTEX_SHADER_SOURCE, constants::FRAGMENT_SHADER_SOURCE_YELLOW) == -1); + 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); + 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); + 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); + 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); default: throw "No function for this draw call"; } @@ -46,8 +56,7 @@ int drawSquare(const char* vertexShaderSource, const char* fragmentShaderSource) copyVerticesMemory(constants::SQUARE_INDICES, constants::SQUARE_INDICES_SIZE, GL_ELEMENT_ARRAY_BUFFER); // set vertex attribute pointers - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); - glEnableVertexAttribArray(0); + configureVertexAttribute(false); doDrawElements(shaderProgram, VAO, GL_TRIANGLES, GL_UNSIGNED_INT, std::size(constants::SQUARE_INDICES)); return 0; @@ -61,7 +70,7 @@ void doDrawElements(const unsigned int shaderProgram, const unsigned int vertexA glBindVertexArray(0); } -int drawTriangle(const float triangleVertices[], const size_t triangleVerticesSize, const char* vertexShaderSource, const char* fragmentShaderSource) +int drawTriangle(const float triangleVertices[], const size_t triangleVerticesSize, const char* vertexShaderSource, const char* fragmentShaderSource, const bool colorIncluded) { const unsigned int vertexBufferObject = copyVerticesMemory(triangleVertices, triangleVerticesSize, GL_ARRAY_BUFFER); @@ -73,21 +82,41 @@ int drawTriangle(const float triangleVertices[], const size_t triangleVerticesSi if (shaderProgram == 0) return -1; - configureVertexAttribute(); const unsigned int vertexArrayObject = generateBindVAO(); copyVerticesArray(vertexBufferObject, triangleVertices, triangleVerticesSize, GL_ARRAY_BUFFER); // set vertex attribute pointers - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); - glEnableVertexAttribArray(0); + configureVertexAttribute(colorIncluded); doDrawArrays(shaderProgram, vertexArrayObject, GL_TRIANGLES, 0, triangleVerticesSize); return 0; } +void updateUniformColor(const unsigned int shaderProgram, const GLchar* uniformName) +{ + // 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. + */ + } +} + + void doDrawArrays(const unsigned int shaderProgram, 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"); glBindVertexArray(vertexArrayObject); // From left: // primitive type we want to draw diff --git a/Engine/engine/draw.hpp b/Engine/engine/draw.hpp index b58ddb1..a4e4bc6 100644 --- a/Engine/engine/draw.hpp +++ b/Engine/engine/draw.hpp @@ -6,7 +6,8 @@ int drawFigure(const int whatToDraw); int drawSquare(const char* vertexShaderSource, const char* 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); +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 ); #endif \ No newline at end of file diff --git a/Engine/engine/match b/Engine/engine/match index 2a6c3d6..f73c15a 100755 Binary files a/Engine/engine/match and b/Engine/engine/match differ diff --git a/Engine/engine/renderLoop.cpp b/Engine/engine/renderLoop.cpp index 1d03f34..5e94d71 100644 --- a/Engine/engine/renderLoop.cpp +++ b/Engine/engine/renderLoop.cpp @@ -11,8 +11,10 @@ int processInput(GLFWwindow *window, const int whatToDraw) { - static bool locked = false; - const bool PRESSED_CHANGE_DRAW = (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS); + static bool lockedLeft = false; + static bool lockedRight = false; + const bool PRESSED_CHANGE_LEFT = (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS); + const bool PRESSED_CHANGE_RIGHT = (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS); // glfwGetKey takes window and key as an input and checks is currently being pressed // if the user pressed escape we close window @@ -20,12 +22,19 @@ int processInput(GLFWwindow *window, const int whatToDraw) glfwSetWindowShouldClose(window, true); if (glfwGetKey(window, GLFW_KEY_C) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); - if ( !PRESSED_CHANGE_DRAW ) - locked = 0; - if ( PRESSED_CHANGE_DRAW && locked == 0 ) + if ( !PRESSED_CHANGE_LEFT ) + lockedLeft = 0; + if ( !PRESSED_CHANGE_RIGHT ) + lockedRight = 0; + if ( PRESSED_CHANGE_RIGHT && lockedRight == 0 ) { - locked = 1; + lockedRight = 1; return (whatToDraw == constants::MAX_DRAW_CALL ? 0 : whatToDraw + 1); + } + if ( PRESSED_CHANGE_LEFT && lockedLeft == 0 ) + { + lockedLeft = 1; + return (whatToDraw == 0 ? constants::MAX_DRAW_CALL : whatToDraw - 1); } return whatToDraw; } @@ -69,21 +78,35 @@ unsigned int copyVerticesMemory(const unsigned int vertices[], const size_t size return vertexBufferObject; } -void configureVertexAttribute() +void configureVertexAttribute(const bool colorIncluded) { - // specify how OGL interprets vertex data - // From left: - // which vertex attribute we configure (from shader source code layout (location = 0)) - // size of vertex attribute (we use vec3 so it contains 3 values) - // type of data of which vec consists of - // should data be normalized, (useful when we use integer data) - // space between vertex attributes, each position data is 3 times the size of float - // offset of where position data begins in buffer - // see: https://learnopengl.com/img/getting-started/vertex_attribute_pointer.png - // vertex attribute data take data from memory managed by VBO bound to GL_ARRAY_BUFFER - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); + /* specify how OGL interprets vertex data + From left: + which vertex attribute we configure (from shader source code layout (location = 0)) + size of vertex attribute (we use vec3 so it contains 3 values) + type of data of which vec consists of + should data be normalized, (useful when we use integer data) + space between vertex attributes, each position data is 3 times the size of float + offset of where position data begins in buffer + see: https://learnopengl.com/img/getting-started/vertex_attribute_pointer.png + vertex attribute data take data from memory managed by VBO bound to GL_ARRAY_BUFFER */ + if(!colorIncluded) { + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); + // enable vertex attribute + glEnableVertexAttribArray(0); + return; + } + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)0); // enable vertex attribute glEnableVertexAttribArray(0); + + /* we change attribute location, color values have size of 3 floats + we do not normalize values, in order to get the next attribute value in data array we need to move 6 floats, (3 for position and 3 for color), we also need to specify an offset, first we have position then after 3 floats we have color + https://learnopengl.com/img/getting-started/vertex_attribute_pointer_interleaved.png */ + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)(3* sizeof(float))); + // enable vertex attribute + glEnableVertexAttribArray(1); } unsigned int generateBindVAO() diff --git a/Engine/engine/renderLoop.hpp b/Engine/engine/renderLoop.hpp index 6537df0..536385d 100644 --- a/Engine/engine/renderLoop.hpp +++ b/Engine/engine/renderLoop.hpp @@ -7,7 +7,7 @@ void renderLoop(GLFWwindow *window); int renderLoopInside(GLFWwindow *window, int whatToDraw); void copyVerticesArray(unsigned int vertexBufferObject, const float vertices[], const size_t sizeOfVertices, const GLenum boundBufferTarget); unsigned int generateBindVAO(); -void configureVertexAttribute(); +void configureVertexAttribute(const bool colorIncluded); int processInput(GLFWwindow *window, int whatToDraw); unsigned int copyVerticesMemory(const float vertices[], const size_t sizeOfVertices, const GLenum boundBufferTarget);