diff --git a/src/1.getting_started/1.1.hello_window/hello_window.cpp b/src/1.getting_started/1.1.hello_window/hello_window.cpp new file mode 100644 index 0000000..ee6d191 --- /dev/null +++ b/src/1.getting_started/1.1.hello_window/hello_window.cpp @@ -0,0 +1,74 @@ +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/1.2.hello_window_clear/hello_window_clear.cpp b/src/1.getting_started/1.2.hello_window_clear/hello_window_clear.cpp new file mode 100644 index 0000000..30ecaee --- /dev/null +++ b/src/1.getting_started/1.2.hello_window_clear/hello_window_clear.cpp @@ -0,0 +1,79 @@ +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/1.hello_window/hellowindow2.cpp b/src/1.getting_started/1.hello_window/hellowindow2.cpp deleted file mode 100644 index 67eaaaa..0000000 --- a/src/1.getting_started/1.hello_window/hellowindow2.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include - -// GLEW -#define GLEW_STATIC -#include - -// GLFW -#include - - -// Function prototypes -void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); - -// Window dimensions -const GLuint WIDTH = 800, HEIGHT = 600; - -// The MAIN function, from here we start the application and run the game loop -int main() -{ - std::cout << "Starting GLFW context, OpenGL 3.3" << std::endl; - // Init GLFW - glfwInit(); - // Set all the required options for GLFW - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); - - // Create a GLFWwindow object that we can use for GLFW's functions - GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr); - glfwMakeContextCurrent(window); - if (window == NULL) - { - std::cout << "Failed to create GLFW window" << std::endl; - glfwTerminate(); - return -1; - } - - // Set the required callback functions - glfwSetKeyCallback(window, key_callback); - - // Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions - glewExperimental = GL_TRUE; - // Initialize GLEW to setup the OpenGL Function pointers - if (glewInit() != GLEW_OK) - { - std::cout << "Failed to initialize GLEW" << std::endl; - return -1; - } - - // Define the viewport dimensions - int width, height; - glfwGetFramebufferSize(window, &width, &height); - glViewport(0, 0, width, height); - - // Game loop - while (!glfwWindowShouldClose(window)) - { - // Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions - glfwPollEvents(); - - // Render - // Clear the colorbuffer - glClearColor(0.2f, 0.3f, 0.3f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - - // Swap the screen buffers - glfwSwapBuffers(window); - } - - // Terminate GLFW, clearing any resources allocated by GLFW. - glfwTerminate(); - return 0; -} - -// Is called whenever a key is pressed/released via GLFW -void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) -{ - std::cout << key << std::endl; - if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) - glfwSetWindowShouldClose(window, GL_TRUE); -} \ No newline at end of file diff --git a/src/1.getting_started/1.hello_window/shader.frag b/src/1.getting_started/1.hello_window/shader.frag deleted file mode 100644 index 0b9522c..0000000 --- a/src/1.getting_started/1.hello_window/shader.frag +++ /dev/null @@ -1 +0,0 @@ -swag_frag \ No newline at end of file diff --git a/src/1.getting_started/1.hello_window/shader.vs b/src/1.getting_started/1.hello_window/shader.vs deleted file mode 100644 index 3bf6f5f..0000000 --- a/src/1.getting_started/1.hello_window/shader.vs +++ /dev/null @@ -1 +0,0 @@ -swag \ No newline at end of file diff --git a/src/1.getting_started/2.1.hello_triangle/hello_triangle.cpp b/src/1.getting_started/2.1.hello_triangle/hello_triangle.cpp new file mode 100644 index 0000000..8e5b515 --- /dev/null +++ b/src/1.getting_started/2.1.hello_triangle/hello_triangle.cpp @@ -0,0 +1,175 @@ +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +const char *vertexShaderSource = "#version 330 core\n" + "layout (location = 0) in vec3 aPos;\n" + "void main()\n" + "{\n" + " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" + "}\0"; +const char *fragmentShaderSource = "#version 330 core\n" + "out vec4 fragColor;\n" + "void main()\n" + "{\n" + " fragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" + "}\n\0"; + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + + // build and compile our shader program + // ------------------------------------ + // vertex shader + int vertexShader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); + glCompileShader(vertexShader); + // check for shader compile errors + int success; + char infoLog[512]; + glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; + } + // fragment shader + int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); + glCompileShader(fragmentShader); + // check for shader compile errors + glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl; + } + // link shaders + int shaderProgram = glCreateProgram(); + glAttachShader(shaderProgram, vertexShader); + glAttachShader(shaderProgram, fragmentShader); + glLinkProgram(shaderProgram); + // check for linking errors + glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); + if (!success) { + glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; + } + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + float vertices[] = { + -0.5f, -0.5f, 0.0f, // left + 0.5f, -0.5f, 0.0f, // right + 0.0f, 0.5f, 0.0f // top + }; + + unsigned int VBO, VAO; + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s). + glBindVertexArray(VAO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + + // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind + glBindBuffer(GL_ARRAY_BUFFER, 0); + + // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other + // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary. + glBindVertexArray(0); + + + // uncomment this call to draw in wireframe polygons. + //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // draw our first triangle + glUseProgram(shaderProgram); + glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized + glDrawArrays(GL_TRIANGLES, 0, 3); + // glBindVertexArray(0); // no need to unbind it every time + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/2.2.hello_triangle_indexed/hello_triangle_indexed.cpp b/src/1.getting_started/2.2.hello_triangle_indexed/hello_triangle_indexed.cpp new file mode 100644 index 0000000..cd2a2a0 --- /dev/null +++ b/src/1.getting_started/2.2.hello_triangle_indexed/hello_triangle_indexed.cpp @@ -0,0 +1,188 @@ +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +const char *vertexShaderSource = "#version 330 core\n" + "layout (location = 0) in vec3 aPos;\n" + "void main()\n" + "{\n" + " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" + "}\0"; +const char *fragmentShaderSource = "#version 330 core\n" + "out vec4 fragColor;\n" + "void main()\n" + "{\n" + " fragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" + "}\n\0"; + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + + // build and compile our shader program + // ------------------------------------ + // vertex shader + int vertexShader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); + glCompileShader(vertexShader); + // check for shader compile errors + int success; + char infoLog[512]; + glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; + } + // fragment shader + int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); + glCompileShader(fragmentShader); + // check for shader compile errors + glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl; + } + // link shaders + int shaderProgram = glCreateProgram(); + glAttachShader(shaderProgram, vertexShader); + glAttachShader(shaderProgram, fragmentShader); + glLinkProgram(shaderProgram); + // check for linking errors + glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); + if (!success) { + glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; + } + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + float vertices[] = { + 0.5f, 0.5f, 0.0f, // top right + 0.5f, -0.5f, 0.0f, // bottom right + -0.5f, -0.5f, 0.0f, // bottom left + -0.5f, 0.5f, 0.0f // top left + }; + unsigned int indices[] = { // note that we start from 0! + 0, 1, 3, // first Triangle + 1, 2, 3 // second Triangle + }; + unsigned int VBO, VAO, EBO; + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + glGenBuffers(1, &EBO); + // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s). + 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); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + + // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind + glBindBuffer(GL_ARRAY_BUFFER, 0); + + // remember: do NOT unbind the EBO while a VAO is active as the bound element buffer object IS stored in the VAO; keep the EBO bound. + //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other + // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary. + glBindVertexArray(0); + + + // uncomment this call to draw in wireframe polygons. + //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // draw our first triangle + glUseProgram(shaderProgram); + glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized + //glDrawArrays(GL_TRIANGLES, 0, 6); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + // glBindVertexArray(0); // no need to unbind it every time + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + glDeleteBuffers(1, &EBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/2.3.hello_triangle_exercise1/hello_triangle_exercise1.cpp b/src/1.getting_started/2.3.hello_triangle_exercise1/hello_triangle_exercise1.cpp new file mode 100644 index 0000000..a6eefa7 --- /dev/null +++ b/src/1.getting_started/2.3.hello_triangle_exercise1/hello_triangle_exercise1.cpp @@ -0,0 +1,181 @@ +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +const char *vertexShaderSource = "#version 330 core\n" + "layout (location = 0) in vec3 aPos;\n" + "void main()\n" + "{\n" + " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" + "}\0"; +const char *fragmentShaderSource = "#version 330 core\n" + "out vec4 fragColor;\n" + "void main()\n" + "{\n" + " fragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" + "}\n\0"; + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + + // build and compile our shader program + // ------------------------------------ + // vertex shader + int vertexShader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); + glCompileShader(vertexShader); + // check for shader compile errors + int success; + char infoLog[512]; + glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; + } + // fragment shader + int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); + glCompileShader(fragmentShader); + // check for shader compile errors + glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl; + } + // link shaders + int shaderProgram = glCreateProgram(); + glAttachShader(shaderProgram, vertexShader); + glAttachShader(shaderProgram, fragmentShader); + glLinkProgram(shaderProgram); + // check for linking errors + glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); + if (!success) { + glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; + } + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + // add a new set of vertices to form a second triangle (a total of 6 vertices); the vertex attribute configuration remains the same (still one 3-float position vector per vertex) + float vertices[] = { + // first triangle + -0.9f, -0.5f, 0.0f, // left + -0.0f, -0.5f, 0.0f, // right + -0.45f, 0.5f, 0.0f, // top + // second triangle + 0.0f, -0.5f, 0.0f, // left + 0.9f, -0.5f, 0.0f, // right + 0.45f, 0.5f, 0.0f // top + }; + + unsigned int VBO, VAO; + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s). + glBindVertexArray(VAO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + + // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind + glBindBuffer(GL_ARRAY_BUFFER, 0); + + // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other + // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary. + glBindVertexArray(0); + + + // uncomment this call to draw in wireframe polygons. + //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // draw our first triangle + glUseProgram(shaderProgram); + glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized + glDrawArrays(GL_TRIANGLES, 0, 6); // set the count to 6 since we're drawing 6 vertices now (2 triangles); not 3! + // glBindVertexArray(0); // no need to unbind it every time + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/2.4.hello_triangle_exercise2/hello_triangle_exercise2.cpp b/src/1.getting_started/2.4.hello_triangle_exercise2/hello_triangle_exercise2.cpp new file mode 100644 index 0000000..994552e --- /dev/null +++ b/src/1.getting_started/2.4.hello_triangle_exercise2/hello_triangle_exercise2.cpp @@ -0,0 +1,182 @@ +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +const char *vertexShaderSource = "#version 330 core\n" + "layout (location = 0) in vec3 aPos;\n" + "void main()\n" + "{\n" + " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" + "}\0"; +const char *fragmentShaderSource = "#version 330 core\n" + "out vec4 fragColor;\n" + "void main()\n" + "{\n" + " fragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" + "}\n\0"; + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + + // build and compile our shader program + // ------------------------------------ + // vertex shader + int vertexShader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); + glCompileShader(vertexShader); + // check for shader compile errors + int success; + char infoLog[512]; + glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; + } + // fragment shader + int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); + glCompileShader(fragmentShader); + // check for shader compile errors + glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl; + } + // link shaders + int shaderProgram = glCreateProgram(); + glAttachShader(shaderProgram, vertexShader); + glAttachShader(shaderProgram, fragmentShader); + glLinkProgram(shaderProgram); + // check for linking errors + glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); + if (!success) { + glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; + } + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + float firstTriangle[] = { + -0.9f, -0.5f, 0.0f, // left + -0.0f, -0.5f, 0.0f, // right + -0.45f, 0.5f, 0.0f, // top + }; + float secondTriangle[] = { + 0.0f, -0.5f, 0.0f, // left + 0.9f, -0.5f, 0.0f, // right + 0.45f, 0.5f, 0.0f // top + }; + unsigned int VBOs[2], VAOs[2]; + glGenVertexArrays(2, VAOs); // we can also generate multiple VAOs or buffers at the same time + glGenBuffers(2, VBOs); + // first triangle setup + // -------------------- + glBindVertexArray(VAOs[0]); + glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]); + glBufferData(GL_ARRAY_BUFFER, sizeof(firstTriangle), firstTriangle, GL_STATIC_DRAW); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); // Vertex attributes stay the same + glEnableVertexAttribArray(0); + // glBindVertexArray(0); // no need to unbind at all as we directly bind a different VAO the next few lines + // second triangle setup + // --------------------- + glBindVertexArray(VAOs[1]); // note that we bind to a different VAO now + glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]); // and a different VBO + glBufferData(GL_ARRAY_BUFFER, sizeof(secondTriangle), secondTriangle, GL_STATIC_DRAW); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); // because the vertex data is tightly packed we can also specify 0 as the vertex attribute's stride to let OpenGL figure it out + glEnableVertexAttribArray(0); + // glBindVertexArray(0); // not really necessary as well, but beware of calls that could affect VAOs while this one is bound (like binding element buffer objects, or enabling/disabling vertex attributes) + + + // uncomment this call to draw in wireframe polygons. + //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + glUseProgram(shaderProgram); + // draw first triangle using the data from the first VAO + glBindVertexArray(VAOs[0]); + glDrawArrays(GL_TRIANGLES, 0, 3); + // then we draw the second triangle using the data from the second VAO + glBindVertexArray(VAOs[1]); + glDrawArrays(GL_TRIANGLES, 0, 3); + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(2, VAOs); + glDeleteBuffers(2, VBOs); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/2.5.hello_triangle_exercise3/hello_triangle_exercise3.cpp b/src/1.getting_started/2.5.hello_triangle_exercise3/hello_triangle_exercise3.cpp new file mode 100644 index 0000000..521d36e --- /dev/null +++ b/src/1.getting_started/2.5.hello_triangle_exercise3/hello_triangle_exercise3.cpp @@ -0,0 +1,176 @@ +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +const char *vertexShaderSource = "#version 330 core\n" + "layout (location = 0) in vec3 aPos;\n" + "void main()\n" + "{\n" + " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" + "}\0"; +const char *fragmentShader1Source = "#version 330 core\n" + "out vec4 fragColor;\n" + "void main()\n" + "{\n" + " fragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" + "}\n\0"; +const char *fragmentShader2Source = "#version 330 core\n" + "out vec4 fragColor;\n" + "void main()\n" + "{\n" + " fragColor = vec4(1.0f, 1.0f, 0.0f, 1.0f);\n" + "}\n\0"; + + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + + // build and compile our shader program + // ------------------------------------ + // we skipped compile log checks this time for readability (if you do encounter issues, add the compile-checks! see previous code samples) + unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER); + unsigned int fragmentShaderOrange = glCreateShader(GL_FRAGMENT_SHADER); // the first fragment shader that outputs the color orange + unsigned int fragmentShaderYellow = glCreateShader(GL_FRAGMENT_SHADER); // the second fragment shader that outputs the color yellow + unsigned int shaderProgramOrange = glCreateProgram(); + unsigned int shaderProgramYellow = glCreateProgram(); // the second shader program + glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); + glCompileShader(vertexShader); + glShaderSource(fragmentShaderOrange, 1, &fragmentShader1Source, NULL); + glCompileShader(fragmentShaderOrange); + glShaderSource(fragmentShaderYellow, 1, &fragmentShader2Source, NULL); + glCompileShader(fragmentShaderYellow); + // link the first program object + glAttachShader(shaderProgramOrange, vertexShader); + glAttachShader(shaderProgramOrange, fragmentShaderOrange); + glLinkProgram(shaderProgramOrange); + // then link the second program object using a different fragment shader (but same vertex shader) + // this is perfectly allowed since the inputs and outputs of both the vertex and fragment shaders are equally matched. + glAttachShader(shaderProgramYellow, vertexShader); + glAttachShader(shaderProgramYellow, fragmentShaderYellow); + glLinkProgram(shaderProgramYellow); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + float firstTriangle[] = { + -0.9f, -0.5f, 0.0f, // left + -0.0f, -0.5f, 0.0f, // right + -0.45f, 0.5f, 0.0f, // top + }; + float secondTriangle[] = { + 0.0f, -0.5f, 0.0f, // left + 0.9f, -0.5f, 0.0f, // right + 0.45f, 0.5f, 0.0f // top + }; + unsigned int VBOs[2], VAOs[2]; + glGenVertexArrays(2, VAOs); // we can also generate multiple VAOs or buffers at the same time + glGenBuffers(2, VBOs); + // first triangle setup + // -------------------- + glBindVertexArray(VAOs[0]); + glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]); + glBufferData(GL_ARRAY_BUFFER, sizeof(firstTriangle), firstTriangle, GL_STATIC_DRAW); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); // Vertex attributes stay the same + glEnableVertexAttribArray(0); + // glBindVertexArray(0); // no need to unbind at all as we directly bind a different VAO the next few lines + // second triangle setup + // --------------------- + glBindVertexArray(VAOs[1]); // note that we bind to a different VAO now + glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]); // and a different VBO + glBufferData(GL_ARRAY_BUFFER, sizeof(secondTriangle), secondTriangle, GL_STATIC_DRAW); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); // because the vertex data is tightly packed we can also specify 0 as the vertex attribute's stride to let OpenGL figure it out + glEnableVertexAttribArray(0); + // glBindVertexArray(0); // not really necessary as well, but beware of calls that could affect VAOs while this one is bound (like binding element buffer objects, or enabling/disabling vertex attributes) + + + // uncomment this call to draw in wireframe polygons. + //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // now when we draw the triangle we first use the vertex and orange fragment shader from the first program + glUseProgram(shaderProgramOrange); + // draw the first triangle using the data from our first VAO + glBindVertexArray(VAOs[0]); + glDrawArrays(GL_TRIANGLES, 0, 3); // this call should output an orange triangle + // then we draw the second triangle using the data from the second VAO + // when we draw the second triangle we want to use a different shader program so we switch to the shader program with our yellow fragment shader. + glUseProgram(shaderProgramYellow); + glBindVertexArray(VAOs[1]); + glDrawArrays(GL_TRIANGLES, 0, 3); // this call should output a yellow triangle + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(2, VAOs); + glDeleteBuffers(2, VBOs); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/2.hello_triangle/hellotriangle2.cpp b/src/1.getting_started/2.hello_triangle/hellotriangle2.cpp deleted file mode 100644 index 6bf2e90..0000000 --- a/src/1.getting_started/2.hello_triangle/hellotriangle2.cpp +++ /dev/null @@ -1,181 +0,0 @@ -#include - -// GLEW -#define GLEW_STATIC -#include - -// GLFW -#include - - -// Function prototypes -void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); - -// Window dimensions -const GLuint WIDTH = 800, HEIGHT = 600; - -// Shaders -const GLchar* vertexShaderSource = "#version 330 core\n" - "layout (location = 0) in vec3 position;\n" - "void main()\n" - "{\n" - "gl_Position = vec4(position.x, position.y, position.z, 1.0);\n" - "}\0"; -const GLchar* fragmentShaderSource = "#version 330 core\n" - "out vec4 color;\n" - "void main()\n" - "{\n" - "color = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" - "}\n\0"; - -// The MAIN function, from here we start the application and run the game loop -int main() -{ - std::cout << "Starting GLFW context, OpenGL 3.3" << std::endl; - // Init GLFW - glfwInit(); - // Set all the required options for GLFW - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); - - // Create a GLFWwindow object that we can use for GLFW's functions - GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr); - glfwMakeContextCurrent(window); - - // Set the required callback functions - glfwSetKeyCallback(window, key_callback); - - // Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions - glewExperimental = GL_TRUE; - // Initialize GLEW to setup the OpenGL Function pointers - glewInit(); - - // Define the viewport dimensions - int width, height; - glfwGetFramebufferSize(window, &width, &height); - glViewport(0, 0, width, height); - - - // Build and compile our shader program - // Vertex shader - GLint vertexShader = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); - glCompileShader(vertexShader); - // Check for compile time errors - GLint success; - GLchar infoLog[512]; - glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); - if (!success) - { - glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); - std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; - } - // Fragment shader - GLint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); - glCompileShader(fragmentShader); - // Check for compile time errors - glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); - if (!success) - { - glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); - std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl; - } - // Link shaders - GLint shaderProgram = glCreateProgram(); - glAttachShader(shaderProgram, vertexShader); - glAttachShader(shaderProgram, fragmentShader); - glLinkProgram(shaderProgram); - // Check for linking errors - glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); - if (!success) { - glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); - std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; - } - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); - - - // Set up vertex data (and buffer(s)) and attribute pointers - //GLfloat vertices[] = { - // // First triangle - // 0.5f, 0.5f, // Top Right - // 0.5f, -0.5f, // Bottom Right - // -0.5f, 0.5f, // Top Left - // // Second triangle - // 0.5f, -0.5f, // Bottom Right - // -0.5f, -0.5f, // Bottom Left - // -0.5f, 0.5f // Top Left - //}; - GLfloat vertices[] = { - 0.5f, 0.5f, 0.0f, // Top Right - 0.5f, -0.5f, 0.0f, // Bottom Right - -0.5f, -0.5f, 0.0f, // Bottom Left - -0.5f, 0.5f, 0.0f // Top Left - }; - GLuint indices[] = { // Note that we start from 0! - 0, 1, 3, // First Triangle - 1, 2, 3 // Second Triangle - }; - GLuint VBO, VAO, EBO; - glGenVertexArrays(1, &VAO); - glGenBuffers(1, &VBO); - glGenBuffers(1, &EBO); - // Bind the Vertex Array Object first, then bind and set vertex buffer(s) and attribute pointer(s). - 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); - - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); - glEnableVertexAttribArray(0); - - glBindBuffer(GL_ARRAY_BUFFER, 0); // Note that this is allowed, the call to glVertexAttribPointer registered VBO as the currently bound vertex buffer object so afterwards we can safely unbind - - glBindVertexArray(0); // Unbind VAO (it's always a good thing to unbind any buffer/array to prevent strange bugs), remember: do NOT unbind the EBO, keep it bound to this VAO - - - // Uncommenting this call will result in wireframe polygons. - //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - // Game loop - while (!glfwWindowShouldClose(window)) - { - // Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions - glfwPollEvents(); - - // Render - // Clear the colorbuffer - glClearColor(0.2f, 0.3f, 0.3f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - - // Draw our first triangle - glUseProgram(shaderProgram); - glBindVertexArray(VAO); - //glDrawArrays(GL_TRIANGLES, 0, 6); - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); - glBindVertexArray(0); - - // Swap the screen buffers - glfwSwapBuffers(window); - } - // Properly de-allocate all resources once they've outlived their purpose - glDeleteVertexArrays(1, &VAO); - glDeleteBuffers(1, &VBO); - glDeleteBuffers(1, &EBO); - // Terminate GLFW, clearing any resources allocated by GLFW. - glfwTerminate(); - return 0; -} - -// Is called whenever a key is pressed/released via GLFW -void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) -{ - if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) - glfwSetWindowShouldClose(window, GL_TRUE); -} \ No newline at end of file diff --git a/src/1.getting_started/3.1.shaders_uniform/shaders_uniform.cpp b/src/1.getting_started/3.1.shaders_uniform/shaders_uniform.cpp new file mode 100644 index 0000000..0a703da --- /dev/null +++ b/src/1.getting_started/3.1.shaders_uniform/shaders_uniform.cpp @@ -0,0 +1,182 @@ +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +const char *vertexShaderSource ="#version 330 core\n" + "layout (location = 0) in vec3 aPos;\n" + "void main()\n" + "{\n" + " gl_Position = vec4(aPos, 1.0);\n" + "}\0"; + +const char *fragmentShaderSource = "#version 330 core\n" + "out vec4 fragColor;\n" + "uniform vec4 ourColor;\n" + "void main()\n" + "{\n" + " fragColor = ourColor;\n" + "}\n\0"; + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + + // build and compile our shader program + // ------------------------------------ + // vertex shader + int vertexShader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); + glCompileShader(vertexShader); + // check for shader compile errors + int success; + char infoLog[512]; + glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; + } + // fragment shader + int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); + glCompileShader(fragmentShader); + // check for shader compile errors + glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl; + } + // link shaders + int shaderProgram = glCreateProgram(); + glAttachShader(shaderProgram, vertexShader); + glAttachShader(shaderProgram, fragmentShader); + glLinkProgram(shaderProgram); + // check for linking errors + glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); + if (!success) { + glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; + } + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + float vertices[] = { + 0.5f, -0.5f, 0.0f, // bottom right + -0.5f, -0.5f, 0.0f, // bottom left + 0.0f, 0.5f, 0.0f // top + }; + + unsigned int VBO, VAO; + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s). + glBindVertexArray(VAO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + + // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other + // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary. + // glBindVertexArray(0); + + + // bind the VAO (it was already bound, but just to demonstrate): seeing as we only have a single VAO we can + // just bind it beforehand before rendering the respective triangle; this is another approach. + glBindVertexArray(VAO); + + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // be sure to activate the shader before any calls to glUniform + glUseProgram(shaderProgram); + + // update shader uniform + float timeValue = glfwGetTime(); + float greenValue = sin(timeValue) / 2.0f + 0.5f; + int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor"); + glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f); + + // render the triangle + glDrawArrays(GL_TRIANGLES, 0, 3); + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/3.2.shaders_interpolation/shaders_interpolation.cpp b/src/1.getting_started/3.2.shaders_interpolation/shaders_interpolation.cpp new file mode 100644 index 0000000..fec6bec --- /dev/null +++ b/src/1.getting_started/3.2.shaders_interpolation/shaders_interpolation.cpp @@ -0,0 +1,180 @@ +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +const char *vertexShaderSource ="#version 330 core\n" + "layout (location = 0) in vec3 aPos;\n" + "layout (location = 1) in vec3 aColor;\n" + "out vec3 ourColor;\n" + "void main()\n" + "{\n" + " gl_Position = vec4(aPos, 1.0);\n" + " ourColor = aColor;\n" + "}\0"; + +const char *fragmentShaderSource = "#version 330 core\n" + "out vec4 fragColor;\n" + "in vec3 ourColor;\n" + "void main()\n" + "{\n" + " fragColor = vec4(ourColor, 1.0f);\n" + "}\n\0"; + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + + // build and compile our shader program + // ------------------------------------ + // vertex shader + int vertexShader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); + glCompileShader(vertexShader); + // check for shader compile errors + int success; + char infoLog[512]; + glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; + } + // fragment shader + int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); + glCompileShader(fragmentShader); + // check for shader compile errors + glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl; + } + // link shaders + int shaderProgram = glCreateProgram(); + glAttachShader(shaderProgram, vertexShader); + glAttachShader(shaderProgram, fragmentShader); + glLinkProgram(shaderProgram); + // check for linking errors + glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); + if (!success) { + glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; + } + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + float vertices[] = { + // 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 + + }; + + unsigned int VBO, VAO; + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s). + glBindVertexArray(VAO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + // position attribute + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + // color attribute + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float))); + glEnableVertexAttribArray(1); + + // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other + // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary. + // glBindVertexArray(0); + + // as we only have a single shader, we could also just activate our shader once beforehand if we want to + glUseProgram(shaderProgram); + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // render the triangle + glBindVertexArray(VAO); + glDrawArrays(GL_TRIANGLES, 0, 3); + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/3.3.shaders_class/3.3.shader.fs b/src/1.getting_started/3.3.shaders_class/3.3.shader.fs new file mode 100644 index 0000000..9f10653 --- /dev/null +++ b/src/1.getting_started/3.3.shaders_class/3.3.shader.fs @@ -0,0 +1,9 @@ +#version 330 core +out vec4 fragColor; + +in vec3 ourColor; + +void main() +{ + fragColor = vec4(ourColor, 1.0f); +} \ No newline at end of file diff --git a/src/1.getting_started/3.3.shaders_class/3.3.shader.vs b/src/1.getting_started/3.3.shaders_class/3.3.shader.vs new file mode 100644 index 0000000..a69d96b --- /dev/null +++ b/src/1.getting_started/3.3.shaders_class/3.3.shader.vs @@ -0,0 +1,11 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec3 aColor; + +out vec3 ourColor; + +void main() +{ + gl_Position = vec4(aPos, 1.0f); + ourColor = aColor; +} \ No newline at end of file diff --git a/src/1.getting_started/3.3.shaders_class/shaders_class.cpp b/src/1.getting_started/3.3.shaders_class/shaders_class.cpp new file mode 100644 index 0000000..90fd7d1 --- /dev/null +++ b/src/1.getting_started/3.3.shaders_class/shaders_class.cpp @@ -0,0 +1,127 @@ +#include +#include + +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + + // build and compile our shader zprogram + // ------------------------------------ + Shader ourShader("3.3.shader.vs", "3.3.shader.fs"); // you can name your shader files however you like + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + float vertices[] = { + // 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 + + }; + + unsigned int VBO, VAO; + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s). + glBindVertexArray(VAO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + // position attribute + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + // color attribute + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float))); + glEnableVertexAttribArray(1); + + // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other + // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary. + // glBindVertexArray(0); + + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // render the triangle + ourShader.use(); + glBindVertexArray(VAO); + glDrawArrays(GL_TRIANGLES, 0, 3); + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/3.shaders/basic.frag b/src/1.getting_started/3.shaders/basic.frag deleted file mode 100644 index bc1d719..0000000 --- a/src/1.getting_started/3.shaders/basic.frag +++ /dev/null @@ -1,9 +0,0 @@ -#version 330 core -in vec3 ourColor; - -out vec4 color; - -void main() -{ - color = vec4(ourColor, 1.0f); -} \ No newline at end of file diff --git a/src/1.getting_started/3.shaders/basic.vs b/src/1.getting_started/3.shaders/basic.vs deleted file mode 100644 index 1f4c214..0000000 --- a/src/1.getting_started/3.shaders/basic.vs +++ /dev/null @@ -1,11 +0,0 @@ -#version 330 core -layout (location = 0) in vec3 position; -layout (location = 1) in vec3 color; - -out vec3 ourColor; - -void main() -{ - gl_Position = vec4(position, 1.0f); - ourColor = color; -} \ No newline at end of file diff --git a/src/1.getting_started/3.shaders/shaders-using-object.cpp b/src/1.getting_started/3.shaders/shaders-using-object.cpp deleted file mode 100644 index 49b3fff..0000000 --- a/src/1.getting_started/3.shaders/shaders-using-object.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include - -// GLEW -#define GLEW_STATIC -#include - -// GLFW -#include - -// Other includes -#include - - -// Function prototypes -void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); - -// Window dimensions -const GLuint WIDTH = 800, HEIGHT = 600; - -// The MAIN function, from here we start the application and run the game loop -int main() -{ - // Init GLFW - glfwInit(); - // Set all the required options for GLFW - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); - - // Create a GLFWwindow object that we can use for GLFW's functions - GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr); - glfwMakeContextCurrent(window); - - // Set the required callback functions - glfwSetKeyCallback(window, key_callback); - - // Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions - glewExperimental = GL_TRUE; - // Initialize GLEW to setup the OpenGL Function pointers - glewInit(); - - // Define the viewport dimensions - glViewport(0, 0, WIDTH, HEIGHT); - - - // Build and compile our shader program - Shader ourShader("basic.vs", "basic.frag"); - - - // Set up vertex data (and buffer(s)) and attribute pointers - GLfloat vertices[] = { - // 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 - }; - GLuint VBO, VAO; - glGenVertexArrays(1, &VAO); - glGenBuffers(1, &VBO); - // Bind the Vertex Array Object first, then bind and set vertex buffer(s) and attribute pointer(s). - glBindVertexArray(VAO); - - glBindBuffer(GL_ARRAY_BUFFER, VBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - - // Position attribute - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0); - glEnableVertexAttribArray(0); - // Color attribute - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); - glEnableVertexAttribArray(1); - - glBindVertexArray(0); // Unbind VAO - - - // Game loop - while (!glfwWindowShouldClose(window)) - { - // Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions - glfwPollEvents(); - - // Render - // Clear the colorbuffer - glClearColor(0.2f, 0.3f, 0.3f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - - // Draw the triangle - ourShader.Use(); - glBindVertexArray(VAO); - glDrawArrays(GL_TRIANGLES, 0, 3); - glBindVertexArray(0); - - // Swap the screen buffers - glfwSwapBuffers(window); - } - // Properly de-allocate all resources once they've outlived their purpose - glDeleteVertexArrays(1, &VAO); - glDeleteBuffers(1, &VBO); - // Terminate GLFW, clearing any resources allocated by GLFW. - glfwTerminate(); - return 0; -} - -// Is called whenever a key is pressed/released via GLFW -void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) -{ - if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) - glfwSetWindowShouldClose(window, GL_TRUE); -} \ No newline at end of file diff --git a/src/1.getting_started/4.1.textures/4.1.texture.fs b/src/1.getting_started/4.1.textures/4.1.texture.fs new file mode 100644 index 0000000..b5fc5bc --- /dev/null +++ b/src/1.getting_started/4.1.textures/4.1.texture.fs @@ -0,0 +1,13 @@ +#version 330 core +out vec4 fragColor; + +in vec3 ourColor; +in vec2 texCoord; + +// texture sampler +uniform sampler2D texture1; + +void main() +{ + fragColor = texture(texture1, texCoord); +} \ No newline at end of file diff --git a/src/1.getting_started/4.1.textures/4.1.texture.vs b/src/1.getting_started/4.1.textures/4.1.texture.vs new file mode 100644 index 0000000..7351c1e --- /dev/null +++ b/src/1.getting_started/4.1.textures/4.1.texture.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.0f); + ourColor = aColor; + texCoord = vec2(aTexCoord.x, aTexCoord.y); +} \ No newline at end of file diff --git a/src/1.getting_started/4.1.textures/textures.cpp b/src/1.getting_started/4.1.textures/textures.cpp new file mode 100644 index 0000000..85ebb85 --- /dev/null +++ b/src/1.getting_started/4.1.textures/textures.cpp @@ -0,0 +1,164 @@ +#include +#include +#include + +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + // build and compile our shader zprogram + // ------------------------------------ + Shader ourShader("4.1.texture.vs", "4.1.texture.fs"); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + 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 texture; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); // all upcoming GL_TEXTURE_2D operations now have effect on this texture object + // 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, height, nrComponents; + unsigned char *data = stbi_load(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // bind Texture + glBindTexture(GL_TEXTURE_2D, texture); + + // render container + ourShader.use(); + glBindVertexArray(VAO); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + glDeleteBuffers(1, &EBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/4.2.textures_combined/4.2.texture.fs b/src/1.getting_started/4.2.textures_combined/4.2.texture.fs new file mode 100644 index 0000000..c7652e0 --- /dev/null +++ b/src/1.getting_started/4.2.textures_combined/4.2.texture.fs @@ -0,0 +1,15 @@ +#version 330 core +out vec4 fragColor; + +in vec3 ourColor; +in vec2 texCoord; + +// texture samplers +uniform sampler2D texture1; +uniform sampler2D texture2; + +void main() +{ + // linearly interpolate between both textures (80% container, 20% awesomeface) + fragColor = mix(texture(texture1, texCoord), texture(texture2, texCoord), 0.2); +} \ No newline at end of file diff --git a/src/1.getting_started/4.2.textures_combined/4.2.texture.vs b/src/1.getting_started/4.2.textures_combined/4.2.texture.vs new file mode 100644 index 0000000..7351c1e --- /dev/null +++ b/src/1.getting_started/4.2.textures_combined/4.2.texture.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.0f); + ourColor = aColor; + texCoord = vec2(aTexCoord.x, aTexCoord.y); +} \ No newline at end of file diff --git a/src/1.getting_started/4.2.textures_combined/textures_combined.cpp b/src/1.getting_started/4.2.textures_combined/textures_combined.cpp new file mode 100644 index 0000000..dde3a54 --- /dev/null +++ b/src/1.getting_started/4.2.textures_combined/textures_combined.cpp @@ -0,0 +1,202 @@ +#include +#include +#include + +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + // build and compile our shader zprogram + // ------------------------------------ + Shader ourShader("4.2.texture.vs", "4.2.texture.fs"); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + 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, height, nrComponents; + stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis. + unsigned char *data = stbi_load(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + // texture 2 + // --------- + glGenTextures(1, &texture2); + glBindTexture(GL_TEXTURE_2D, texture2); + // 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 + data = stbi_load(FileSystem::getPath("resources/textures/awesomeface.png").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + // note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + + // tell opengl for each sampler to which texture unit it belongs to (only has to be done once) + // ------------------------------------------------------------------------------------------- + ourShader.use(); // don't forget to activate/use the shader before setting uniforms! + // either set it manually like so: + glUniform1i(glGetUniformLocation(ourShader.ID, "texture1"), 0); + // or set it via the texture class + ourShader.setInt("texture2", 1); + + + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // bind textures on corresponding texture units + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture1); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, texture2); + + // render container + ourShader.use(); + glBindVertexArray(VAO); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + glDeleteBuffers(1, &EBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/4.3.textures_exercise2/textures_exercise2.cpp b/src/1.getting_started/4.3.textures_exercise2/textures_exercise2.cpp new file mode 100644 index 0000000..362eecd --- /dev/null +++ b/src/1.getting_started/4.3.textures_exercise2/textures_exercise2.cpp @@ -0,0 +1,203 @@ +#include +#include +#include + +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + + // build and compile our shader zprogram + // ------------------------------------ + Shader ourShader("4.2.texture_combined.vs", "4.2.texture_combined.fs"); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + float vertices[] = { + // positions // colors // texture coords (note that we changed them to 2.0f!) + 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 2.0f, 2.0f, // top right + 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 2.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, 2.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_CLAMP_TO_EDGE); // note that we set the container wrapping method to GL_CLAMP_TO_EDGE + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + // 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, height, nrComponents; + stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis. + unsigned char *data = stbi_load(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + // texture 2 + // --------- + glGenTextures(1, &texture2); + glBindTexture(GL_TEXTURE_2D, texture2); + // set the texture wrapping parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // we want to repeat the awesomeface pattern so we kept it at GL_REPEAT + 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 + data = stbi_load(FileSystem::getPath("resources/textures/awesomeface.png").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + // note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + + // tell opengl for each sampler to which texture unit it belongs to (only has to be done once) + // ------------------------------------------------------------------------------------------- + ourShader.use(); // don't forget to activate/use the shader before setting uniforms! + // either set it manually like so: + glUniform1i(glGetUniformLocation(ourShader.ID, "texture1"), 0); + // or set it via the texture class + ourShader.setInt("texture2", 1); + + + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // bind textures on corresponding texture units + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture1); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, texture2); + + // render container + ourShader.use(); + glBindVertexArray(VAO); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + glDeleteBuffers(1, &EBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/4.4.textures_exercise3/textures_exercise3.cpp b/src/1.getting_started/4.4.textures_exercise3/textures_exercise3.cpp new file mode 100644 index 0000000..26f884e --- /dev/null +++ b/src/1.getting_started/4.4.textures_exercise3/textures_exercise3.cpp @@ -0,0 +1,203 @@ +#include +#include +#include + +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + + // build and compile our shader zprogram + // ------------------------------------ + Shader ourShader("4.2.texture_combined.vs", "4.2.texture_combined.fs"); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + float vertices[] = { + // positions // colors // texture coords (note that we changed them to 'zoom in' on our texture image) + 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.55f, 0.55f, // top right + 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.55f, 0.45f, // bottom right + -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.45f, 0.45f, // bottom left + -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.45f, 0.55f // 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_CLAMP_TO_EDGE); // note that we set the container wrapping method to GL_CLAMP_TO_EDGE + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + // set texture filtering parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // set texture filtering to nearest neighbor to clearly see the texels/pixels + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + // load image, create texture and generate mipmaps + int width, height, nrComponents; + stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis. + unsigned char *data = stbi_load(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + // texture 2 + // --------- + glGenTextures(1, &texture2); + glBindTexture(GL_TEXTURE_2D, texture2); + // set the texture wrapping parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + // set texture filtering parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // set texture filtering to nearest neighbor to clearly see the texels/pixels + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + // load image, create texture and generate mipmaps + data = stbi_load(FileSystem::getPath("resources/textures/awesomeface.png").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + // note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + + // tell opengl for each sampler to which texture unit it belongs to (only has to be done once) + // ------------------------------------------------------------------------------------------- + ourShader.use(); // don't forget to activate/use the shader before setting uniforms! + // either set it manually like so: + glUniform1i(glGetUniformLocation(ourShader.ID, "texture1"), 0); + // or set it via the texture class + ourShader.setInt("texture2", 1); + + + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // bind textures on corresponding texture units + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture1); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, texture2); + + // render container + ourShader.use(); + glBindVertexArray(VAO); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + glDeleteBuffers(1, &EBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/4.5.textures_exercise4/4.5.texture.fs b/src/1.getting_started/4.5.textures_exercise4/4.5.texture.fs new file mode 100644 index 0000000..bf5ce11 --- /dev/null +++ b/src/1.getting_started/4.5.textures_exercise4/4.5.texture.fs @@ -0,0 +1,17 @@ +#version 330 core +out vec4 fragColor; + +in vec3 ourColor; +in vec2 texCoord; + +uniform float mixValue; + +// texture samplers +uniform sampler2D texture1; +uniform sampler2D texture2; + +void main() +{ + // linearly interpolate between both textures + fragColor = mix(texture(texture1, texCoord), texture(texture2, texCoord), mixValue); +} \ No newline at end of file diff --git a/src/1.getting_started/4.5.textures_exercise4/4.5.texture.vs b/src/1.getting_started/4.5.textures_exercise4/4.5.texture.vs new file mode 100644 index 0000000..7351c1e --- /dev/null +++ b/src/1.getting_started/4.5.textures_exercise4/4.5.texture.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.0f); + ourColor = aColor; + texCoord = vec2(aTexCoord.x, aTexCoord.y); +} \ No newline at end of file diff --git a/src/1.getting_started/4.5.textures_exercise4/textures_exercise4.cpp b/src/1.getting_started/4.5.textures_exercise4/textures_exercise4.cpp new file mode 100644 index 0000000..28846f8 --- /dev/null +++ b/src/1.getting_started/4.5.textures_exercise4/textures_exercise4.cpp @@ -0,0 +1,222 @@ +#include +#include +#include + +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +// stores how much we're seeing of either texture +float mixValue = 0.2f; + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + + // build and compile our shader zprogram + // ------------------------------------ + Shader ourShader("4.5.texture.vs", "4.5.texture.fs"); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + 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, height, nrComponents; + stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis. + unsigned char *data = stbi_load(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + // texture 2 + // --------- + glGenTextures(1, &texture2); + glBindTexture(GL_TEXTURE_2D, texture2); + // 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 + data = stbi_load(FileSystem::getPath("resources/textures/awesomeface.png").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + // note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + + // tell opengl for each sampler to which texture unit it belongs to (only has to be done once) + // ------------------------------------------------------------------------------------------- + ourShader.use(); // don't forget to activate/use the shader before setting uniforms! + // either set it manually like so: + glUniform1i(glGetUniformLocation(ourShader.ID, "texture1"), 0); + // or set it via the texture class + ourShader.setInt("texture2", 1); + + + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // bind textures on corresponding texture units + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture1); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, texture2); + + // set the texture mix value in the shader + ourShader.setFloat("mixValue", mixValue); + + // render container + ourShader.use(); + glBindVertexArray(VAO); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + glDeleteBuffers(1, &EBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); + + if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) + { + mixValue += 0.001f; // change this value accordingly (might be too slow or too fast based on system hardware) + if(mixValue >= 1.0f) + mixValue = 1.0f; + } + if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) + { + mixValue -= 0.001f; // change this value accordingly (might be too slow or too fast based on system hardware) + if (mixValue <= 0.0f) + mixValue = 0.0f; + } +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/4.textures/texture.frag b/src/1.getting_started/4.textures/texture.frag deleted file mode 100644 index 854c642..0000000 --- a/src/1.getting_started/4.textures/texture.frag +++ /dev/null @@ -1,15 +0,0 @@ -#version 330 core -in vec3 ourColor; -in vec2 TexCoord; - -out vec4 color; - -// Texture samplers -uniform sampler2D ourTexture1; -uniform sampler2D ourTexture2; - -void main() -{ - // Linearly interpolate between both textures (second texture is only slightly combined) - color = mix(texture(ourTexture1, TexCoord), texture(ourTexture2, TexCoord), 0.2); -} \ No newline at end of file diff --git a/src/1.getting_started/4.textures/texture.vs b/src/1.getting_started/4.textures/texture.vs deleted file mode 100644 index 366cf08..0000000 --- a/src/1.getting_started/4.textures/texture.vs +++ /dev/null @@ -1,16 +0,0 @@ -#version 330 core -layout (location = 0) in vec3 position; -layout (location = 1) in vec3 color; -layout (location = 2) in vec2 texCoord; - -out vec3 ourColor; -out vec2 TexCoord; - -void main() -{ - gl_Position = vec4(position, 1.0f); - ourColor = color; - // We swap the y-axis by substracing our coordinates from 1. This is done because most images have the top y-axis inversed with OpenGL's top y-axis. - // TexCoord = texCoord; - TexCoord = vec2(texCoord.x, 1.0 - texCoord.y); -} \ No newline at end of file diff --git a/src/1.getting_started/4.textures/textures_combined.cpp b/src/1.getting_started/4.textures/textures_combined.cpp deleted file mode 100644 index a9ce3be..0000000 --- a/src/1.getting_started/4.textures/textures_combined.cpp +++ /dev/null @@ -1,179 +0,0 @@ -#include - -// GLEW -#define GLEW_STATIC -#include - -// GLFW -#include - -// Other Libs -#include - -// Other includes -#include -#include - -// Function prototypes -void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); - -// Window dimensions -const GLuint WIDTH = 800, HEIGHT = 600; - -// The MAIN function, from here we start the application and run the game loop -int main() -{ - // Init GLFW - glfwInit(); - // Set all the required options for GLFW - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); - - // Create a GLFWwindow object that we can use for GLFW's functions - GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr); - glfwMakeContextCurrent(window); - - // Set the required callback functions - glfwSetKeyCallback(window, key_callback); - - // Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions - glewExperimental = GL_TRUE; - // Initialize GLEW to setup the OpenGL Function pointers - glewInit(); - - // Define the viewport dimensions - glViewport(0, 0, WIDTH, HEIGHT); - - - // Build and compile our shader program - Shader ourShader("texture.vs", "texture.frag"); - - - // Set up vertex data (and buffer(s)) and attribute pointers - GLfloat 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 - }; - GLuint indices[] = { // Note that we start from 0! - 0, 1, 3, // First Triangle - 1, 2, 3 // Second Triangle - }; - GLuint 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(GLfloat), (GLvoid*)0); - glEnableVertexAttribArray(0); - // Color attribute - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); - glEnableVertexAttribArray(1); - // TexCoord attribute - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat))); - glEnableVertexAttribArray(2); - - glBindVertexArray(0); // Unbind VAO - - - // Load and create a texture - GLuint texture1; - GLuint texture2; - // ==================== - // Texture 1 - // ==================== - glGenTextures(1, &texture1); - glBindTexture(GL_TEXTURE_2D, texture1); // All upcoming GL_TEXTURE_2D operations now have effect on our texture object - // Set our texture parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture wrapping to GL_REPEAT - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - // Set texture filtering - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // Load, create texture and generate mipmaps - int width, height; - - unsigned char* image = SOIL_load_image(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, 0, SOIL_LOAD_RGB); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); - glGenerateMipmap(GL_TEXTURE_2D); - SOIL_free_image_data(image); - glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture when done, so we won't accidentily mess up our texture. - // =================== - // Texture 2 - // =================== - glGenTextures(1, &texture2); - glBindTexture(GL_TEXTURE_2D, texture2); - // Set our texture parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - // Set texture filtering - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // Load, create texture and generate mipmaps - image = SOIL_load_image(FileSystem::getPath("resources/textures/awesomeface.png").c_str(), &width, &height, 0, SOIL_LOAD_RGB); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); - glGenerateMipmap(GL_TEXTURE_2D); - SOIL_free_image_data(image); - glBindTexture(GL_TEXTURE_2D, 0); - - - // Game loop - while (!glfwWindowShouldClose(window)) - { - // Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions - glfwPollEvents(); - - // Render - // Clear the colorbuffer - glClearColor(0.2f, 0.3f, 0.3f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - - - // Bind Textures using texture units - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, texture1); - glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture1"), 0); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, texture2); - glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture2"), 1); - - // Activate shader - ourShader.Use(); - - // Draw container - glBindVertexArray(VAO); - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); - glBindVertexArray(0); - - // Swap the screen buffers - glfwSwapBuffers(window); - } - // Properly de-allocate all resources once they've outlived their purpose - glDeleteVertexArrays(1, &VAO); - glDeleteBuffers(1, &VBO); - glDeleteBuffers(1, &EBO); - // Terminate GLFW, clearing any resources allocated by GLFW. - glfwTerminate(); - return 0; -} - -// Is called whenever a key is pressed/released via GLFW -void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) -{ - if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) - glfwSetWindowShouldClose(window, GL_TRUE); -} \ No newline at end of file diff --git a/src/1.getting_started/5.1.transformations/5.1.transform.fs b/src/1.getting_started/5.1.transformations/5.1.transform.fs new file mode 100644 index 0000000..c7652e0 --- /dev/null +++ b/src/1.getting_started/5.1.transformations/5.1.transform.fs @@ -0,0 +1,15 @@ +#version 330 core +out vec4 fragColor; + +in vec3 ourColor; +in vec2 texCoord; + +// texture samplers +uniform sampler2D texture1; +uniform sampler2D texture2; + +void main() +{ + // linearly interpolate between both textures (80% container, 20% awesomeface) + fragColor = mix(texture(texture1, texCoord), texture(texture2, texCoord), 0.2); +} \ No newline at end of file diff --git a/src/1.getting_started/5.1.transformations/5.1.transform.vs b/src/1.getting_started/5.1.transformations/5.1.transform.vs new file mode 100644 index 0000000..16c6e90 --- /dev/null +++ b/src/1.getting_started/5.1.transformations/5.1.transform.vs @@ -0,0 +1,16 @@ +#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; + +uniform mat4 transform; + +void main() +{ + gl_Position = transform * vec4(aPos, 1.0f); + ourColor = aColor; + texCoord = vec2(aTexCoord.x, aTexCoord.y); +} \ No newline at end of file diff --git a/src/1.getting_started/5.1.transformations/transformations.cpp b/src/1.getting_started/5.1.transformations/transformations.cpp new file mode 100644 index 0000000..f99f6fe --- /dev/null +++ b/src/1.getting_started/5.1.transformations/transformations.cpp @@ -0,0 +1,212 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + // build and compile our shader zprogram + // ------------------------------------ + Shader ourShader("5.1.transform.vs", "5.1.transform.fs"); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + 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); + 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, height, nrComponents; + stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis. + unsigned char *data = stbi_load(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + // texture 2 + // --------- + glGenTextures(1, &texture2); + glBindTexture(GL_TEXTURE_2D, texture2); + // set the texture wrapping parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + 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 + data = stbi_load(FileSystem::getPath("resources/textures/awesomeface.png").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + // note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + + // tell opengl for each sampler to which texture unit it belongs to (only has to be done once) + // ------------------------------------------------------------------------------------------- + ourShader.use(); + ourShader.setInt("texture1", 0); + ourShader.setInt("texture2", 1); + + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // bind textures on corresponding texture units + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture1); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, texture2); + + // create transformations + glm::mat4 transform; + transform = glm::translate(transform, glm::vec3(0.5f, -0.5f, 0.0f)); + transform = glm::rotate(transform, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f)); + + // get matrix's uniform location and set matrix + unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform"); + glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform)); + + // render container + ourShader.use(); + glBindVertexArray(VAO); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + glDeleteBuffers(1, &EBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/5.2.transformations_exercise2/transformations_exercise2.cpp b/src/1.getting_started/5.2.transformations_exercise2/transformations_exercise2.cpp new file mode 100644 index 0000000..ec8e914 --- /dev/null +++ b/src/1.getting_started/5.2.transformations_exercise2/transformations_exercise2.cpp @@ -0,0 +1,223 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + // build and compile our shader zprogram + // ------------------------------------ + Shader ourShader("5.1.transform.vs", "5.1.transform.fs"); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + 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); + 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, height, nrComponents; + stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis. + unsigned char *data = stbi_load(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + // texture 2 + // --------- + glGenTextures(1, &texture2); + glBindTexture(GL_TEXTURE_2D, texture2); + // set the texture wrapping parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + 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 + data = stbi_load(FileSystem::getPath("resources/textures/awesomeface.png").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + // note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + + // tell opengl for each sampler to which texture unit it belongs to (only has to be done once) + // ------------------------------------------------------------------------------------------- + ourShader.use(); + ourShader.setInt("texture1", 0); + ourShader.setInt("texture2", 1); + + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // bind textures on corresponding texture units + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture1); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, texture2); + + + glm::mat4 transform; + // first container + // --------------- + transform = glm::translate(transform, glm::vec3(0.5f, -0.5f, 0.0f)); + transform = glm::rotate(transform, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f)); + // get their uniform location and set matrix (using glm::value_ptr) + unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform"); + glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform)); + + // with the uniform matrix set, draw the first container + glBindVertexArray(VAO); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + + // second transformation + // --------------------- + transform = glm::mat4(); // reset it to an identity matrix + transform = glm::translate(transform, glm::vec3(-0.5f, 0.5f, 0.0f)); + float scaleAmount = sin(glfwGetTime()); + transform = glm::scale(transform, glm::vec3(scaleAmount, scaleAmount, scaleAmount)); + glUniformMatrix4fv(transformLoc, 1, GL_FALSE, &transform[0][0]); // this time take the matrix value array's first element as its memory pointer value + + // now with the uniform matrix being replaced with new transformations, draw it again. + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + glDeleteBuffers(1, &EBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/5.transformations/transform.vs b/src/1.getting_started/5.transformations/transform.vs deleted file mode 100644 index 5d42ec8..0000000 --- a/src/1.getting_started/5.transformations/transform.vs +++ /dev/null @@ -1,13 +0,0 @@ -#version 330 core -layout (location = 0) in vec3 position; -layout (location = 2) in vec2 texCoord; - -out vec2 TexCoord; - -uniform mat4 transform; - -void main() -{ - gl_Position = transform * vec4(position, 1.0f); - TexCoord = vec2(texCoord.x, 1.0 - texCoord.y); -} \ No newline at end of file diff --git a/src/1.getting_started/5.transformations/transformations.cpp b/src/1.getting_started/5.transformations/transformations.cpp deleted file mode 100644 index 400e195..0000000 --- a/src/1.getting_started/5.transformations/transformations.cpp +++ /dev/null @@ -1,190 +0,0 @@ -#include - -// GLEW -#define GLEW_STATIC -#include - -// GLFW -#include - -// Other Libs -#include -// GLM Mathematics -#include -#include -#include - -// Other includes -#include -#include - -// Function prototypes -void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); - -// Window dimensions -const GLuint WIDTH = 800, HEIGHT = 600; - -// The MAIN function, from here we start the application and run the game loop -int main() -{ - // Init GLFW - glfwInit(); - // Set all the required options for GLFW - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); - - // Create a GLFWwindow object that we can use for GLFW's functions - GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr); - glfwMakeContextCurrent(window); - - // Set the required callback functions - glfwSetKeyCallback(window, key_callback); - - // Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions - glewExperimental = GL_TRUE; - // Initialize GLEW to setup the OpenGL Function pointers - glewInit(); - - // Define the viewport dimensions - glViewport(0, 0, WIDTH, HEIGHT); - - - // Build and compile our shader program - Shader ourShader("transform.vs", "transform.frag"); - - - // Set up vertex data (and buffer(s)) and attribute pointers - GLfloat 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 - }; - GLuint indices[] = { // Note that we start from 0! - 0, 1, 3, // First Triangle - 1, 2, 3 // Second Triangle - }; - GLuint 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(GLfloat), (GLvoid*)0); - glEnableVertexAttribArray(0); - // Color attribute - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); - glEnableVertexAttribArray(1); - // TexCoord attribute - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat))); - glEnableVertexAttribArray(2); - - glBindVertexArray(0); // Unbind VAO - - - // Load and create a texture - GLuint texture1; - GLuint texture2; - // ==================== - // Texture 1 - // ==================== - glGenTextures(1, &texture1); - glBindTexture(GL_TEXTURE_2D, texture1); // All upcoming GL_TEXTURE_2D operations now have effect on our texture object - // Set our texture parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture wrapping to GL_REPEAT - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - // Set texture filtering - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // Load, create texture and generate mipmaps - int width, height; - unsigned char* image = SOIL_load_image(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, 0, SOIL_LOAD_RGB); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); - glGenerateMipmap(GL_TEXTURE_2D); - SOIL_free_image_data(image); - glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture when done, so we won't accidentily mess up our texture. - // =================== - // Texture 2 - // =================== - glGenTextures(1, &texture2); - glBindTexture(GL_TEXTURE_2D, texture2); - // Set our texture parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - // Set texture filtering - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // Load, create texture and generate mipmaps - image = SOIL_load_image(FileSystem::getPath("resources/textures/awesomeface.png").c_str(), &width, &height, 0, SOIL_LOAD_RGB); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); - glGenerateMipmap(GL_TEXTURE_2D); - SOIL_free_image_data(image); - glBindTexture(GL_TEXTURE_2D, 0); - - - // Game loop - while (!glfwWindowShouldClose(window)) - { - // Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions - glfwPollEvents(); - - // Render - // Clear the colorbuffer - glClearColor(0.2f, 0.3f, 0.3f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - - - // Bind Textures using texture units - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, texture1); - glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture1"), 0); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, texture2); - glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture2"), 1); - - // Activate shader - ourShader.Use(); - - // Create transformations - glm::mat4 transform; - transform = glm::translate(transform, glm::vec3(0.5f, -0.5f, 0.0f)); - transform = glm::rotate(transform, (GLfloat)glfwGetTime() * 50.0f, glm::vec3(0.0f, 0.0f, 1.0f)); - - // Get matrix's uniform location and set matrix - GLint transformLoc = glGetUniformLocation(ourShader.Program, "transform"); - glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform)); - - // Draw container - glBindVertexArray(VAO); - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); - glBindVertexArray(0); - - // Swap the screen buffers - glfwSwapBuffers(window); - } - // Properly de-allocate all resources once they've outlived their purpose - glDeleteVertexArrays(1, &VAO); - glDeleteBuffers(1, &VBO); - glDeleteBuffers(1, &EBO); - // Terminate GLFW, clearing any resources allocated by GLFW. - glfwTerminate(); - return 0; -} - -// Is called whenever a key is pressed/released via GLFW -void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) -{ - if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) - glfwSetWindowShouldClose(window, GL_TRUE); -} \ No newline at end of file diff --git a/src/1.getting_started/6.1.coordinate_systems/6.1.coordinate_systems.fs b/src/1.getting_started/6.1.coordinate_systems/6.1.coordinate_systems.fs new file mode 100644 index 0000000..c7652e0 --- /dev/null +++ b/src/1.getting_started/6.1.coordinate_systems/6.1.coordinate_systems.fs @@ -0,0 +1,15 @@ +#version 330 core +out vec4 fragColor; + +in vec3 ourColor; +in vec2 texCoord; + +// texture samplers +uniform sampler2D texture1; +uniform sampler2D texture2; + +void main() +{ + // linearly interpolate between both textures (80% container, 20% awesomeface) + fragColor = mix(texture(texture1, texCoord), texture(texture2, texCoord), 0.2); +} \ No newline at end of file diff --git a/src/1.getting_started/6.1.coordinate_systems/6.1.coordinate_systems.vs b/src/1.getting_started/6.1.coordinate_systems/6.1.coordinate_systems.vs new file mode 100644 index 0000000..10577d9 --- /dev/null +++ b/src/1.getting_started/6.1.coordinate_systems/6.1.coordinate_systems.vs @@ -0,0 +1,18 @@ +#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; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + +void main() +{ + gl_Position = projection * view * model * vec4(aPos, 1.0f); + ourColor = aColor; + texCoord = vec2(aTexCoord.x, aTexCoord.y); +} \ No newline at end of file diff --git a/src/1.getting_started/6.1.coordinate_systems/coordinate_systems.cpp b/src/1.getting_started/6.1.coordinate_systems/coordinate_systems.cpp new file mode 100644 index 0000000..19322f9 --- /dev/null +++ b/src/1.getting_started/6.1.coordinate_systems/coordinate_systems.cpp @@ -0,0 +1,221 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + // build and compile our shader zprogram + // ------------------------------------ + Shader ourShader("6.1.coordinate_systems.vs", "6.1.coordinate_systems.fs"); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + 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); + 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, height, nrComponents; + stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis. + unsigned char *data = stbi_load(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + // texture 2 + // --------- + glGenTextures(1, &texture2); + glBindTexture(GL_TEXTURE_2D, texture2); + // set the texture wrapping parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + 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 + data = stbi_load(FileSystem::getPath("resources/textures/awesomeface.png").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + // note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + + // tell opengl for each sampler to which texture unit it belongs to (only has to be done once) + // ------------------------------------------------------------------------------------------- + ourShader.use(); + ourShader.setInt("texture1", 0); + ourShader.setInt("texture2", 1); + + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // bind textures on corresponding texture units + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture1); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, texture2); + + // activate shader + ourShader.use(); + + // create transformations + glm::mat4 model; + glm::mat4 view; + glm::mat4 projection; + model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f)); + view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f)); + projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f); + // retrieve the matrix uniform locations + unsigned int modelLoc = glGetUniformLocation(ourShader.ID, "model"); + unsigned int viewLoc = glGetUniformLocation(ourShader.ID, "view"); + // pass them to the shaders (3 different ways) + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + glUniformMatrix4fv(viewLoc, 1, GL_FALSE, &view[0][0]); + // note: currently we set the projection matrix each frame, but since the projection matrix rarely changes it's often best practice to set it outside the main loop only once. + ourShader.setMat4("projection", projection); + + // render container + glBindVertexArray(VAO); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + glDeleteBuffers(1, &EBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/6.2.coordinate_systems_depth/6.2.coordinate_systems.fs b/src/1.getting_started/6.2.coordinate_systems_depth/6.2.coordinate_systems.fs new file mode 100644 index 0000000..43d8561 --- /dev/null +++ b/src/1.getting_started/6.2.coordinate_systems_depth/6.2.coordinate_systems.fs @@ -0,0 +1,14 @@ +#version 330 core +out vec4 fragColor; + +in vec2 texCoord; + +// texture samplers +uniform sampler2D texture1; +uniform sampler2D texture2; + +void main() +{ + // linearly interpolate between both textures (80% container, 20% awesomeface) + fragColor = mix(texture(texture1, texCoord), texture(texture2, texCoord), 0.2); +} \ No newline at end of file diff --git a/src/1.getting_started/6.2.coordinate_systems_depth/6.2.coordinate_systems.vs b/src/1.getting_started/6.2.coordinate_systems_depth/6.2.coordinate_systems.vs new file mode 100644 index 0000000..1e26e0d --- /dev/null +++ b/src/1.getting_started/6.2.coordinate_systems_depth/6.2.coordinate_systems.vs @@ -0,0 +1,15 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec2 aTexCoord; + +out vec2 texCoord; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + +void main() +{ + gl_Position = projection * view * model * vec4(aPos, 1.0f); + texCoord = vec2(aTexCoord.x, aTexCoord.y); +} \ No newline at end of file diff --git a/src/1.getting_started/6.2.coordinate_systems_depth/coordinate_systems_depth.cpp b/src/1.getting_started/6.2.coordinate_systems_depth/coordinate_systems_depth.cpp new file mode 100644 index 0000000..41457fa --- /dev/null +++ b/src/1.getting_started/6.2.coordinate_systems_depth/coordinate_systems_depth.cpp @@ -0,0 +1,250 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + // configure global opengl state + // ----------------------------- + glEnable(GL_DEPTH_TEST); + + // build and compile our shader zprogram + // ------------------------------------ + Shader ourShader("6.2.coordinate_systems.vs", "6.2.coordinate_systems.fs"); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + float vertices[] = { + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, + 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, + + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, + -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + + -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f + }; + unsigned int VBO, VAO; + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + + glBindVertexArray(VAO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + // position attribute + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + // texture coord attribute + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + glEnableVertexAttribArray(1); + + + // 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); + 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, height, nrComponents; + stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis. + unsigned char *data = stbi_load(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + // texture 2 + // --------- + glGenTextures(1, &texture2); + glBindTexture(GL_TEXTURE_2D, texture2); + // set the texture wrapping parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + 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 + data = stbi_load(FileSystem::getPath("resources/textures/awesomeface.png").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + // note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + + // tell opengl for each sampler to which texture unit it belongs to (only has to be done once) + // ------------------------------------------------------------------------------------------- + ourShader.use(); + ourShader.setInt("texture1", 0); + ourShader.setInt("texture2", 1); + + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // also clear the depth buffer now! + + // bind textures on corresponding texture units + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture1); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, texture2); + + // activate shader + ourShader.use(); + + // create transformations + glm::mat4 model; + glm::mat4 view; + glm::mat4 projection; + model = glm::rotate(model, (float)glfwGetTime(), glm::vec3(0.5f, 1.0f, 0.0f)); + view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f)); + projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f); + // retrieve the matrix uniform locations + unsigned int modelLoc = glGetUniformLocation(ourShader.ID, "model"); + unsigned int viewLoc = glGetUniformLocation(ourShader.ID, "view"); + // pass them to the shaders (3 different ways) + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + glUniformMatrix4fv(viewLoc, 1, GL_FALSE, &view[0][0]); + // note: currently we set the projection matrix each frame, but since the projection matrix rarely changes it's often best practice to set it outside the main loop only once. + ourShader.setMat4("projection", projection); + + // render box + glBindVertexArray(VAO); + glDrawArrays(GL_TRIANGLES, 0, 36); + + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/5.transformations/transform.frag b/src/1.getting_started/6.3.coordinate_systems_multiple_objects/6.3.coordinate_systems.fs similarity index 100% rename from src/1.getting_started/5.transformations/transform.frag rename to src/1.getting_started/6.3.coordinate_systems_multiple_objects/6.3.coordinate_systems.fs diff --git a/src/1.getting_started/6.coordinate_systems/coordinate_systems.vs b/src/1.getting_started/6.3.coordinate_systems_multiple_objects/6.3.coordinate_systems.vs similarity index 100% rename from src/1.getting_started/6.coordinate_systems/coordinate_systems.vs rename to src/1.getting_started/6.3.coordinate_systems_multiple_objects/6.3.coordinate_systems.vs diff --git a/src/1.getting_started/6.3.coordinate_systems_multiple_objects/coordinate_systems_multiple_objects.cpp b/src/1.getting_started/6.3.coordinate_systems_multiple_objects/coordinate_systems_multiple_objects.cpp new file mode 100644 index 0000000..6b88ed2 --- /dev/null +++ b/src/1.getting_started/6.3.coordinate_systems_multiple_objects/coordinate_systems_multiple_objects.cpp @@ -0,0 +1,265 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + // configure global opengl state + // ----------------------------- + glEnable(GL_DEPTH_TEST); + + // build and compile our shader zprogram + // ------------------------------------ + Shader ourShader("6.2.coordinate_systems.vs", "6.2.coordinate_systems.fs"); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + float vertices[] = { + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, + 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, + + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, + -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + + -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f + }; + // world space positions of our cubes + glm::vec3 cubePositions[] = { + glm::vec3( 0.0f, 0.0f, 0.0f), + glm::vec3( 2.0f, 5.0f, -15.0f), + glm::vec3(-1.5f, -2.2f, -2.5f), + glm::vec3(-3.8f, -2.0f, -12.3f), + glm::vec3( 2.4f, -0.4f, -3.5f), + glm::vec3(-1.7f, 3.0f, -7.5f), + glm::vec3( 1.3f, -2.0f, -2.5f), + glm::vec3( 1.5f, 2.0f, -2.5f), + glm::vec3( 1.5f, 0.2f, -1.5f), + glm::vec3(-1.3f, 1.0f, -1.5f) + }; + unsigned int VBO, VAO; + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + + glBindVertexArray(VAO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + // position attribute + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + // texture coord attribute + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + glEnableVertexAttribArray(1); + + + // 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); + 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, height, nrComponents; + stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis. + unsigned char *data = stbi_load(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + // texture 2 + // --------- + glGenTextures(1, &texture2); + glBindTexture(GL_TEXTURE_2D, texture2); + // set the texture wrapping parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + 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 + data = stbi_load(FileSystem::getPath("resources/textures/awesomeface.png").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + // note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + + // tell opengl for each sampler to which texture unit it belongs to (only has to be done once) + // ------------------------------------------------------------------------------------------- + ourShader.use(); + ourShader.setInt("texture1", 0); + ourShader.setInt("texture2", 1); + + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // also clear the depth buffer now! + + // bind textures on corresponding texture units + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture1); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, texture2); + + // activate shader + ourShader.use(); + + // create transformations + glm::mat4 view; + glm::mat4 projection; + projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f); + view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f)); + // pass transformation matrices to the shader + ourShader.setMat4("projection", projection); // note: currently we set the projection matrix each frame, but since the projection matrix rarely changes it's often best practice to set it outside the main loop only once. + ourShader.setMat4("view", view); + + // render boxes + glBindVertexArray(VAO); + for (GLuint i = 0; i < 10; i++) + { + // calculate the model matrix for each object and pass it to shader before drawing + glm::mat4 model; + model = glm::translate(model, cubePositions[i]); + float angle = 20.0f * i; + model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f)); + ourShader.setMat4("model", model); + + glDrawArrays(GL_TRIANGLES, 0, 36); + } + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/6.coordinate_systems/coordinate_systems.frag b/src/1.getting_started/6.coordinate_systems/coordinate_systems.frag deleted file mode 100644 index eb67075..0000000 --- a/src/1.getting_started/6.coordinate_systems/coordinate_systems.frag +++ /dev/null @@ -1,12 +0,0 @@ -#version 330 core -in vec2 TexCoord; - -out vec4 color; - -uniform sampler2D ourTexture1; -uniform sampler2D ourTexture2; - -void main() -{ - color = mix(texture(ourTexture1, TexCoord), texture(ourTexture2, TexCoord), 0.2); -} \ No newline at end of file diff --git a/src/1.getting_started/6.coordinate_systems/coordinate_systems_multiple_objects.cpp b/src/1.getting_started/6.coordinate_systems/coordinate_systems_multiple_objects.cpp deleted file mode 100644 index d3e1d37..0000000 --- a/src/1.getting_started/6.coordinate_systems/coordinate_systems_multiple_objects.cpp +++ /dev/null @@ -1,244 +0,0 @@ -#include - -// GLEW -#define GLEW_STATIC -#include - -// GLFW -#include - -// Other Libs -#include -// GLM Mathematics -#include -#include -#include - -// Other includes -#include -#include - -// Function prototypes -void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); - -// Window dimensions -const GLuint WIDTH = 800, HEIGHT = 600; - -// The MAIN function, from here we start the application and run the game loop -int main() -{ - // Init GLFW - glfwInit(); - // Set all the required options for GLFW - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); - - // Create a GLFWwindow object that we can use for GLFW's functions - GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr); - glfwMakeContextCurrent(window); - - // Set the required callback functions - glfwSetKeyCallback(window, key_callback); - - // Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions - glewExperimental = GL_TRUE; - // Initialize GLEW to setup the OpenGL Function pointers - glewInit(); - - // Define the viewport dimensions - glViewport(0, 0, WIDTH, HEIGHT); - - // Setup OpenGL options - glEnable(GL_DEPTH_TEST); - - - // Build and compile our shader program - Shader ourShader("coordinate_systems.vs", "coordinate_systems.frag"); - - - // Set up vertex data (and buffer(s)) and attribute pointers - GLfloat vertices[] = { - -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, - 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, - - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, - -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - - -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f - }; - // World space positions of our cubes - glm::vec3 cubePositions[] = { - glm::vec3( 0.0f, 0.0f, 0.0f), - glm::vec3( 2.0f, 5.0f, -15.0f), - glm::vec3(-1.5f, -2.2f, -2.5f), - glm::vec3(-3.8f, -2.0f, -12.3f), - glm::vec3( 2.4f, -0.4f, -3.5f), - glm::vec3(-1.7f, 3.0f, -7.5f), - glm::vec3( 1.3f, -2.0f, -2.5f), - glm::vec3( 1.5f, 2.0f, -2.5f), - glm::vec3( 1.5f, 0.2f, -1.5f), - glm::vec3(-1.3f, 1.0f, -1.5f) - }; - GLuint VBO, VAO; - glGenVertexArrays(1, &VAO); - glGenBuffers(1, &VBO); - - glBindVertexArray(VAO); - - glBindBuffer(GL_ARRAY_BUFFER, VBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - - // Position attribute - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); - glEnableVertexAttribArray(0); - // TexCoord attribute - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); - glEnableVertexAttribArray(2); - - glBindVertexArray(0); // Unbind VAO - - - // Load and create a texture - GLuint texture1; - GLuint texture2; - // ==================== - // Texture 1 - // ==================== - glGenTextures(1, &texture1); - glBindTexture(GL_TEXTURE_2D, texture1); // All upcoming GL_TEXTURE_2D operations now have effect on our texture object - // Set our texture parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture wrapping to GL_REPEAT - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - // Set texture filtering - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // Load, create texture and generate mipmaps - int width, height; - unsigned char* image = SOIL_load_image(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, 0, SOIL_LOAD_RGB); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); - glGenerateMipmap(GL_TEXTURE_2D); - SOIL_free_image_data(image); - glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture when done, so we won't accidentily mess up our texture. - // =================== - // Texture 2 - // =================== - glGenTextures(1, &texture2); - glBindTexture(GL_TEXTURE_2D, texture2); - // Set our texture parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - // Set texture filtering - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // Load, create texture and generate mipmaps - image = SOIL_load_image(FileSystem::getPath("resources/textures/awesomeface.png").c_str(), &width, &height, 0, SOIL_LOAD_RGB); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); - glGenerateMipmap(GL_TEXTURE_2D); - SOIL_free_image_data(image); - glBindTexture(GL_TEXTURE_2D, 0); - - - // Game loop - while (!glfwWindowShouldClose(window)) - { - // Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions - glfwPollEvents(); - - // Render - // Clear the colorbuffer - glClearColor(0.2f, 0.3f, 0.3f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - - // Bind Textures using texture units - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, texture1); - glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture1"), 0); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, texture2); - glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture2"), 1); - - // Activate shader - ourShader.Use(); - - // Create transformations - glm::mat4 view; - glm::mat4 projection; - view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f)); - projection = glm::perspective(45.0f, (GLfloat)WIDTH / (GLfloat)HEIGHT, 0.1f, 100.0f); - // Get their uniform location - GLint modelLoc = glGetUniformLocation(ourShader.Program, "model"); - GLint viewLoc = glGetUniformLocation(ourShader.Program, "view"); - GLint projLoc = glGetUniformLocation(ourShader.Program, "projection"); - // Pass the matrices to the shader - glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view)); - // Note: currently we set the projection matrix each frame, but since the projection matrix rarely changes it's often best practice to set it outside the main loop only once. - glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection)); - - glBindVertexArray(VAO); - for (GLuint i = 0; i < 10; i++) - { - // Calculate the model matrix for each object and pass it to shader before drawing - glm::mat4 model; - model = glm::translate(model, cubePositions[i]); - GLfloat angle = 20.0f * i; - model = glm::rotate(model, angle, glm::vec3(1.0f, 0.3f, 0.5f)); - glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); - - glDrawArrays(GL_TRIANGLES, 0, 36); - } - glBindVertexArray(0); - - // Swap the screen buffers - glfwSwapBuffers(window); - } - // Properly de-allocate all resources once they've outlived their purpose - glDeleteVertexArrays(1, &VAO); - glDeleteBuffers(1, &VBO); - // Terminate GLFW, clearing any resources allocated by GLFW. - glfwTerminate(); - return 0; -} - -// Is called whenever a key is pressed/released via GLFW -void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) -{ - if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) - glfwSetWindowShouldClose(window, GL_TRUE); -} \ No newline at end of file diff --git a/src/1.getting_started/7.1.camera_circle/7.1.camera.fs b/src/1.getting_started/7.1.camera_circle/7.1.camera.fs new file mode 100644 index 0000000..43d8561 --- /dev/null +++ b/src/1.getting_started/7.1.camera_circle/7.1.camera.fs @@ -0,0 +1,14 @@ +#version 330 core +out vec4 fragColor; + +in vec2 texCoord; + +// texture samplers +uniform sampler2D texture1; +uniform sampler2D texture2; + +void main() +{ + // linearly interpolate between both textures (80% container, 20% awesomeface) + fragColor = mix(texture(texture1, texCoord), texture(texture2, texCoord), 0.2); +} \ No newline at end of file diff --git a/src/1.getting_started/7.1.camera_circle/7.1.camera.vs b/src/1.getting_started/7.1.camera_circle/7.1.camera.vs new file mode 100644 index 0000000..1e26e0d --- /dev/null +++ b/src/1.getting_started/7.1.camera_circle/7.1.camera.vs @@ -0,0 +1,15 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec2 aTexCoord; + +out vec2 texCoord; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + +void main() +{ + gl_Position = projection * view * model * vec4(aPos, 1.0f); + texCoord = vec2(aTexCoord.x, aTexCoord.y); +} \ No newline at end of file diff --git a/src/1.getting_started/7.1.camera_circle/camera_circle.cpp b/src/1.getting_started/7.1.camera_circle/camera_circle.cpp new file mode 100644 index 0000000..b6b36d9 --- /dev/null +++ b/src/1.getting_started/7.1.camera_circle/camera_circle.cpp @@ -0,0 +1,269 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + // configure global opengl state + // ----------------------------- + glEnable(GL_DEPTH_TEST); + + // build and compile our shader zprogram + // ------------------------------------ + Shader ourShader("7.1.camera.vs", "7.1.camera.fs"); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + float vertices[] = { + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, + 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, + + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, + -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + + -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f + }; + // world space positions of our cubes + glm::vec3 cubePositions[] = { + glm::vec3( 0.0f, 0.0f, 0.0f), + glm::vec3( 2.0f, 5.0f, -15.0f), + glm::vec3(-1.5f, -2.2f, -2.5f), + glm::vec3(-3.8f, -2.0f, -12.3f), + glm::vec3 (2.4f, -0.4f, -3.5f), + glm::vec3(-1.7f, 3.0f, -7.5f), + glm::vec3( 1.3f, -2.0f, -2.5f), + glm::vec3( 1.5f, 2.0f, -2.5f), + glm::vec3( 1.5f, 0.2f, -1.5f), + glm::vec3(-1.3f, 1.0f, -1.5f) + }; + unsigned int VBO, VAO; + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + + glBindVertexArray(VAO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + // position attribute + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + // texture coord attribute + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + glEnableVertexAttribArray(1); + + + // 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); + 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, height, nrComponents; + stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis. + unsigned char *data = stbi_load(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + // texture 2 + // --------- + glGenTextures(1, &texture2); + glBindTexture(GL_TEXTURE_2D, texture2); + // set the texture wrapping parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + 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 + data = stbi_load(FileSystem::getPath("resources/textures/awesomeface.png").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + // note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + + // tell opengl for each sampler to which texture unit it belongs to (only has to be done once) + // ------------------------------------------------------------------------------------------- + ourShader.use(); + ourShader.setInt("texture1", 0); + ourShader.setInt("texture2", 1); + + // pass projection matrix to shader (as projection matrix rarely changes there's no need to do this per frame) + // ----------------------------------------------------------------------------------------------------------- + glm::mat4 projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f); + ourShader.setMat4("projection", projection); + + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // bind textures on corresponding texture units + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture1); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, texture2); + + // activate shader + ourShader.use(); + + // camera/view transformation + glm::mat4 view; + float radius = 10.0f; + float camX = sin(glfwGetTime()) * radius; + float camZ = cos(glfwGetTime()) * radius; + view = glm::lookAt(glm::vec3(camX, 0.0f, camZ), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f)); + ourShader.setMat4("view", view); + + // render boxes + glBindVertexArray(VAO); + for (GLuint i = 0; i < 10; i++) + { + // calculate the model matrix for each object and pass it to shader before drawing + glm::mat4 model; + model = glm::translate(model, cubePositions[i]); + float angle = 20.0f * i; + model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f)); + ourShader.setMat4("model", model); + + glDrawArrays(GL_TRIANGLES, 0, 36); + } + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/7.2.camera_keyboard_dt/camera_keyboard_dt.cpp b/src/1.getting_started/7.2.camera_keyboard_dt/camera_keyboard_dt.cpp new file mode 100644 index 0000000..c30340d --- /dev/null +++ b/src/1.getting_started/7.2.camera_keyboard_dt/camera_keyboard_dt.cpp @@ -0,0 +1,289 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void processInput(GLFWwindow *window); + +// camera +glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f); +glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f); +glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f); + +float deltaTime = 0.0f; // time between current frame and last frame +float lastFrame = 0.0f; + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + // configure global opengl state + // ----------------------------- + glEnable(GL_DEPTH_TEST); + + // build and compile our shader zprogram + // ------------------------------------ + Shader ourShader("7.1.camera.vs", "7.1.camera.fs"); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + float vertices[] = { + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, + 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, + + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, + -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + + -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f + }; + // world space positions of our cubes + glm::vec3 cubePositions[] = { + glm::vec3( 0.0f, 0.0f, 0.0f), + glm::vec3( 2.0f, 5.0f, -15.0f), + glm::vec3(-1.5f, -2.2f, -2.5f), + glm::vec3(-3.8f, -2.0f, -12.3f), + glm::vec3( 2.4f, -0.4f, -3.5f), + glm::vec3(-1.7f, 3.0f, -7.5f), + glm::vec3( 1.3f, -2.0f, -2.5f), + glm::vec3( 1.5f, 2.0f, -2.5f), + glm::vec3( 1.5f, 0.2f, -1.5f), + glm::vec3(-1.3f, 1.0f, -1.5f) + }; + unsigned int VBO, VAO; + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + + glBindVertexArray(VAO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + // position attribute + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + // texture coord attribute + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + glEnableVertexAttribArray(1); + + + // 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); + 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, height, nrComponents; + stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis. + unsigned char *data = stbi_load(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + // texture 2 + // --------- + glGenTextures(1, &texture2); + glBindTexture(GL_TEXTURE_2D, texture2); + // set the texture wrapping parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + 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 + data = stbi_load(FileSystem::getPath("resources/textures/awesomeface.png").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + // note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + + // tell opengl for each sampler to which texture unit it belongs to (only has to be done once) + // ------------------------------------------------------------------------------------------- + ourShader.use(); + ourShader.setInt("texture1", 0); + ourShader.setInt("texture2", 1); + + // pass projection matrix to shader (as projection matrix rarely changes there's no need to do this per frame) + // ----------------------------------------------------------------------------------------------------------- + glm::mat4 projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f); + ourShader.setMat4("projection", projection); + + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // per-frame time logic + // -------------------- + float currentFrame = glfwGetTime(); + deltaTime = currentFrame - lastFrame; + lastFrame = currentFrame; + + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // bind textures on corresponding texture units + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture1); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, texture2); + + // activate shader + ourShader.use(); + + // camera/view transformation + glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp); + ourShader.setMat4("view", view); + + // render boxes + glBindVertexArray(VAO); + for (GLuint i = 0; i < 10; i++) + { + // calculate the model matrix for each object and pass it to shader before drawing + glm::mat4 model; + model = glm::translate(model, cubePositions[i]); + float angle = 20.0f * i; + model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f)); + ourShader.setMat4("model", model); + + glDrawArrays(GL_TRIANGLES, 0, 36); + } + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); + + float cameraSpeed = 2.5 * deltaTime; + if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) + cameraPos += cameraSpeed * cameraFront; + if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) + cameraPos -= cameraSpeed * cameraFront; + if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) + cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed; + if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) + cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed; +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/1.getting_started/7.3.camera_mouse_zoom/camera_mouse_zoom.cpp b/src/1.getting_started/7.3.camera_mouse_zoom/camera_mouse_zoom.cpp new file mode 100644 index 0000000..916b65c --- /dev/null +++ b/src/1.getting_started/7.3.camera_mouse_zoom/camera_mouse_zoom.cpp @@ -0,0 +1,350 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void mouse_callback(GLFWwindow* window, double xpos, double ypos); +void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); +void processInput(GLFWwindow *window); + +// camera +glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f); +glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f); +glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f); + +bool firstMouse = true; +float yaw = -90.0f; // yaw is initialized to -90.0 degrees since a yaw of 0.0 results in a direction vector pointing to the right so we initially rotate a bit to the left. +float pitch = 0.0f; +float lastX = 800.0f / 2.0; +float lastY = 600.0 / 2.0; +float fov = 45.0f; + +float deltaTime = 0.0f; // time between current frame and last frame +float lastFrame = 0.0f; + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + glfwSetCursorPosCallback(window, mouse_callback); + glfwSetScrollCallback(window, scroll_callback); + + // tell GLFW to capture our mouse + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + // configure global opengl state + // ----------------------------- + glEnable(GL_DEPTH_TEST); + + // build and compile our shader zprogram + // ------------------------------------ + Shader ourShader("7.1.camera.vs", "7.1.camera.fs"); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + float vertices[] = { + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, + 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, + + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, + -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + + -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f + }; + // world space positions of our cubes + glm::vec3 cubePositions[] = { + glm::vec3( 0.0f, 0.0f, 0.0f), + glm::vec3( 2.0f, 5.0f, -15.0f), + glm::vec3(-1.5f, -2.2f, -2.5f), + glm::vec3(-3.8f, -2.0f, -12.3f), + glm::vec3( 2.4f, -0.4f, -3.5f), + glm::vec3(-1.7f, 3.0f, -7.5f), + glm::vec3( 1.3f, -2.0f, -2.5f), + glm::vec3( 1.5f, 2.0f, -2.5f), + glm::vec3( 1.5f, 0.2f, -1.5f), + glm::vec3(-1.3f, 1.0f, -1.5f) + }; + unsigned int VBO, VAO; + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + + glBindVertexArray(VAO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + // position attribute + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + // texture coord attribute + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + glEnableVertexAttribArray(1); + + + // 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); + 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, height, nrComponents; + stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis. + unsigned char *data = stbi_load(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + // texture 2 + // --------- + glGenTextures(1, &texture2); + glBindTexture(GL_TEXTURE_2D, texture2); + // set the texture wrapping parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + 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 + data = stbi_load(FileSystem::getPath("resources/textures/awesomeface.png").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + // note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + + // tell opengl for each sampler to which texture unit it belongs to (only has to be done once) + // ------------------------------------------------------------------------------------------- + ourShader.use(); + ourShader.setInt("texture1", 0); + ourShader.setInt("texture2", 1); + + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // per-frame time logic + // -------------------- + float currentFrame = glfwGetTime(); + deltaTime = currentFrame - lastFrame; + lastFrame = currentFrame; + + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // bind textures on corresponding texture units + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture1); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, texture2); + + // activate shader + ourShader.use(); + + // pass projection matrix to shader (note that in this case it could change every frame) + glm::mat4 projection = glm::perspective(glm::radians(fov), 800.0f / 600.0f, 0.1f, 100.0f); + ourShader.setMat4("projection", projection); + + // camera/view transformation + glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp); + ourShader.setMat4("view", view); + + // render boxes + glBindVertexArray(VAO); + for (GLuint i = 0; i < 10; i++) + { + // calculate the model matrix for each object and pass it to shader before drawing + glm::mat4 model; + model = glm::translate(model, cubePositions[i]); + float angle = 20.0f * i; + model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f)); + ourShader.setMat4("model", model); + + glDrawArrays(GL_TRIANGLES, 0, 36); + } + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); + + float cameraSpeed = 2.5 * deltaTime; + if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) + cameraPos += cameraSpeed * cameraFront; + if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) + cameraPos -= cameraSpeed * cameraFront; + if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) + cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed; + if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) + cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed; +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} + +// glfw: whenever the mouse moves, this callback is called +// ------------------------------------------------------- +void mouse_callback(GLFWwindow* window, double xpos, double ypos) +{ + if (firstMouse) + { + lastX = xpos; + lastY = ypos; + firstMouse = false; + } + + float xoffset = xpos - lastX; + float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top + lastX = xpos; + lastY = ypos; + + float sensitivity = 0.1f; // change this value to your liking + xoffset *= sensitivity; + yoffset *= sensitivity; + + yaw += xoffset; + pitch += yoffset; + + // make sure that when pitch is out of bounds, screen doesn't get flipped + if (pitch > 89.0f) + pitch = 89.0f; + if (pitch < -89.0f) + pitch = -89.0f; + + glm::vec3 front; + front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch)); + front.y = sin(glm::radians(pitch)); + front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch)); + cameraFront = glm::normalize(front); +} + +// glfw: whenever the mouse scroll wheel scrolls, this callback is called +// ---------------------------------------------------------------------- +void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) +{ + if (fov >= 1.0f && fov <= 45.0f) + fov -= yoffset; + if (fov <= 1.0f) + fov = 1.0f; + if (fov >= 45.0f) + fov = 45.0f; +} \ No newline at end of file diff --git a/src/1.getting_started/7.4.camera_class/camera_class.cpp b/src/1.getting_started/7.4.camera_class/camera_class.cpp new file mode 100644 index 0000000..71bde9d --- /dev/null +++ b/src/1.getting_started/7.4.camera_class/camera_class.cpp @@ -0,0 +1,325 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void mouse_callback(GLFWwindow* window, double xpos, double ypos); +void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); +void processInput(GLFWwindow *window); + +// camera +Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); +float lastX = 800.0f / 2.0; +float lastY = 600.0 / 2.0; +bool firstMouse = true; + +float deltaTime = 0.0f; // time between current frame and last frame +float lastFrame = 0.0f; + +int main() +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + glfwSetCursorPosCallback(window, mouse_callback); + glfwSetScrollCallback(window, scroll_callback); + + // tell GLFW to capture our mouse + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + // configure global opengl state + // ----------------------------- + glEnable(GL_DEPTH_TEST); + + // build and compile our shader zprogram + // ------------------------------------ + Shader ourShader("7.1.camera.vs", "7.1.camera.fs"); + + // set up vertex data (and buffer(s)) and configure vertex attributes + // ------------------------------------------------------------------ + float vertices[] = { + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, + 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, + + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, + -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + + -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f + }; + // world space positions of our cubes + glm::vec3 cubePositions[] = { + glm::vec3( 0.0f, 0.0f, 0.0f), + glm::vec3( 2.0f, 5.0f, -15.0f), + glm::vec3(-1.5f, -2.2f, -2.5f), + glm::vec3(-3.8f, -2.0f, -12.3f), + glm::vec3( 2.4f, -0.4f, -3.5f), + glm::vec3(-1.7f, 3.0f, -7.5f), + glm::vec3( 1.3f, -2.0f, -2.5f), + glm::vec3( 1.5f, 2.0f, -2.5f), + glm::vec3( 1.5f, 0.2f, -1.5f), + glm::vec3(-1.3f, 1.0f, -1.5f) + }; + unsigned int VBO, VAO; + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + + glBindVertexArray(VAO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + // position attribute + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + // texture coord attribute + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + glEnableVertexAttribArray(1); + + + // 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); + 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, height, nrComponents; + stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis. + unsigned char *data = stbi_load(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + // texture 2 + // --------- + glGenTextures(1, &texture2); + glBindTexture(GL_TEXTURE_2D, texture2); + // set the texture wrapping parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + 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 + data = stbi_load(FileSystem::getPath("resources/textures/awesomeface.png").c_str(), &width, &height, &nrComponents, 0); + if (data) + { + // note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + + // tell opengl for each sampler to which texture unit it belongs to (only has to be done once) + // ------------------------------------------------------------------------------------------- + ourShader.use(); + ourShader.setInt("texture1", 0); + ourShader.setInt("texture2", 1); + + + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // per-frame time logic + // -------------------- + float currentFrame = glfwGetTime(); + deltaTime = currentFrame - lastFrame; + lastFrame = currentFrame; + + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // bind textures on corresponding texture units + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture1); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, texture2); + + // activate shader + ourShader.use(); + + // pass projection matrix to shader (note that in this case it could change every frame) + glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), 800.0f / 600.0f, 0.1f, 100.0f); + ourShader.setMat4("projection", projection); + + // camera/view transformation + glm::mat4 view = camera.GetViewMatrix(); + ourShader.setMat4("view", view); + + // render boxes + glBindVertexArray(VAO); + for (GLuint i = 0; i < 10; i++) + { + // calculate the model matrix for each object and pass it to shader before drawing + glm::mat4 model; + model = glm::translate(model, cubePositions[i]); + float angle = 20.0f * i; + model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f)); + ourShader.setMat4("model", model); + + glDrawArrays(GL_TRIANGLES, 0, 36); + } + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); + + float cameraSpeed = 2.5 * deltaTime; + if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) + camera.ProcessKeyboard(FORWARD, deltaTime); + if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) + camera.ProcessKeyboard(BACKWARD, deltaTime); + if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) + camera.ProcessKeyboard(LEFT, deltaTime); + if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) + camera.ProcessKeyboard(RIGHT, deltaTime); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} + + +// glfw: whenever the mouse moves, this callback is called +// ------------------------------------------------------- +void mouse_callback(GLFWwindow* window, double xpos, double ypos) +{ + if (firstMouse) + { + lastX = xpos; + lastY = ypos; + firstMouse = false; + } + + float xoffset = xpos - lastX; + float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top + + lastX = xpos; + lastY = ypos; + + camera.ProcessMouseMovement(xoffset, yoffset); +} + +// glfw: whenever the mouse scroll wheel scrolls, this callback is called +// ---------------------------------------------------------------------- +void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) +{ + camera.ProcessMouseScroll(yoffset); +} \ No newline at end of file diff --git a/src/1.getting_started/7.camera/camera_with_class.cpp b/src/1.getting_started/7.camera/camera_with_class.cpp deleted file mode 100644 index bf0b674..0000000 --- a/src/1.getting_started/7.camera/camera_with_class.cpp +++ /dev/null @@ -1,299 +0,0 @@ -// Std. Includes -#include - -// GLEW -#define GLEW_STATIC -#include - -// GLFW -#include - -// GL includes -#include -#include - -// GLM Mathemtics -#include -#include -#include - -// Other Libs -#include -#include - -// Properties -GLuint screenWidth = 800, screenHeight = 600; - -// Function prototypes -void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); -void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); -void mouse_callback(GLFWwindow* window, double xpos, double ypos); -void Do_Movement(); - -// Camera -Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); -bool keys[1024]; -GLfloat lastX = 400, lastY = 300; -bool firstMouse = true; - -GLfloat deltaTime = 0.0f; -GLfloat lastFrame = 0.0f; - -// The MAIN function, from here we start our application and run our Game loop -int main() -{ - // Init GLFW - glfwInit(); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); - glfwWindowHint(GLFW_SAMPLES, 4); - - GLFWwindow* window = glfwCreateWindow(screenWidth, screenHeight, "LearnOpenGL", nullptr, nullptr); // Windowed - glfwMakeContextCurrent(window); - - // Set the required callback functions - glfwSetKeyCallback(window, key_callback); - glfwSetCursorPosCallback(window, mouse_callback); - glfwSetScrollCallback(window, scroll_callback); - - // Options - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - - // Initialize GLEW to setup the OpenGL Function pointers - glewExperimental = GL_TRUE; - glewInit(); - - // Define the viewport dimensions - glViewport(0, 0, screenWidth, screenHeight); - - // Setup some OpenGL options - glEnable(GL_DEPTH_TEST); - - // Setup and compile our shaders - Shader ourShader("coordinate_systems.vs", "coordinate_systems.frag"); - - // Set up our vertex data (and buffer(s)) and attribute pointers - GLfloat vertices[] = { - -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, - 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, - - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, - -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - - -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f - }; - glm::vec3 cubePositions[] = { - glm::vec3(0.0f, 0.0f, 0.0f), - glm::vec3(2.0f, 5.0f, -15.0f), - glm::vec3(-1.5f, -2.2f, -2.5f), - glm::vec3(-3.8f, -2.0f, -12.3f), - glm::vec3(2.4f, -0.4f, -3.5f), - glm::vec3(-1.7f, 3.0f, -7.5f), - glm::vec3(1.3f, -2.0f, -2.5f), - glm::vec3(1.5f, 2.0f, -2.5f), - glm::vec3(1.5f, 0.2f, -1.5f), - glm::vec3(-1.3f, 1.0f, -1.5f) - }; - - GLuint VBO, VAO; - glGenVertexArrays(1, &VAO); - glGenBuffers(1, &VBO); - // Bind our Vertex Array Object first, then bind and set our buffers and pointers. - glBindVertexArray(VAO); - - glBindBuffer(GL_ARRAY_BUFFER, VBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - - // Position attribute - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); - glEnableVertexAttribArray(0); - // TexCoord attribute - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); - glEnableVertexAttribArray(2); - - glBindVertexArray(0); // Unbind VAO - - // Load and create a texture - GLuint texture1; - GLuint texture2; - // --== TEXTURE 1 == -- - glGenTextures(1, &texture1); - glBindTexture(GL_TEXTURE_2D, texture1); // All upcoming GL_TEXTURE_2D operations now have effect on our texture object - // Set our texture parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - // Set texture filtering - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // Load, create texture and generate mipmaps - int width, height; - unsigned char* image = SOIL_load_image(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, 0, SOIL_LOAD_RGB); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); - glGenerateMipmap(GL_TEXTURE_2D); - SOIL_free_image_data(image); - glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture when done, so we won't accidentily mess up our texture. - // --== TEXTURE 2 == -- - glGenTextures(1, &texture2); - glBindTexture(GL_TEXTURE_2D, texture2); - // Set our texture parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - // Set texture filtering - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // Load, create texture and generate mipmaps - image = SOIL_load_image(FileSystem::getPath("resources/textures/awesomeface.png").c_str(), &width, &height, 0, SOIL_LOAD_RGB); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); - glGenerateMipmap(GL_TEXTURE_2D); - SOIL_free_image_data(image); - glBindTexture(GL_TEXTURE_2D, 0); - - // Game loop - while(!glfwWindowShouldClose(window)) - { - // Set frame time - GLfloat currentFrame = glfwGetTime(); - deltaTime = currentFrame - lastFrame; - lastFrame = currentFrame; - - // Check and call events - glfwPollEvents(); - Do_Movement(); - - // Clear the colorbuffer - glClearColor(0.2f, 0.3f, 0.3f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // Draw our first triangle - ourShader.Use(); - - // Bind Textures using texture units - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, texture1); - glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture1"), 0); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, texture2); - glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture2"), 1); - - // Create camera transformation - glm::mat4 view; - view = camera.GetViewMatrix(); - glm::mat4 projection; - projection = glm::perspective(camera.Zoom, (float)screenWidth/(float)screenHeight, 0.1f, 1000.0f); - // Get the uniform locations - GLint modelLoc = glGetUniformLocation(ourShader.Program, "model"); - GLint viewLoc = glGetUniformLocation(ourShader.Program, "view"); - GLint projLoc = glGetUniformLocation(ourShader.Program, "projection"); - // Pass the matrices to the shader - glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view)); - glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection)); - - glBindVertexArray(VAO); - for(GLuint i = 0; i < 10; i++) - { - // Calculate the model matrix for each object and pass it to shader before drawing - glm::mat4 model; - model = glm::translate(model, cubePositions[i]); - GLfloat angle = 20.0f * i; - model = glm::rotate(model, angle, glm::vec3(1.0f, 0.3f, 0.5f)); - glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); - - glDrawArrays(GL_TRIANGLES, 0, 36); - } - glBindVertexArray(0); - // Swap the buffers - glfwSwapBuffers(window); - } - // Properly de-allocate all resources once they've outlived their purpose - glDeleteVertexArrays(1, &VAO); - glDeleteBuffers(1, &VBO); - glfwTerminate(); - return 0; -} - -// Moves/alters the camera positions based on user input -void Do_Movement() -{ - // Camera controls - if(keys[GLFW_KEY_W]) - camera.ProcessKeyboard(FORWARD, deltaTime); - if(keys[GLFW_KEY_S]) - camera.ProcessKeyboard(BACKWARD, deltaTime); - if(keys[GLFW_KEY_A]) - camera.ProcessKeyboard(LEFT, deltaTime); - if(keys[GLFW_KEY_D]) - camera.ProcessKeyboard(RIGHT, deltaTime); -} - -// Is called whenever a key is pressed/released via GLFW -void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) -{ - //cout << key << endl; - if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) - glfwSetWindowShouldClose(window, GL_TRUE); - - if(action == GLFW_PRESS) - keys[key] = true; - else if(action == GLFW_RELEASE) - keys[key] = false; -} - -void mouse_callback(GLFWwindow* window, double xpos, double ypos) -{ - if(firstMouse) - { - lastX = xpos; - lastY = ypos; - firstMouse = false; - } - - GLfloat xoffset = xpos - lastX; - GLfloat yoffset = lastY - ypos; // Reversed since y-coordinates go from bottom to left - - lastX = xpos; - lastY = ypos; - - camera.ProcessMouseMovement(xoffset, yoffset); -} - - -void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) -{ - camera.ProcessMouseScroll(yoffset); -} \ No newline at end of file diff --git a/src/1.getting_started/7.camera/coordinate_systems.frag b/src/1.getting_started/7.camera/coordinate_systems.frag deleted file mode 100644 index eb67075..0000000 --- a/src/1.getting_started/7.camera/coordinate_systems.frag +++ /dev/null @@ -1,12 +0,0 @@ -#version 330 core -in vec2 TexCoord; - -out vec4 color; - -uniform sampler2D ourTexture1; -uniform sampler2D ourTexture2; - -void main() -{ - color = mix(texture(ourTexture1, TexCoord), texture(ourTexture2, TexCoord), 0.2); -} \ No newline at end of file diff --git a/src/1.getting_started/7.camera/coordinate_systems.vs b/src/1.getting_started/7.camera/coordinate_systems.vs deleted file mode 100644 index ae6ca8b..0000000 --- a/src/1.getting_started/7.camera/coordinate_systems.vs +++ /dev/null @@ -1,15 +0,0 @@ -#version 330 core -layout (location = 0) in vec3 position; -layout (location = 2) in vec2 texCoord; - -out vec2 TexCoord; - -uniform mat4 model; -uniform mat4 view; -uniform mat4 projection; - -void main() -{ - gl_Position = projection * view * model * vec4(position, 1.0f); - TexCoord = vec2(texCoord.x, 1.0 - texCoord.y); -} \ No newline at end of file