#ifndef DRAW_CPP #define DRAW_CPP #include #include #include #include #include #include "draw.hpp" #include "renderLoop.hpp" #include "shaders.hpp" #include "constants.hpp" #include "misc.hpp" #include "shader.hpp" #include "textures.hpp" #include "stb_image.h" int drawFigure(const int whatToDraw) { switch (whatToDraw) { case 0: return drawTriangleClass(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, constants::VERTEX_SHADER_SOURCE_FILENAME, constants::FRAGMENT_SHADER_SOURCE_FILENAME); case 1: return drawSquare(constants::SQUARE_VERTICES, constants::SQUARE_VERTICES_SIZE, constants::SQUARE_INDICES, constants::SQUARE_INDICES_SIZE, 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 drawTriangleClass(constants::TRIANGLES_VERTICES, constants::TRIANGLES_VERTICES_SIZE, constants::VERTEX_SHADER_SOURCE_FILENAME, constants::FRAGMENT_SHADER_SOURCE_FILENAME); case 3: // Now create the same 2 triangles using two different VAOs and VBOs for their data return (drawTriangleClass(constants::TRIANGLE_ONE, constants::TRIANGLE_ONE_SIZE, constants::VERTEX_SHADER_SOURCE_FILENAME, constants::FRAGMENT_SHADER_SOURCE_FILENAME) == -1 || drawTriangleClass(constants::TRIANGLE_TWO, constants::TRIANGLE_TWO_SIZE, constants::VERTEX_SHADER_SOURCE_FILENAME, constants::FRAGMENT_SHADER_SOURCE_FILENAME) == -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 (drawTriangleClass(constants::TRIANGLE_ONE, constants::TRIANGLE_ONE_SIZE, constants::VERTEX_SHADER_SOURCE_FILENAME, constants::FRAGMENT_SHADER_SOURCE_FILENAME) == -1 || drawTriangleClass(constants::TRIANGLE_TWO, constants::TRIANGLE_TWO_SIZE, constants::VERTEX_SHADER_SOURCE_FILENAME, constants::FRAGMENT_SHADER_SOURCE_YELLOW_FILENAME) == -1); case 5: // Get color from vertex shader to fragment shader return drawTriangleClass(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, constants::VERTEX_SHADER_COLOR_FILENAME, constants::FRAGMENT_SHADER_COLOR_FROM_VERTEX_FILENAME); case 6: // set color from opengl code to uniform value in fragment shader return drawTriangleClass(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, constants::VERTEX_SHADER_COLOR_FILENAME, constants::FRAGMENT_SHADER_UNIFORMS_FILENAME); case 7: // set color from opengl code to uniform value in fragment shader return drawTriangleClass(constants::TRIANGLE_COLORS, constants::TRIANGLE_COLORS_SIZE, constants::VERTEX_SHADER_VERTICE_COLOR_FILENAME, constants::FRAGMENT_SHADER_COLOR_FROM_VERTEX_FILENAME, true); case 8: // upside down triangle return drawTriangleClass(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, constants::VERTEX_SHADER_UPSIDE_DOWN_FILENAME, constants::FRAGMENT_SHADER_SOURCE_FILENAME); case 9: { // 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, false, offsets); } 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 drawDebilMode(); default: throw "No function for this draw call"; } } unsigned int getShaderProgram(const char* vertexShaderSource, const char* fragmentShaderSource) { const std::pair shaders = compileShaders(vertexShaderSource, fragmentShaderSource); if (shaders.first == 0 || shaders.second == 0) return 0; const unsigned int shaderProgram = linkShaderObjectsShaderProgram(shaders.first, shaders.second); if (shaderProgram == 0) return 0; return shaderProgram; } void setOffsets(Shader shader, const offsetsStruct offsets) { shader.setFloat("xOffset", offsets.xOffset); shader.setFloat("yOffset", offsets.yOffset); shader.setFloat("zOffset", offsets.zOffset); } 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: // ====================== // float offset = 0.5f; Shader ourShader(vertexPath, fragmentPath); ourShader.use(); setOffsets(ourShader, offsets); const unsigned int vertexBufferObject = copyVerticesMemory(triangleVertices, triangleVerticesSize, GL_ARRAY_BUFFER); const unsigned int vertexArrayObject = generateBindVAO(); copyVerticesArray(vertexBufferObject, triangleVertices, triangleVerticesSize, GL_ARRAY_BUFFER); // set vertex attribute pointers 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, const bool textureIncluded) { const unsigned int shaderProgram = getShaderProgram(vertexShaderSource, fragmentShaderSource); if (shaderProgram == 0) return -1; const unsigned int vertexBufferObject = copyVerticesMemory(triangleVertices, triangleVerticesSize, GL_ARRAY_BUFFER); const unsigned int vertexArrayObject = generateBindVAO(); copyVerticesArray(vertexBufferObject, triangleVertices, triangleVerticesSize, GL_ARRAY_BUFFER); // set vertex attribute pointers configureVertexAttribute(colorIncluded, textureIncluded); doDrawArrays(shaderProgram, vertexArrayObject, GL_TRIANGLES, 0, triangleVerticesSize); return 0; } int drawSquare(const float squareVertices[], const size_t squareVerticesSize, const unsigned int squareIndices[], const size_t squareIndicesSize, const char* vertexShaderSource, const char* fragmentShaderSource, const bool colorIncluded, const bool textureIncluded, const offsetsStruct offsets) { const unsigned int shaderProgram = getShaderProgram(vertexShaderSource, fragmentShaderSource); if (shaderProgram == 0) return -1; const unsigned int VAO = generateBindVAO(); copyVerticesMemory(squareVertices, squareVerticesSize, GL_ARRAY_BUFFER); copyVerticesMemory(squareIndices, squareIndicesSize, GL_ELEMENT_ARRAY_BUFFER); // set vertex attribute pointers configureVertexAttribute(colorIncluded, textureIncluded); doDrawElements(shaderProgram, VAO, GL_TRIANGLES, GL_UNSIGNED_INT, squareIndicesSize); return 0; } int drawSquareClass(const char* vertexPath, const char* fragmentPath, const bool colorIncluded, const bool textureIncluded, const offsetsStruct offsets) { Shader ourShader(vertexPath, fragmentPath); ourShader.use(); const unsigned int vertexBufferObject = copyVerticesMemory(constants::SQUARE_VERTICES, constants::SQUARE_VERTICES_SIZE, GL_ARRAY_BUFFER); const unsigned int vertexArrayObject = generateBindVAO(); copyVerticesArray(vertexBufferObject, constants::SQUARE_VERTICES, constants::SQUARE_VERTICES_SIZE, GL_ARRAY_BUFFER); // set vertex attribute pointers configureVertexAttribute(false, false); doDrawArrays(ourShader.ID, vertexArrayObject, GL_TRIANGLES, 0, constants::SQUARE_VERTICES_SIZE); return 0; } int drawDebilMode() { // https://stackoverflow.com/questions/33883609/opengl-linker-error-linking-with-uncompiled-shader Shader ourShader(constants::VERTEX_SHADER_TEXTURE_FILENAME, constants::FRAGMENT_SHADER_TEXTURE_FILENAME); float vertices[] = { // 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 }; unsigned int indices[] = { 0, 1, 3, // first triangle 1, 2, 3 // second triangle }; unsigned int VBO, VAO, EBO; glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glGenBuffers(1, &EBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // position attribute glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); // color attribute glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); // texture coord attribute glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); glEnableVertexAttribArray(2); // load and create a texture // ------------------------- unsigned int texture1, texture2; // texture 1 // --------- glGenTextures(1, &texture1); glBindTexture(GL_TEXTURE_2D, texture1); // set the texture wrapping parameters glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // set texture filtering parameters glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // load image, create texture and generate mipmaps int width = 430, height = 288, nrChannels; stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis. // The FileSystem::getPath(...) is part of the GitHub repository so we can find files on any IDE/platform; replace it with your own image path. unsigned char *data = stbi_load("assets/Preview.png", &width, &height, &nrChannels, 0); if (data) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); } else { stbi_image_free(data); std::cout << "Failed to load texture" << std::endl; } stbi_image_free(data); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture1); ourShader.use(); // don't forget to activate/use the shader before setting uniforms! // or set it via the texture class ourShader.setInt("texture1", 1); glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glDeleteVertexArrays(1, &VAO); glDeleteBuffers(1, &VBO); glDeleteBuffers(1, &EBO); 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); } 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"); const unsigned int texture = generateTexture("./assets/Preview.png", 430, 288, 3); glBindTexture(GL_TEXTURE_2D, texture); 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 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