diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e46acf..207578d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.12) +cmake_minimum_required(VERSION 3.19) project(OpenGLTest CXX) set(CMAKE_CXX_STANDARD 17) @@ -8,7 +8,8 @@ find_package(GLEW REQUIRED) find_package(glm REQUIRED) find_package(glfw3 REQUIRED) -add_executable(opengl_test src/main.cpp) +file(GLOB SOURCES src/*.h src/*.cpp) +add_executable(opengl_test ${SOURCES}) target_link_libraries(opengl_test OpenGL::GL diff --git a/src/geometry.cpp b/src/geometry.cpp new file mode 100644 index 0000000..281e236 --- /dev/null +++ b/src/geometry.cpp @@ -0,0 +1,23 @@ +#include "geometry.h" + +void create_triangle(GLuint *VAO, GLuint *VBO) { + GLfloat vertices[] = { + -1.0f, -1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, + 0.0f, 1.0f, 0.0f + }; + + glGenVertexArrays(1, VAO); + glBindVertexArray(*VAO); + + glGenBuffers(1, VBO); + glBindBuffer(GL_ARRAY_BUFFER, *VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(0); + + // Unbinding + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); +} diff --git a/src/geometry.h b/src/geometry.h new file mode 100644 index 0000000..9ca6d61 --- /dev/null +++ b/src/geometry.h @@ -0,0 +1,4 @@ +#pragma once +#include + +void create_triangle(GLuint *VAO, GLuint *VBO); diff --git a/src/main.cpp b/src/main.cpp index 08ade88..8eca5f4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,3 @@ -#include -#include #include #include #include @@ -7,11 +5,31 @@ #include #include -// Window dimensions -const GLint WIDTH = 800, HEIGHT = 600; +#include "shader.h" +#include "geometry.h" +#include "math.h" +#include "window.h" -// Vertex Shader -static const char *vertex_shader = " \n\ +// Window dimensions + +int main() { + GLuint VAO, VBO, shader_program, uniform_model; + bool direction = true; + float tri_offset = 0.0f; + float tri_max_offset = 0.7f; + float tri_increment = 0.005f; + float current_angle = 0.0f; + bool size_direction = true; + float current_size = 0.4f; + float max_size = 0.9f; + float min_size = 0.1f; + + Window window; + bool success = setup_window(&window); + + Shader vertex_shader; + vertex_shader.type = VERTEX; + vertex_shader.raw_code = " \n\ #version 330 \n\ \n\ layout (location = 0) in vec3 pos; \n\ @@ -19,11 +37,12 @@ layout (location = 0) in vec3 pos; \n\ uniform mat4 model; \n\ \n\ void main() { \n\ - gl_Position = model * vec4(pos.x, pos.y, pos.z, 1.0); \n\ + gl_Position = model * vec4(pos, 1.0); \n\ }"; -// Fragment shader -static const char *fragment_shader = " \n\ + Shader fragment_shader; + fragment_shader.type = FRAGMENT; + fragment_shader.raw_code = " \n\ #version 330 \n\ \n\ out vec4 color; \n\ @@ -32,158 +51,12 @@ void main() { \n\ color = vec4(1.0, 0.0, 0.0, 1.0); \n\ }"; -bool add_shader(GLuint *program, const char *shader_code, GLenum shader_type) { - GLuint shader = glCreateShader(shader_type); - const GLchar *code[1]; - code[0] = shader_code; - - GLint code_length[1]; - code_length[0] = strlen(shader_code); - - glShaderSource(shader, 1, code, code_length); - glCompileShader(shader); - - GLint result = 0; - GLchar errors[1024] = { 0 }; - - glGetShaderiv(shader, GL_COMPILE_STATUS, &result); - if (!result) { - glGetShaderInfoLog(shader, sizeof(errors), NULL, errors); - printf("Error compiling the %d shader: '%s'\n", shader_type, errors); - return false; - } - - glAttachShader(*program, shader); - return true; -} - -bool compile_shaders(GLuint *shader_program, GLuint *uniform_model) { - *shader_program = glCreateProgram(); - - if (!shader_program) { - printf("Error creating shader program!\n"); - return false; - } - - add_shader(shader_program, vertex_shader, GL_VERTEX_SHADER); - add_shader(shader_program, fragment_shader, GL_FRAGMENT_SHADER); - - GLint result = 0; - GLchar errors[1024] = { 0 }; - - glLinkProgram(*shader_program); - glGetProgramiv(*shader_program, GL_LINK_STATUS, &result); - - if (!result) { - glGetProgramInfoLog(*shader_program, sizeof(errors), NULL, errors); - printf("Error linking program: '%s'\n", errors); - return false; - } - - glValidateProgram(*shader_program); - glGetProgramiv(*shader_program, GL_VALIDATE_STATUS, &result); - - if (!result) { - glGetProgramInfoLog(*shader_program, sizeof(errors), NULL, errors); - printf("Error validating program: '%s'\n", errors); - return false; - } - - *uniform_model = glGetUniformLocation(*shader_program, "model"); - - return true; -} - -void create_triangle(GLuint *VAO, GLuint *VBO) { - GLfloat vertices[] = { - -1.0f, -1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, - 0.0f, 1.0f, 0.0f - }; - - glGenVertexArrays(1, VAO); - glBindVertexArray(*VAO); - - glGenBuffers(1, VBO); - glBindBuffer(GL_ARRAY_BUFFER, *VBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); - glEnableVertexAttribArray(0); - - // Unbinding - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); -} - -int main() { - GLuint VAO, VBO, shader_program, uniform_model; - bool direction = true; - float tri_offset = 0.0f; - float tri_max_offset = 0.7f; - float tri_increment = 0.05f; - - // Initialize GLFW - glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_WAYLAND); - - if (!glfwInit()) { - printf("GLFW initialization failed!"); - glfwTerminate(); - return 1; - } - - - // Setup GLFW window properties - // OpenGL version - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); - // Core profile means it will not be backwards compatible - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); - - GLFWwindow *window = glfwCreateWindow(WIDTH, HEIGHT, "Test Window", NULL, NULL); - - if (!window) { - const char *desc; - int code = glfwGetError(&desc); - printf("GLFW window creation failed!"); - printf("GLFW error code: %d, description: %s\n", code, desc ? desc : "No description given"); - glfwTerminate(); - return 1; - } - - // Get Buffer size information - int buffer_width, buffer_height; - glfwGetFramebufferSize(window, &buffer_width, &buffer_height); - - // Set context for GLEW to use - glfwMakeContextCurrent(window); - - - glGetError(); - - // Allow modern extension features - glewExperimental = GL_TRUE; - - GLenum err = glewInit(); - if (err != GLEW_OK && err != GLEW_ERROR_NO_GLX_DISPLAY) { - printf("OpenGL version: %s\n", glGetString(GL_VERSION)); - fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); - printf("glewInit() returned: %d\n", err); - glfwDestroyWindow(window); - glfwTerminate(); - return 1; - } - - // Setup viewport size - glViewport(0, 0, buffer_width, buffer_height); - // Create our triangle create_triangle(&VAO, &VBO); - compile_shaders(&shader_program, &uniform_model); + compile_shaders(&shader_program, &uniform_model, &vertex_shader, &fragment_shader); // Loop until window is closed - while (!glfwWindowShouldClose(window)) { + while (!glfwWindowShouldClose(window.gl_window)) { // Get and handle user input events glfwPollEvents(); @@ -197,14 +70,36 @@ int main() { direction = !direction; } + current_angle += 0.1f; + + // This isn't necessary except for safety reasons + // the program will still run correctly, but if left open too + // long the number will overflow. + if (current_angle >= 360) { + current_angle -= 360; + } + + if (size_direction) { + current_size += 0.01f; + } else { + current_size -= 0.01f; + } + + if (current_size >= max_size || current_size <= min_size) { + size_direction = !size_direction; + } + // Clear window glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glUseProgram(shader_program); - glm::mat4 model = glm::mat4(1.0f); - model = glm::translate(model, glm::vec3(tri_offset, 0.0f, 0.0f)); + Matrix4 model = Matrix4(1.0f); + // The order of these matter + model = glm::translate(model, Vector3(tri_offset, 0.0f, 0.0f)); + model = glm::scale(model, Vector3(current_size, 0.4f, 1.0f)); + model = glm::rotate(model, current_angle * RADIAN_FACTOR, Vector3(0.0f, 0.0f, 1.0f)); glUniformMatrix4fv(uniform_model, 1, GL_FALSE, glm::value_ptr(model)); @@ -214,14 +109,13 @@ int main() { glBindVertexArray(0); glUseProgram(0); - // We usually have two buffers, the first is hidden and that's // the one we draw to. The second is the one we display, so // when we're done drawing we call this glfwSwapBuffers() to // swap the buffers to show the one we've been drawing to so // that it now shows. We then can start drawing on the other // buffer. - glfwSwapBuffers(window); + glfwSwapBuffers(window.gl_window); } return 0; diff --git a/src/math.h b/src/math.h new file mode 100644 index 0000000..dbdac1f --- /dev/null +++ b/src/math.h @@ -0,0 +1,11 @@ +#pragma once + +#include +#include +#include + +using Matrix4 = glm::mat4; +using Vector3 = glm::vec3; + +const float RADIAN_FACTOR = 3.14159265f / 180.0f; + diff --git a/src/shader.cpp b/src/shader.cpp new file mode 100644 index 0000000..6f246d1 --- /dev/null +++ b/src/shader.cpp @@ -0,0 +1,66 @@ +#include +#include +#include "shader.h" + +bool add_shader(GLuint *program, Shader *shader) { + shader->gl = glCreateShader(shader->type); + const GLchar *code[1]; + code[0] = shader->raw_code; + + GLint code_length[1]; + code_length[0] = strlen(shader->raw_code); + + glShaderSource(shader->gl, 1, code, code_length); + glCompileShader(shader->gl); + + GLint result = 0; + GLchar errors[1024] = { 0 }; + + glGetShaderiv(shader->gl, GL_COMPILE_STATUS, &result); + if (!result) { + glGetShaderInfoLog(shader->gl, sizeof(errors), NULL, errors); + printf("Error compiling the %d shader->gl: '%s'\n", shader->type, errors); + return false; + } + + glAttachShader(*program, shader->gl); + return true; +} + +bool compile_shaders(GLuint *program, GLuint *uniform_model, Shader *vertex_shader, Shader *fragment_shader) { + *program = glCreateProgram(); + + if (!program) { + printf("Error creating shader program!\n"); + return false; + } + + add_shader(program, vertex_shader); + add_shader(program, fragment_shader); + + GLint result = 0; + GLchar errors[1024] = { 0 }; + + glLinkProgram(*program); + glGetProgramiv(*program, GL_LINK_STATUS, &result); + + if (!result) { + glGetProgramInfoLog(*program, sizeof(errors), NULL, errors); + printf("Error linking program: '%s'\n", errors); + return false; + } + + glValidateProgram(*program); + glGetProgramiv(*program, GL_VALIDATE_STATUS, &result); + + if (!result) { + glGetProgramInfoLog(*program, sizeof(errors), NULL, errors); + printf("Error validating program: '%s'\n", errors); + return false; + } + + *uniform_model = glGetUniformLocation(*program, "model"); + + return true; +} + diff --git a/src/shader.h b/src/shader.h new file mode 100644 index 0000000..ca185fa --- /dev/null +++ b/src/shader.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +enum Shader_Type : unsigned int { + VERTEX = GL_VERTEX_SHADER, + FRAGMENT = GL_FRAGMENT_SHADER +}; + +struct Shader { + Shader_Type type; + const char *raw_code; + GLuint gl; +}; + +bool add_shader(GLuint *program, Shader *shader, const char *raw_code); + +bool compile_shaders(GLuint *shader_program, GLuint *uniform_model, Shader *vertex_shader, Shader *fragment_shader); diff --git a/src/window.cpp b/src/window.cpp new file mode 100644 index 0000000..d0de653 --- /dev/null +++ b/src/window.cpp @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "window.h" + +bool setup_window(Window *window) { + // Initialize GLFW + glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_WAYLAND); + + if (!glfwInit()) { + printf("GLFW initialization failed!"); + glfwTerminate(); + return false; + } + + // Setup GLFW window properties + // OpenGL version + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); + // Core profile means it will not be backwards compatible + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + + window->gl_window = glfwCreateWindow(window->width, window->height, "Test Window", NULL, NULL); + + if (!window) { + const char *desc; + int code = glfwGetError(&desc); + printf("GLFW window creation failed!"); + printf("GLFW error code: %d, description: %s\n", code, desc ? desc : "No description given"); + glfwTerminate(); + return false; + } + + // Get Buffer size information + int buffer_width, buffer_height; + glfwGetFramebufferSize(window->gl_window, &buffer_width, &buffer_height); + + // Set context for GLEW to use + glfwMakeContextCurrent(window->gl_window); + + glGetError(); + + // Allow modern extension features + glewExperimental = GL_TRUE; + + GLenum err = glewInit(); + if (err != GLEW_OK && err != GLEW_ERROR_NO_GLX_DISPLAY) { + printf("OpenGL version: %s\n", glGetString(GL_VERSION)); + fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); + printf("glewInit() returned: %d\n", err); + glfwDestroyWindow(window->gl_window); + glfwTerminate(); + return false; + } + + // Setup viewport size + glViewport(0, 0, buffer_width, buffer_height); + + return true; +} + diff --git a/src/window.h b/src/window.h new file mode 100644 index 0000000..29e7435 --- /dev/null +++ b/src/window.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +struct Window { + GLint width = 800, height = 600; + GLFWwindow *gl_window = nullptr; +}; + +bool setup_window(Window *window); +