diff --git a/Engine/engine/beforeRender.cpp b/Engine/engine/beforeRender.cpp new file mode 100644 index 0000000..106cefc --- /dev/null +++ b/Engine/engine/beforeRender.cpp @@ -0,0 +1,92 @@ +#ifndef BEFORE_RENDER_CPP +#define BEFORE_RENDER_CPP +#include +#include + +#include +#include "beforeRender.hpp" +#include "constants.hpp" +#include "misc.hpp" + +void configureGLFW(const int GLFWMajorVersion, const int GLFWMinorVersion) { + // first argument tells us what option to configure + // second is to what we set the value of this option + // see: https://www.glfw.org/docs/latest/window.html#window_hints + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, GLFWMajorVersion); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, GLFWMinorVersion); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + // we set GLFW to 3.3 CORE + // core profile gives us access to smaller subset of OGL without backwards compatible features + + // if we are on Mac OS X we need this for our code to work + #ifdef __APPLE__ + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + #endif +} + +void instantiateGLFWwindow() { + // Initialize GLFW + glfwInit(); + configureGLFW(constants::GLFW_MAJOR_VERSION, constants::GLFW_MINOR_VERSION); +} + +GLFWwindow* createWindowObject() { + // First two arguments are width and height + // Third is the name of the window + // We ignore last two + GLFWwindow* window = glfwCreateWindow(constants::MAIN_WINDOW_WIDTH, constants::MAIN_WINDOW_HEIGHT, constants::MAIN_WINDOW_NAME, NULL, NULL); + return window; +} + +int initializeGLAD() +{ + // we load address of OGL OS-specific function pointers + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + print("Failed to initialize GLAD"); + return -1; + } + return 0; +} + +// resizes viewport when user resizes window +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + glViewport(0, 0, width, height); +} + +void viewPort(GLFWwindow* window) +{ + // We tell OGL size of rendering window + // First two define left corner of window + // 3th and 4th width and height of rendering window + // we could set them to be smaller than window dimension, ogl rendering will be then displayed in smaller window + glViewport(0, 0, constants::MAIN_WINDOW_WIDTH, constants::MAIN_WINDOW_HEIGHT); + // processed coordinates are between -1 and 1 so here we map: + // (-1 to 1) to (0, constants::MAIN_WINDOW_WIDTH) and (0, constants::MAIN_WINDOW_HEIGHT) + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + // we call framebuffer_size_callback on every window resize +} + +GLFWwindow* prepareForRender() +{ + instantiateGLFWwindow(); + + GLFWwindow* window = createWindowObject(); + // function returns GLFWWindow object + + if (window == NULL) + { + print("Failed to create GLFW window"); + glfwTerminate(); + return window; + } + // we make context of this window main context of current thread + glfwMakeContextCurrent(window); + + if(initializeGLAD() == -1) return NULL; + viewPort(window); + return window; +} + +#endif \ No newline at end of file diff --git a/Engine/engine/beforeRender.hpp b/Engine/engine/beforeRender.hpp new file mode 100644 index 0000000..51627d8 --- /dev/null +++ b/Engine/engine/beforeRender.hpp @@ -0,0 +1,13 @@ +#ifndef BEFORE_RENDER_HPP +#define BEFORE_RENDER_HPP +#include + +void configureGLFW(const int GLFWMajorVersion, const int GLFWMinorVersion); +void instantiateGLFWwindow(); +GLFWwindow* createWindowObject(); +int initializeGLAD(); +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void viewPort(GLFWwindow* window); +GLFWwindow* prepareForRender(); + +#endif \ No newline at end of file diff --git a/Engine/engine/constants.hpp b/Engine/engine/constants.hpp index 6d0d3f7..c0a5f7b 100644 --- a/Engine/engine/constants.hpp +++ b/Engine/engine/constants.hpp @@ -1,10 +1,13 @@ #ifndef CONSTANTS_HPP +#define CONSTANTS_HPP #include #include #include namespace constants { + inline constexpr int GLFW_MAJOR_VERSION { 3 }; + inline constexpr int GLFW_MINOR_VERSION { 3 }; // best practice is to use inline constexpr std::string_view but glfwCreateWindow takes only char* as input inline const char* MAIN_WINDOW_NAME { "Match" }; inline constexpr int MAIN_WINDOW_WIDTH { 800 }; diff --git a/Engine/engine/draw.cpp b/Engine/engine/draw.cpp new file mode 100644 index 0000000..f3c84a8 --- /dev/null +++ b/Engine/engine/draw.cpp @@ -0,0 +1,93 @@ +#ifndef DRAW_CPP +#define DRAW_CPP +#include +#include +#include +#include "draw.hpp" +#include "renderLoop.hpp" +#include "shaders.hpp" +#include "constants.hpp" +#include "misc.hpp" + +int drawFigure(const bool whatToDraw) +{ + if(whatToDraw) + { + if(drawTriangle() == -1) + { + print("Error with drawing triangle! "); + return -1; + } + }else + { + if(drawSquare() == -1) + { + print("Error with drawing square! "); + return -1; + } + } + return 0; +} + +int drawSquare() +{ + std::pair shaders = compileShaders(); + if(shaders.first == 0 || shaders.second == 0) return -1; + + unsigned int shaderProgram = linkShaderObjectsShaderProgram(shaders.first, shaders.second); + if(shaderProgram == 0) return -1; + + unsigned int VAO = generateBindVAO(); + copyVerticesMemory(constants::SQUARE_VERTICES, constants::SQUARE_VERTICES_SIZE, GL_ARRAY_BUFFER); + 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); + + doDrawElements(shaderProgram, 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) +{ + glUseProgram(shaderProgram); + glBindVertexArray(vertexArrayObject); + glDrawElements(drawArrayMode, numberOfElementsToDraw, drawType, 0); + glBindVertexArray(0); +} + +int drawTriangle() +{ + unsigned int vertexBufferObject = copyVerticesMemory(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, GL_ARRAY_BUFFER); + + std::pair shaders = compileShaders(); + if(shaders.first == 0 || shaders.second == 0) return -1; + + unsigned int shaderProgram = linkShaderObjectsShaderProgram(shaders.first, shaders.second); + if(shaderProgram == 0) return -1; + + configureVertexAttribute(); + unsigned int vertexArrayObject = generateBindVAO(); + copyVerticesArray(vertexBufferObject, constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, GL_ARRAY_BUFFER); + + // set vertex attribute pointers + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + doDrawArrays(shaderProgram, vertexArrayObject, GL_TRIANGLES, 0, 3); + return 0; +} + +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); + glBindVertexArray(vertexArrayObject); + // From left: + // primitive type we want to draw + // starting index of vertex array + // how many vertices we want to draw + glDrawArrays(drawArrayMode, firstIndex, numberOfIndicesToBeRendered); +} + +#endif \ No newline at end of file diff --git a/Engine/engine/draw.hpp b/Engine/engine/draw.hpp new file mode 100644 index 0000000..634f778 --- /dev/null +++ b/Engine/engine/draw.hpp @@ -0,0 +1,12 @@ +#ifndef DRAW_HPP +#define DRAW_HPP +#include +#include + +int drawFigure(const bool whatToDraw); +int drawSquare(); +void doDrawElements(const unsigned int shaderProgram, const unsigned int vertexArrayObject, const GLenum drawArrayMode, const GLenum drawType, const int numberOfElementsToDraw); +int drawTriangle(); +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 old mode 100755 new mode 100644 index d786d84..8cada05 Binary files a/Engine/engine/match and b/Engine/engine/match differ diff --git a/Engine/engine/match.cpp b/Engine/engine/match.cpp index 9114656..3c57f97 100644 --- a/Engine/engine/match.cpp +++ b/Engine/engine/match.cpp @@ -1,375 +1,23 @@ #ifndef MAIN_CPP - +#define MAIN_CPP #include #include #include - #include // I am using standart library RNG because I am lazy and wanted to create quick code snippet // upgrade to this: https://arvid.io/2018/06/30/on-cxx-random-number-generator-quality/ whenever, if ever I feel like it #include // for std::chrono #include "constants.hpp" - -void configureGLFW() { - // first argument tells us what option to configure - // second is to what we set the value of this option - // see: https://www.glfw.org/docs/latest/window.html#window_hints - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - // we set GLFW to 3.3 CORE - // core profile gives us access to smaller subset of OGL without backwards compatible features - - // if we are on Mac OS X we need this for our code to work - #ifdef __APPLE__ - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); - #endif -} - -void instantiateGLFWwindow() { - // Initialize GLFW - glfwInit(); - configureGLFW(); -} - -GLFWwindow* createWindowObject() { - // First two arguments are width and height - // Third is the name of the window - // We ignore last two - GLFWwindow* window = glfwCreateWindow(constants::MAIN_WINDOW_WIDTH, constants::MAIN_WINDOW_HEIGHT, constants::MAIN_WINDOW_NAME, NULL, NULL); - return window; -} - -int initializeGLAD() -{ - // we load address of OGL OS-specific function pointers - if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) - { - std::cout << "Failed to initialize GLAD" << std::endl; - return -1; - } - return 0; -} - -// resizes viewport when user resizes window -void framebuffer_size_callback(GLFWwindow* window, int width, int height) -{ - glViewport(0, 0, width, height); -} - -void viewPort(GLFWwindow* window) -{ - // We tell OGL size of rendering window - // First two define left corner of window - // 3th and 4th width and height of rendering window - // we could set them to be smaller than window dimension, ogl rendering will be then displayed in smaller window - glViewport(0, 0, constants::MAIN_WINDOW_WIDTH, constants::MAIN_WINDOW_HEIGHT); - // processed coordinates are between -1 and 1 so here we map: - // (-1 to 1) to (0, constants::MAIN_WINDOW_WIDTH) and (0, constants::MAIN_WINDOW_HEIGHT) - glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); - // we call framebuffer_size_callback on every window resize -} - -bool processInput(GLFWwindow *window, bool whatToDraw) -{ - // glfwGetKey takes window and key as an input and checks is currently being pressed - // if the user pressed escape we close window - if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) - glfwSetWindowShouldClose(window, true); - if(glfwGetKey(window, GLFW_KEY_C) == GLFW_PRESS) - glfwSetWindowShouldClose(window, true); - if(glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS ) return !whatToDraw; - return whatToDraw; -} - -int shaderProgramLinkingSuccessful(const unsigned int shaderProgram) -{ - // check if compilation was successful - // int because glGetShaderiv requires int - int successfulLinking; - // here we store info about compilation - char infoLog[512]; - // check if compilation was successful - glGetProgramiv(shaderProgram, GL_LINK_STATUS, &successfulLinking); - // if not display compilation log - if(!successfulLinking) - { - glGetProgramInfoLog(shaderProgram, sizeof(infoLog) / sizeof(infoLog[0]), NULL, infoLog); - std::cout << "ERROR shaderProgram compilation failed \n" << infoLog << std::endl; - } - return successfulLinking; -} - - -int shaderCompilationSuccessful(const unsigned int shader) -{ - // check if compilation was successful - // int because glGetShaderiv requires int - int successfulCompilation; - // here we store info about compilation - char infoLog[512]; - // check if compilation was successful - glGetShaderiv(shader, GL_COMPILE_STATUS, &successfulCompilation); - // if not display compilation log - if(!successfulCompilation) - { - glGetShaderInfoLog(shader, sizeof(infoLog) / sizeof(infoLog[0]), NULL, infoLog); - std::cout << "ERROR vertex shader compilation failed \n" << infoLog << std::endl; - } - return successfulCompilation; -} - -unsigned int compileShader(const GLenum shaderType, const char * shaderSource) -{ - // we create vertex shader and assign its id to shader variable - unsigned int shaderID; - 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(!shaderCompilationSuccessful(shaderID)) return 0; - return shaderID; -} - -template -// https://stackoverflow.com/a/25680092 -unsigned int copyVerticesMemory(const T vertices[], const size_t sizeOfVertices, const GLenum boundBufferTarget) -{ - // stores vertices in gpu memory - unsigned int vertexBufferObject; - // this is open gl object so we refer it by its ID generated here and stored in vertexBufferObject variable - glGenBuffers(1, &vertexBufferObject); - // buffer type of vertex buffer object is GL_ARRAY_BUFFER - glBindBuffer(boundBufferTarget, vertexBufferObject); - // now whenever we change GL_ARRAY_BUFFER we change bound buffer vertexBufferObject - - /* we copy vertex data into buffer memory - GL_STREAM_DRAW: the data is set only once and used by the GPU at most a few times. - GL_STATIC_DRAW: the data is set only once and used many times. - GL_DYNAMIC_DRAW: the data is changed a lot and used many times. - */ - glBufferData(boundBufferTarget, sizeOfVertices, vertices, GL_STATIC_DRAW); - return vertexBufferObject; -} - -std::pair compileShaders() -{ - unsigned int vertexShader = compileShader(GL_VERTEX_SHADER, constants::vertexShaderSource); - if(vertexShader == 0) - { - std::cout << "Vertex Shader Compilation Failed" << std::endl; - return std::make_pair(0, 0); - } - - unsigned int fragmentShader = compileShader(GL_FRAGMENT_SHADER, constants::fragmentShaderSource); - if(fragmentShader == 0) - { - std::cout << "Fragment Shader Compilation Failed" << std::endl; - return std::make_pair(0, 0); - } - return std::make_pair(vertexShader, fragmentShader); -} - -unsigned int linkShaderObjectsShaderProgram(unsigned int vertexShaders, unsigned int fragmentShader) -{ - // link shader objects into shader program - // will store shader program id - unsigned int shaderProgram; - // creates program - shaderProgram = glCreateProgram(); - - // attachShaders - glAttachShader(shaderProgram, vertexShaders); - glAttachShader(shaderProgram, fragmentShader); - - // link shaders - glLinkProgram(shaderProgram); - if(!shaderProgramLinkingSuccessful(shaderProgram)) return 0; - - // activate program - // after that every shader and rendering call will use this program object - glUseProgram(shaderProgram); - - // delete shaders (they are linked into shaderProgram and we do not need them anymore) - glDeleteShader(vertexShaders); - glDeleteShader(fragmentShader); - if(shaderProgram == 0) std::cout << "Shader Program Linking Failed" << std::endl; - return shaderProgram; -} - -void configureVertexAttribute() -{ - // 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); - // enable vertex attribute - glEnableVertexAttribArray(0); -} - -unsigned int generateBindVAO() -{ - // vertex array object is used to draw objects by binding them to vao - // generate vao - unsigned int vertexArrayObject; - glGenVertexArrays(1, &vertexArrayObject); - // bind vao - glBindVertexArray(vertexArrayObject); - return vertexArrayObject; -} - -void copyVerticesArray(unsigned int vertexBufferObject, const float vertices[], const size_t sizeOfVertices, const GLenum boundBufferTarget) -{ - // copy vertices array in array useful for OGL - glBindBuffer(boundBufferTarget, vertexBufferObject); - glBufferData(boundBufferTarget, sizeOfVertices, vertices, GL_STATIC_DRAW); -} - -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); - glBindVertexArray(vertexArrayObject); - // From left: - // primitive type we want to draw - // starting index of vertex array - // how many vertices we want to draw - glDrawArrays(drawArrayMode, firstIndex, numberOfIndicesToBeRendered); -} - -int drawTriangle() -{ - unsigned int vertexBufferObject = copyVerticesMemory(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, GL_ARRAY_BUFFER); - - std::pair shaders = compileShaders(); - if(shaders.first == 0 || shaders.second == 0) return -1; - - unsigned int shaderProgram = linkShaderObjectsShaderProgram(shaders.first, shaders.second); - if(shaderProgram == 0) return -1; - - configureVertexAttribute(); - unsigned int vertexArrayObject = generateBindVAO(); - copyVerticesArray(vertexBufferObject, constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, GL_ARRAY_BUFFER); - - // set vertex attribute pointers - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); - glEnableVertexAttribArray(0); - doDrawArrays(shaderProgram, vertexArrayObject, GL_TRIANGLES, 0, 3); - return 0; -} - - -void doDrawElements(const unsigned int shaderProgram, const unsigned int vertexArrayObject, const GLenum drawArrayMode, const GLenum drawType, const int numberOfElementsToDraw) -{ - glUseProgram(shaderProgram); - glBindVertexArray(vertexArrayObject); - glDrawElements(drawArrayMode, numberOfElementsToDraw, drawType, 0); - glBindVertexArray(0); -} - -int drawSquare() -{ - std::pair shaders = compileShaders(); - if(shaders.first == 0 || shaders.second == 0) return -1; - - unsigned int shaderProgram = linkShaderObjectsShaderProgram(shaders.first, shaders.second); - if(shaderProgram == 0) return -1; - - unsigned int VAO = generateBindVAO(); - copyVerticesMemory(constants::SQUARE_VERTICES, constants::SQUARE_VERTICES_SIZE, GL_ARRAY_BUFFER); - 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); - - doDrawElements(shaderProgram, VAO, GL_TRIANGLES, GL_UNSIGNED_INT, std::size(constants::SQUARE_INDICES)); - return 0; -} - -int drawFigure(const bool whatToDraw) -{ - if(whatToDraw) - { - if(drawTriangle() == -1) - { - std::cout << "Error with drawing triangle! " << std::endl; - return -1; - } - }else - { - if(drawSquare() == -1) - { - std::cout << "Error with drawing square! " << std::endl; - return -1; - } - } - return 0; - -} - - - -void renderLoop(GLFWwindow* window) -{ - bool whatToDraw = true; - // glfwWindowShouldClose checks if GLFW was instructed to close - while(!glfwWindowShouldClose(window)) - { - // input - whatToDraw = processInput(window, whatToDraw); - // We specify the color to clear the screen with - // RGB and alpha value - glClearColor( constants::LEARN_OPEN_GL_COLOR.red, constants::LEARN_OPEN_GL_COLOR.green, constants::LEARN_OPEN_GL_COLOR.blue, constants::LEARN_OPEN_GL_COLOR.alpha); - // There is GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT and GL_STENCIL_BUFFER_BIT - glClear(GL_COLOR_BUFFER_BIT); - - if(drawFigure(whatToDraw) == -1) - { - std::cout << "error with drawing!" << std::endl; - glfwSetWindowShouldClose(window, true); - }; - - // swaps buffer containing color values of each pixel in window - // there is front buffer (final image) and back buffer (where all rendering commands draw to) - // when back buffer is ready we swap it with front buffer to eliminate flickering - glfwSwapBuffers(window); - - // glfwPollEvents checks if any event (like mouse/keyboard input was triggered), updates window state and calls functions (which we register via callback methods) - glfwPollEvents(); - } -} +#include "beforeRender.hpp" +#include "misc.hpp" +#include "renderLoop.hpp" int main() { - instantiateGLFWwindow(); - - GLFWwindow* window = createWindowObject(); - // function returns GLFWWindow object - - if (window == NULL) - { - std::cout << "Failed to create GLFW window" << std::endl; - glfwTerminate(); - return -1; - } - // we make context of this window main context of current thread - glfwMakeContextCurrent(window); - - if(initializeGLAD() == -1) return -1; - viewPort(window); + GLFWwindow* window = prepareForRender(); + if(window == NULL) return -1; renderLoop(window); // clean GLFW resources diff --git a/Engine/engine/misc.cpp b/Engine/engine/misc.cpp new file mode 100644 index 0000000..e3a8bae --- /dev/null +++ b/Engine/engine/misc.cpp @@ -0,0 +1,10 @@ +#ifndef MISC_CPP +#define MISC_CPP +#include +#include "misc.hpp" +void print(const std::string s) +{ + std::cout << s << std::endl; +} + +#endif \ No newline at end of file diff --git a/Engine/engine/misc.hpp b/Engine/engine/misc.hpp new file mode 100644 index 0000000..1aeec16 --- /dev/null +++ b/Engine/engine/misc.hpp @@ -0,0 +1,6 @@ +#ifndef MISC_HPP +#define MISC_HPP +#include + +void print(const std::string s); +#endif \ No newline at end of file diff --git a/Engine/engine/renderLoop.cpp b/Engine/engine/renderLoop.cpp new file mode 100644 index 0000000..2dceb21 --- /dev/null +++ b/Engine/engine/renderLoop.cpp @@ -0,0 +1,131 @@ +#ifndef RENDER_LOOP_CPP +#define RENDER_LOOP_CPP +#include +#include +#include +#include "renderLoop.hpp" +#include "draw.hpp" +#include "shaders.hpp" +#include "constants.hpp" +#include "misc.hpp" + +bool processInput(GLFWwindow *window, bool whatToDraw) +{ + // glfwGetKey takes window and key as an input and checks is currently being pressed + // if the user pressed escape we close window + if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); + if(glfwGetKey(window, GLFW_KEY_C) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); + if(glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS ) return !whatToDraw; + return whatToDraw; +} + +unsigned int compileShader(const GLenum shaderType, const char * shaderSource) +{ + // we create vertex shader and assign its id to shader variable + unsigned int shaderID; + 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(!shaderCompilationSuccessful(shaderID)) return 0; + return shaderID; +} + +template +// https://stackoverflow.com/a/25680092 +unsigned int copyVerticesMemory(const T vertices[], const size_t sizeOfVertices, const GLenum boundBufferTarget) +{ + // stores vertices in gpu memory + unsigned int vertexBufferObject; + // this is open gl object so we refer it by its ID generated here and stored in vertexBufferObject variable + glGenBuffers(1, &vertexBufferObject); + // buffer type of vertex buffer object is GL_ARRAY_BUFFER + glBindBuffer(boundBufferTarget, vertexBufferObject); + // now whenever we change GL_ARRAY_BUFFER we change bound buffer vertexBufferObject + + /* we copy vertex data into buffer memory + GL_STREAM_DRAW: the data is set only once and used by the GPU at most a few times. + GL_STATIC_DRAW: the data is set only once and used many times. + GL_DYNAMIC_DRAW: the data is changed a lot and used many times. + */ + glBufferData(boundBufferTarget, sizeOfVertices, vertices, GL_STATIC_DRAW); + return vertexBufferObject; +} + +void configureVertexAttribute() +{ + // 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); + // enable vertex attribute + glEnableVertexAttribArray(0); +} + +unsigned int generateBindVAO() +{ + // vertex array object is used to draw objects by binding them to vao + // generate vao + unsigned int vertexArrayObject; + glGenVertexArrays(1, &vertexArrayObject); + // bind vao + glBindVertexArray(vertexArrayObject); + return vertexArrayObject; +} + +void copyVerticesArray(unsigned int vertexBufferObject, const float vertices[], const size_t sizeOfVertices, const GLenum boundBufferTarget) +{ + // copy vertices array in array useful for OGL + glBindBuffer(boundBufferTarget, vertexBufferObject); + glBufferData(boundBufferTarget, sizeOfVertices, vertices, GL_STATIC_DRAW); +} + +bool renderLoopInside(GLFWwindow* window, bool whatToDraw) +{ + // input + whatToDraw = processInput(window, whatToDraw); + // We specify the color to clear the screen with + // RGB and alpha value + glClearColor( constants::LEARN_OPEN_GL_COLOR.red, constants::LEARN_OPEN_GL_COLOR.green, constants::LEARN_OPEN_GL_COLOR.blue, constants::LEARN_OPEN_GL_COLOR.alpha); + // There is GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT and GL_STENCIL_BUFFER_BIT + glClear(GL_COLOR_BUFFER_BIT); + + if(drawFigure(whatToDraw) == -1) + { + print("error with drawing!"); + glfwSetWindowShouldClose(window, true); + }; + + // swaps buffer containing color values of each pixel in window + // there is front buffer (final image) and back buffer (where all rendering commands draw to) + // when back buffer is ready we swap it with front buffer to eliminate flickering + glfwSwapBuffers(window); + + // glfwPollEvents checks if any event (like mouse/keyboard input was triggered), updates window state and calls functions (which we register via callback methods) + glfwPollEvents(); + return whatToDraw; +} + +void renderLoop(GLFWwindow* window) +{ + bool whatToDraw = true; + // glfwWindowShouldClose checks if GLFW was instructed to close + while(!glfwWindowShouldClose(window)) + { + whatToDraw = renderLoopInside(window, whatToDraw); + } +} + +#endif \ No newline at end of file diff --git a/Engine/engine/renderLoop.hpp b/Engine/engine/renderLoop.hpp new file mode 100644 index 0000000..09aafa9 --- /dev/null +++ b/Engine/engine/renderLoop.hpp @@ -0,0 +1,18 @@ +#ifndef RENDER_LOOP_HPP +#define RENDER_LOOP_HPP +#include +#include + + + +void renderLoop(GLFWwindow* window); +bool renderLoopInside(GLFWwindow* window, bool whatToDraw); +void copyVerticesArray(unsigned int vertexBufferObject, const float vertices[], const size_t sizeOfVertices, const GLenum boundBufferTarget); +unsigned int generateBindVAO(); +void configureVertexAttribute(); +bool processInput(GLFWwindow *window, bool whatToDraw); + +template unsigned int copyVerticesMemory(const T vertices[], const size_t sizeOfVertices, const GLenum boundBufferTarget); + + +#endif \ No newline at end of file diff --git a/Engine/engine/shaders.cpp b/Engine/engine/shaders.cpp new file mode 100644 index 0000000..8078f56 --- /dev/null +++ b/Engine/engine/shaders.cpp @@ -0,0 +1,91 @@ +#ifndef SHADERS_CPP +#define SHADERS_CPP +#include +#include +#include "shaders.hpp" +#include "constants.hpp" +#include "misc.hpp" + + +unsigned int linkShaderObjectsShaderProgram(unsigned int vertexShaders, unsigned int fragmentShader) +{ + // link shader objects into shader program + // will store shader program id + unsigned int shaderProgram; + // creates program + shaderProgram = glCreateProgram(); + + // attachShaders + glAttachShader(shaderProgram, vertexShaders); + glAttachShader(shaderProgram, fragmentShader); + + // link shaders + glLinkProgram(shaderProgram); + if(!shaderProgramLinkingSuccessful(shaderProgram)) return 0; + + // activate program + // after that every shader and rendering call will use this program object + glUseProgram(shaderProgram); + + // 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; +} + +std::pair compileShaders() +{ + unsigned int vertexShader = compileShader(GL_VERTEX_SHADER, constants::vertexShaderSource); + if(vertexShader == 0) + { + print("Vertex Shader Compilation Failed"); + return std::make_pair(0, 0); + } + + unsigned int fragmentShader = compileShader(GL_FRAGMENT_SHADER, constants::fragmentShaderSource); + if(fragmentShader == 0) + { + print("Fragment Shader Compilation Failed"); + return std::make_pair(0, 0); + } + return std::make_pair(vertexShader, fragmentShader); +} + +int shaderCompilationSuccessful(const unsigned int shader) +{ + // check if compilation was successful + // int because glGetShaderiv requires int + int successfulCompilation; + // here we store info about compilation + char infoLog[512]; + // check if compilation was successful + glGetShaderiv(shader, GL_COMPILE_STATUS, &successfulCompilation); + // if not display compilation log + if(!successfulCompilation) + { + glGetShaderInfoLog(shader, sizeof(infoLog) / sizeof(infoLog[0]), NULL, infoLog); + std::cout << "ERROR vertex shader compilation failed \n" << infoLog << std::endl; + } + return successfulCompilation; +} + +int shaderProgramLinkingSuccessful(const unsigned int shaderProgram) +{ + // check if compilation was successful + // int because glGetShaderiv requires int + int successfulLinking; + // here we store info about compilation + char infoLog[512]; + // check if compilation was successful + glGetProgramiv(shaderProgram, GL_LINK_STATUS, &successfulLinking); + // if not display compilation log + if(!successfulLinking) + { + glGetProgramInfoLog(shaderProgram, sizeof(infoLog) / sizeof(infoLog[0]), NULL, infoLog); + std::cout << "ERROR shaderProgram compilation failed \n" << infoLog << std::endl; + } + return successfulLinking; +} + +#endif \ No newline at end of file diff --git a/Engine/engine/shaders.hpp b/Engine/engine/shaders.hpp new file mode 100644 index 0000000..899a5f1 --- /dev/null +++ b/Engine/engine/shaders.hpp @@ -0,0 +1,14 @@ +#ifndef SHADERS_HPP +#define SHADERS_HPP +#include +#include +#include + +unsigned int linkShaderObjectsShaderProgram(unsigned int vertexShaders, unsigned int fragmentShader); +std::pair compileShaders(); +unsigned int compileShader(const GLenum shaderType, const char * shaderSource); +int shaderCompilationSuccessful(const unsigned int shader); +int shaderProgramLinkingSuccessful(const unsigned int shaderProgram); + + +#endif \ No newline at end of file