diff --git a/.vscode/settings.json b/.vscode/settings.json index c1547d3..0ad8168 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -87,7 +87,12 @@ "mutex": "cpp", "semaphore": "cpp", "stop_token": "cpp", - "thread": "cpp" + "thread": "cpp", + "codecvt": "cpp", + "set": "cpp", + "unordered_set": "cpp", + "iomanip": "cpp", + "variant": "cpp" }, "C_Cpp.errorSquiggles": "Disabled", "cSpell.words": [ diff --git a/Engine/engine/Shaders/fragmentShaderTexture.fs b/Engine/engine/Shaders/fragmentShaderTexture.fs new file mode 100644 index 0000000..a081fad --- /dev/null +++ b/Engine/engine/Shaders/fragmentShaderTexture.fs @@ -0,0 +1,12 @@ +#version 330 core +out vec4 FragColor; + +in vec3 ourColor; +in vec2 TexCoord; + +uniform sampler2D ourTexture; + +void main() +{ + FragColor = texture(ourTexture, TexCoord); +} \ No newline at end of file diff --git a/Engine/engine/Shaders/vertexShaderTexture.vs b/Engine/engine/Shaders/vertexShaderTexture.vs new file mode 100644 index 0000000..311ec24 --- /dev/null +++ b/Engine/engine/Shaders/vertexShaderTexture.vs @@ -0,0 +1,14 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec3 aColor; +layout (location = 2) in vec2 aTexCoord; + +out vec3 ourColor; +out vec2 TexCoord; + +void main() +{ + gl_Position = vec4(aPos, 1.0); + ourColor = aColor; + TexCoord = aTexCoord; +} \ No newline at end of file diff --git a/Engine/engine/constants.hpp b/Engine/engine/constants.hpp index 10662c8..b50529e 100644 --- a/Engine/engine/constants.hpp +++ b/Engine/engine/constants.hpp @@ -34,16 +34,6 @@ 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" } ; - inline const char* VERTEX_SHADER_COLOR_FILENAME { "./Shaders/vertexShaderColor.vs" }; @@ -59,6 +49,7 @@ namespace constants // 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 + // DO NOT REMOVE UNTIL CAN DRAW SQUARE USING CLASS inline const char *VERTEX_SHADER_SOURCE { "#version 330 core\n" "layout (location = 0) in vec3 aPos;\n" "void main()\n" @@ -70,16 +61,6 @@ namespace constants "./Shaders/vertexShaderSource.vs" }; - 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" } ; - inline const char* VERTEX_SHADER_VERTICE_COLOR_FILENAME { "./Shaders/vertexShaderVerticeColor.vs" }; @@ -88,42 +69,25 @@ namespace constants "./Shaders/vertexShaderTaskThree.vs" }; + inline const char* VERTEX_SHADER_TEXTURE_FILENAME { + "./Shaders/vertexShaderTexture.vs" + }; + inline const char* FRAGMENT_SHADER_TASK_THREE_FILENAME { "./Shaders/fragmentShaderTaskThree.fs" }; - // ... 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" - }; - inline const char* FRAGMENT_SHADER_COLOR_FROM_VERTEX_FILENAME { "./Shaders/fragmentShaderColorFromVertex.fs" }; - // 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" - }; - inline const char* FRAGMENT_SHADER_UNIFORMS_FILENAME { "./Shaders/fragmentShaderUniforms.fs" }; // write fragment shader // we set the color of each pixel to be orange + // DO NOT REMOVE UNTIL CAN DRAW SQUARE USING CLASS inline const char *FRAGMENT_SHADER_SOURCE { "#version 330 core\n" "out vec4 FragColor;\n" @@ -136,20 +100,15 @@ namespace constants inline const char* FRAGMENT_SHADER_SOURCE_FILENAME { "./Shaders/fragmentShaderSource.fs" }; - - inline const char *FRAGMENT_SHADER_SOURCE_YELLOW { - "#version 330 core\n" - "out vec4 FragColor;\n" - "void main()\n" - "{\n" - "FragColor = vec4(1.0f, 1.0f, 0.0f, 1.0f);\n" - "}\0" - }; - + inline const char* FRAGMENT_SHADER_SOURCE_YELLOW_FILENAME { "./Shaders/fragmentShaderSourceYellow.fs" }; + inline const char* FRAGMENT_SHADER_TEXTURE_FILENAME { + ".Shaders/fragmentShaderTexture.fs" + }; + // we specify three vertices // each of them with position in 3d space // x y z @@ -231,7 +190,7 @@ namespace constants inline constexpr size_t SQUARE_VERTICES_SIZE = { sizeof(SQUARE_VERTICES) }; - inline constexpr int MAX_DRAW_CALL = { 10 }; + inline constexpr int MAX_DRAW_CALL = { 11 }; // https://learnopengl.com/img/getting-started/tex_coords.png inline constexpr float TEXTURE_COORDINATES[] { @@ -240,6 +199,16 @@ namespace constants 0.5f, 1.0f // top-center corner }; + inline constexpr float POSITION_COLOR_TEXTURE[] { + // positions // colors // texture coords + 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right + 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right + -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left + -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left + }; + + inline constexpr size_t POSITION_COLOR_TEXTURE_SIZE = { sizeof(POSITION_COLOR_TEXTURE) }; + } #endif \ No newline at end of file diff --git a/Engine/engine/draw.cpp b/Engine/engine/draw.cpp index 2ecc245..c37d339 100644 --- a/Engine/engine/draw.cpp +++ b/Engine/engine/draw.cpp @@ -10,6 +10,7 @@ #include "constants.hpp" #include "misc.hpp" #include "shader.hpp" +#include "textures.hpp" int drawFigure(const int whatToDraw) { @@ -45,10 +46,12 @@ int drawFigure(const int whatToDraw) // offset triangle offsetsStruct offsets = offsetsStruct(); offsets.xOffset = 0.5f; - return drawTriangleClass(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, constants::VERTEX_SHADER_OFFSET_FILENAME, constants::FRAGMENT_SHADER_SOURCE_FILENAME, false, offsets); + return drawTriangleClass(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, constants::VERTEX_SHADER_OFFSET_FILENAME, constants::FRAGMENT_SHADER_SOURCE_FILENAME, false, false, offsets); } - case constants::MAX_DRAW_CALL: + case 10: return drawTriangleClass(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, constants::VERTEX_SHADER_TASK_THREE_FILENAME, constants::FRAGMENT_SHADER_TASK_THREE_FILENAME); + case constants::MAX_DRAW_CALL: + return drawTriangleClass(constants::POSITION_COLOR_TEXTURE, constants::POSITION_COLOR_TEXTURE_SIZE, constants::VERTEX_SHADER_TEXTURE_FILENAME, constants::FRAGMENT_SHADER_TEXTURE_FILENAME, true, true); default: throw "No function for this draw call"; } @@ -72,7 +75,7 @@ void setOffsets(Shader shader, const offsetsStruct offsets) { shader.setFloat("zOffset", offsets.zOffset); } -int drawTriangleClass(const float triangleVertices[], const size_t triangleVerticesSize, const char* vertexPath, const char* fragmentPath, const bool colorIncluded, const offsetsStruct offsets) +int drawTriangleClass(const float triangleVertices[], const size_t triangleVerticesSize, const char* vertexPath, const char* fragmentPath, const bool colorIncluded, const bool textureIncluded, const offsetsStruct offsets) { // In your CPP file: // ====================== @@ -87,12 +90,12 @@ int drawTriangleClass(const float triangleVertices[], const size_t triangleVerti copyVerticesArray(vertexBufferObject, triangleVertices, triangleVerticesSize, GL_ARRAY_BUFFER); // set vertex attribute pointers - configureVertexAttribute(colorIncluded); + configureVertexAttribute(colorIncluded, textureIncluded); doDrawArrays(ourShader.ID, vertexArrayObject, GL_TRIANGLES, 0, triangleVerticesSize); return 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 char* vertexShaderSource, const char* fragmentShaderSource, const bool colorIncluded, const bool textureIncluded) { const unsigned int shaderProgram = getShaderProgram(vertexShaderSource, fragmentShaderSource); @@ -104,7 +107,7 @@ int drawTriangle(const float triangleVertices[], const size_t triangleVerticesSi copyVerticesArray(vertexBufferObject, triangleVertices, triangleVerticesSize, GL_ARRAY_BUFFER); // set vertex attribute pointers - configureVertexAttribute(colorIncluded); + configureVertexAttribute(colorIncluded, textureIncluded); doDrawArrays(shaderProgram, vertexArrayObject, GL_TRIANGLES, 0, triangleVerticesSize); return 0; } @@ -119,7 +122,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 - configureVertexAttribute(false); + configureVertexAttribute(false, false); doDrawElements(shaderProgram, VAO, GL_TRIANGLES, GL_UNSIGNED_INT, std::size(constants::SQUARE_INDICES)); return 0; @@ -134,7 +137,7 @@ int drawSquareClass(const char* vertexPath, const char* fragmentPath) copyVerticesArray(vertexBufferObject, constants::SQUARE_VERTICES, constants::SQUARE_VERTICES_SIZE, GL_ARRAY_BUFFER); // set vertex attribute pointers - configureVertexAttribute(false); + configureVertexAttribute(false, false); doDrawArrays(ourShader.ID, vertexArrayObject, GL_TRIANGLES, 0, constants::SQUARE_VERTICES_SIZE); return 0; } @@ -172,6 +175,8 @@ void doDrawArrays(const unsigned int shaderProgram, const unsigned int vertexArr // use shader program to render an object glUseProgram(shaderProgram); updateUniformColor(shaderProgram, "ourColor"); + const unsigned int texture = generateTexture("./assets/Preview.png", 500, 500, 3); + glBindTexture(GL_TEXTURE_2D, texture); glBindVertexArray(vertexArrayObject); // From left: // primitive type we want to draw @@ -180,4 +185,11 @@ void doDrawArrays(const unsigned int shaderProgram, const unsigned int vertexArr glDrawArrays(drawArrayMode, firstIndex, numberOfIndicesToBeRendered); } +int drawTexture() { + // we added new vertex attribute and need to inform opengl that we done so + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); + glEnableVertexAttribArray(2); + return -1; +} + #endif \ No newline at end of file diff --git a/Engine/engine/draw.hpp b/Engine/engine/draw.hpp index 6eee203..efe4b1f 100644 --- a/Engine/engine/draw.hpp +++ b/Engine/engine/draw.hpp @@ -13,8 +13,9 @@ int drawFigure(const int whatToDraw); int drawSquare(const char* vertexShaderSource, const char* fragmentShaderSource); int drawSquareClass(const char* vertexPath, const char* fragmentPath); 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); -int drawTriangleClass(const float triangleVertices[], const size_t triangleVerticesSize, const char* vertexPath, const char* fragmentPath, const bool colorIncluded = false, const offsetsStruct offsets = offsetsStruct()); +int drawTriangleClass(const float triangleVertices[], const size_t triangleVerticesSize, const char* vertexPath, const char* fragmentPath, const bool colorIncluded = false, const bool textureIncluded = false, const offsetsStruct offsets = offsetsStruct()); +int drawTriangle(const float triangleVertices[], const size_t triangleVerticesSize, const char* vertexShaderSource, const char* fragmentShaderSource, const bool colorIncluded = false, const bool textureIncluded = false); +int drawTexture(); 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 ); unsigned int drawSquareShaderProgram(const char* vertexShaderSource, const char* fragmentShaderSource); diff --git a/Engine/engine/match b/Engine/engine/match index 76d46bd..e702d82 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 5e94d71..a713108 100644 --- a/Engine/engine/renderLoop.cpp +++ b/Engine/engine/renderLoop.cpp @@ -78,7 +78,7 @@ unsigned int copyVerticesMemory(const unsigned int vertices[], const size_t size return vertexBufferObject; } -void configureVertexAttribute(const bool colorIncluded) +void configureVertexAttribute(const bool colorIncluded, const bool textureIncluded) { /* specify how OGL interprets vertex data From left: @@ -97,16 +97,38 @@ void configureVertexAttribute(const bool colorIncluded) 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); + + if(colorIncluded && !textureIncluded) { + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)0); + // enable vertex attribute + glEnableVertexAttribArray(0); + + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)(3* sizeof(float))); + // enable vertex attribute + glEnableVertexAttribArray(1); + return; + } + + // Since we've added an extra vertex attribute we again have to notify OpenGL of the new vertex format + // this time for textures we add just 2 more attributes and not 3 as with color + if(textureIncluded) { + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)0); + // enable vertex attribute + glEnableVertexAttribArray(0); + + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(3* sizeof(float))); + // enable vertex attribute + glEnableVertexAttribArray(1); + + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); + glEnableVertexAttribArray(2); + return; + } } unsigned int generateBindVAO() diff --git a/Engine/engine/renderLoop.hpp b/Engine/engine/renderLoop.hpp index 536385d..3c16f64 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(const bool colorIncluded); +void configureVertexAttribute(const bool colorIncluded, const bool textureIncluded); int processInput(GLFWwindow *window, int whatToDraw); unsigned int copyVerticesMemory(const float vertices[], const size_t sizeOfVertices, const GLenum boundBufferTarget); diff --git a/Engine/engine/textures.cpp b/Engine/engine/textures.cpp index 370a8c7..6a97d06 100644 --- a/Engine/engine/textures.cpp +++ b/Engine/engine/textures.cpp @@ -72,5 +72,46 @@ void setTextureFilteringAndMipMap(const GLenum textureTarget, const GLenum filte glTexParameteri(textureTarget, filterType, textureFilteringMethod); } +unsigned char *loadTexture(const char* texturePath, int textureWidth, int textureHeight, int colorChannels) +{ + // first argument is the location of an image + // second and third is its width and height + // fourth is number of color channels + unsigned char *data = stbi_load(texturePath, &textureWidth, &textureHeight, &colorChannels, 0); + return data; +} + +unsigned int generateTexture(const char* texturePath, const int textureWidth, const int textureHeight, const int colorChannels) { + unsigned int texture; + // first argument is how many textures we want to generate + // second is an array of unsigned int in which we will store id of those textures + glGenTextures(1, &texture); + // then we bind texture + glBindTexture(GL_TEXTURE_2D, texture); + + unsigned char *data = loadTexture(texturePath, textureWidth, textureHeight, colorChannels); + if(data) { + // generate texture + /* + first argument is texture target, setting it to GL_TEXTURE_2D will only affect 2D targets and not 1D or 3D + 2nd is mipmap level for which to create texture, base level is 0 + 3rd is in what format we want to store texture (our image has only rgb values so rgb) + 4th and 5th are the width and height of texture + 6th argument is always 0 (legacy, its called border parameter) + 7th and 8th are the format and datatype of source image, we store the image data as chars (bytes) so we pass that + 9th last argument is actual data of the texture + */ + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textureWidth, textureHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + // after generating texture, lets free the memory from image + stbi_image_free(data); + return texture; + } + else + { + std::cout << "Failed to load texture! " << std::endl; + return -1; + } +} #endif // TEXTURES_CPP diff --git a/Engine/engine/textures.hpp b/Engine/engine/textures.hpp index b17dc4b..aa9af15 100644 --- a/Engine/engine/textures.hpp +++ b/Engine/engine/textures.hpp @@ -1,5 +1,6 @@ #ifndef TEXTURES_HPP #define TEXTURES_HPP +#include #include #include @@ -8,5 +9,7 @@ void setTextureSCoordinate(const GLenum textureTarget = GL_TEXTURE_2D, const GLi void setTextureTCoordinate(const GLenum textureTarget = GL_TEXTURE_2D, const GLint tCoordinateOption = GL_REPEAT, const float* borderColor = NULL); void setTextureRCoordinate(const GLenum textureTarget = GL_TEXTURE_3D, const GLint rCoordinateOption = GL_REPEAT, const float* borderColor = NULL); void setTextureFilteringAndMipMap(const GLenum textureTarget = GL_TEXTURE_2D, const GLenum filterType = GL_TEXTURE_MAG_FILTER, const GLint textureFilteringMethod = GL_NEAREST, const GLint mipMapFilteringMethod = GL_NEAREST_MIPMAP_NEAREST); +unsigned int generateTexture(const char* texturePath, const int textureWidth, const int textureHeight, const int colorChannels); +unsigned char* loadTexture(const char* texturePath, int textureWidth, int textureHeight, int colorChannels); #endif // TEXTURES_HPP \ No newline at end of file