From 988b0bdbcd3ce3eb86421dd727ab9583d8a062cf Mon Sep 17 00:00:00 2001 From: Corentin Date: Tue, 6 Jul 2021 17:33:29 +0900 Subject: [PATCH] Box implementation, improved window API --- include/uui/application.hpp | 5 +- include/uui/component.hpp | 12 +++ include/uui/opengl/application.hpp | 14 +++- include/uui/opengl/box.hpp | 22 ++++++ include/uui/window.hpp | 13 ++-- make.py | 15 ++-- src/test/example_gl.cpp | 6 +- src/uui/opengl/application.cpp | 14 +++- src/uui/opengl/box.cpp | 114 +++++++++++++++++++++++++++++ src/uui/opengl/shaders/main.frag | 7 ++ src/uui/opengl/shaders/main.vert | 8 ++ src/uui/opengl/window.cpp | 21 ++++-- 12 files changed, 224 insertions(+), 27 deletions(-) create mode 100644 include/uui/component.hpp create mode 100644 include/uui/opengl/box.hpp create mode 100644 src/uui/opengl/box.cpp create mode 100644 src/uui/opengl/shaders/main.frag create mode 100644 src/uui/opengl/shaders/main.vert diff --git a/include/uui/application.hpp b/include/uui/application.hpp index 5a7ae07..7410bba 100644 --- a/include/uui/application.hpp +++ b/include/uui/application.hpp @@ -1,13 +1,16 @@ #pragma once +#include #include +#include "window.hpp" + namespace uui { class Application { public: virtual void run() = 0; - virtual void add_window(int width, int height, const std::string& title) = 0; + virtual std::weak_ptr add_window(int width, int height, const std::string& title) = 0; }; } // namespace uui diff --git a/include/uui/component.hpp b/include/uui/component.hpp new file mode 100644 index 0000000..6f67f5f --- /dev/null +++ b/include/uui/component.hpp @@ -0,0 +1,12 @@ +#pragma once + +namespace uui +{ + +class Component +{ +public: + virtual void render() = 0; +}; + +} diff --git a/include/uui/opengl/application.hpp b/include/uui/opengl/application.hpp index db2e589..b436b18 100644 --- a/include/uui/opengl/application.hpp +++ b/include/uui/opengl/application.hpp @@ -16,14 +16,18 @@ class GlApplication: public Application friend class GlWindow; public: +#ifdef DEBUG + constexpr static bool debug_mode = true; +#else + constexpr static bool debug_mode = false; +#endif + std::vector> windows; + GlApplication(); ~GlApplication(); void run(); - void add_window(int width, int height, const std::string& title); - -private: - std::vector> windows; + std::weak_ptr add_window(int width, int height, const std::string& title); }; class GlWindow: public Window @@ -34,6 +38,8 @@ public: GlWindow(const GlApplication& app, int width, int height, const std::string& title); ~GlWindow(); + void add_box(); + private: const GlApplication& app; diff --git a/include/uui/opengl/box.hpp b/include/uui/opengl/box.hpp new file mode 100644 index 0000000..07325bf --- /dev/null +++ b/include/uui/opengl/box.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "graphic_context.hpp" +#include "uui/component.hpp" + +namespace uui +{ +class GlBox: public Component +{ +public: + GlBox(); + ~GlBox(); + + void render(); + +private: + GLuint gl_vbo; + GLuint gl_vao; + GLuint gl_program; +}; + +} // namespace uui diff --git a/include/uui/window.hpp b/include/uui/window.hpp index cc2ae89..378af08 100644 --- a/include/uui/window.hpp +++ b/include/uui/window.hpp @@ -1,22 +1,25 @@ #pragma once -#include #include -#include -#include #include -#include #include #include "graphic_context.hpp" +#include "uui/component.hpp" +namespace uui +{ class Window { public: std::string title; + std::vector> components; - virtual void draw() = 0; + virtual void add_box() = 0; protected: GLFWwindow* glfw_window; + + virtual void draw() = 0; }; +} // namespace uui diff --git a/make.py b/make.py index 688d052..a68eb57 100644 --- a/make.py +++ b/make.py @@ -2,6 +2,7 @@ import os from pathlib import Path +import shutil from umake import make @@ -30,14 +31,16 @@ class Config: def main(): def pre_compile(): - # Compiling fragment shaders - for frag_path in Config.SOURCE_DIR.rglob('*.frag'): - out_path = (Config.BIN_DIR / frag_path.relative_to(Config.SOURCE_DIR)) + # Copying OpenGL shaders + src_opengl_shader_path = Config.SOURCE_DIR / 'uui' / 'opengl' / 'shaders' + for shader_path in ( + list(src_opengl_shader_path.rglob('*.vert')) + + list(src_opengl_shader_path.rglob('*.frag'))): + out_path = (Config.BIN_DIR / shader_path.relative_to(Config.SOURCE_DIR)) if not out_path.parent.exists(): out_path.parent.mkdir(parents=True) - if subprocess.run(['glslc', str(frag_path), '-o', str(out_path) + '.spv']).returncode != 0: - print(f'Error while compiling fragment shader {frag_path}') - return + shutil.copy(shader_path, out_path) + Config.PRE_COMPILE_FUNCTION = pre_compile make(Config) diff --git a/src/test/example_gl.cpp b/src/test/example_gl.cpp index 171030b..74e1aeb 100644 --- a/src/test/example_gl.cpp +++ b/src/test/example_gl.cpp @@ -11,8 +11,10 @@ int main() try { uui::GlApplication app; - app.add_window(800, 600, "Vulkan!"); - app.add_window(600, 600, "Vulkan 2!"); + auto window_1 = app.add_window(800, 600, "OpenGl!"); + window_1.lock()->add_box(); + auto window_2 = app.add_window(600, 600, "OpenGL 2!"); + window_2.lock()->add_box(); app.run(); } catch(const std::exception& error) diff --git a/src/uui/opengl/application.cpp b/src/uui/opengl/application.cpp index 2d05059..78931c0 100644 --- a/src/uui/opengl/application.cpp +++ b/src/uui/opengl/application.cpp @@ -1,8 +1,11 @@ #include "uui/opengl/application.hpp" +#include +#include uui::GlApplication::GlApplication() { + std::cout << "Creating the GlApplication" << std::endl; // Init GLFW glfwInit(); // Set all the required options for GLFW @@ -13,12 +16,14 @@ uui::GlApplication::GlApplication() uui::GlApplication::~GlApplication() { + std::cout << "Destroying the GlApplication" << std::endl; + windows.clear(); glfwTerminate(); } void uui::GlApplication::run() { - std::cout << "Starting the Application" << std::endl; + std::cout << "Starting the GlApplication" << std::endl; auto start_time = std::chrono::high_resolution_clock::now(); auto end_time = start_time; @@ -32,7 +37,7 @@ void uui::GlApplication::run() // std::cout << "Frame " << frame_count << ", duration: " << render_duration << std::endl; if(frame_count > 0.0f && render_duration > 500.0f) { - std::cout << "\rFPS : " << (frame_count * 1000.0f) / render_duration << " "<< std::flush; + std::cout << "\rFPS : " << (frame_count * 1000.0f) / render_duration << " " << std::flush; frame_count = 0.0f; start_time = end_time; } @@ -57,10 +62,10 @@ void uui::GlApplication::run() } frame_count += 1; } - std::cout << "Ending the Application" << std::endl; + std::cout << "Ending the GlApplication" << std::endl; } -void uui::GlApplication::add_window(int width, int height, const std::string& title) +std::weak_ptr uui::GlApplication::add_window(int width, int height, const std::string& title) { windows.push_back(std::make_unique(*this, width, height, title)); glfwSwapInterval(1); @@ -69,4 +74,5 @@ void uui::GlApplication::add_window(int width, int height, const std::string& ti glfwMakeContextCurrent((*(windows.end() - 2))->glfw_window); glfwSwapInterval(0); } + return windows.back(); } diff --git a/src/uui/opengl/box.cpp b/src/uui/opengl/box.cpp new file mode 100644 index 0000000..e09384f --- /dev/null +++ b/src/uui/opengl/box.cpp @@ -0,0 +1,114 @@ +#include "uui/opengl/box.hpp" + +#include + +#include "uui/opengl/application.hpp" +#include "uui/shader.hpp" + +uui::GlBox::GlBox() +{ + std::cout << "Creating a GlBox" << std::endl; + + // Vertex shader compilation + GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); + { + auto vertex_src = readFile("bin/uui/opengl/shaders/main.vert"); + auto vertex_code = vertex_src.data(); + glShaderSource(vertex_shader, 1, &vertex_code, NULL); + glCompileShader(vertex_shader); + if constexpr(uui::GlApplication::debug_mode) + { + int success; + char info[512]; + glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success); + if(!success) + { + glGetShaderInfoLog(vertex_shader, 512, NULL, info); + std::cout << "GlBox error : " << info << std::endl; + } + } + } + + // Fragment shader compilation + GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); + { + auto fragment_src = readFile("bin/uui/opengl/shaders/main.frag"); + auto fragment_code = fragment_src.data(); + glShaderSource(fragment_shader, 1, &fragment_code, NULL); + glCompileShader(fragment_shader); + if constexpr(uui::GlApplication::debug_mode) + { + int success; + char info[512]; + glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success); + if(!success) + { + glGetShaderInfoLog(fragment_shader, 512, NULL, info); + std::cout << "GlBox error : " << info << std::endl; + } + } + } + + // Creating shader program + gl_program = glCreateProgram(); + glAttachShader(gl_program, vertex_shader); + glAttachShader(gl_program, fragment_shader); + glLinkProgram(gl_program); + if constexpr(uui::GlApplication::debug_mode) + { + int success; + char info[512]; + glGetProgramiv(gl_program, GL_LINK_STATUS, &success); + if(!success) + { + glGetProgramInfoLog(gl_program, 512, NULL, info); + std::cout << "GlBox error : " << info << std::endl; + } + } + glDeleteShader(vertex_shader); + glDeleteShader(fragment_shader); + + // clang-format off + float vertices[] = { + -0.5f, -0.5f, 0.0f, + 0.5f, -0.5f, 0.0f, + 0.0f, 0.5f, 0.0f + }; + // clang-format on + glGenVertexArrays(1, &gl_vao); + glGenBuffers(1, &gl_vbo); + // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s). + glBindVertexArray(gl_vao); + + glBindBuffer(GL_ARRAY_BUFFER, gl_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + glVertexAttribPointer( + 0, // index + 3, // size + GL_FLOAT, // type + GL_FALSE, // enable normalization, + 3 * sizeof(float), // stride + nullptr // offset + ); + glEnableVertexAttribArray(0); + + // unbinding VBO/VAO + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); +} + +uui::GlBox::~GlBox() +{ + std::cout << "Closing a GlBox" << std::endl; + glDeleteVertexArrays(1, &gl_vao); + glDeleteProgram(gl_program); + glDeleteBuffers(1, &gl_vbo); +} + +void uui::GlBox::render() +{ + glBindVertexArray(gl_vao); + glDrawArrays(GL_TRIANGLES, 0, 3); + glUseProgram(gl_program); +} diff --git a/src/uui/opengl/shaders/main.frag b/src/uui/opengl/shaders/main.frag new file mode 100644 index 0000000..f1f1dfe --- /dev/null +++ b/src/uui/opengl/shaders/main.frag @@ -0,0 +1,7 @@ +#version 460 core +out vec4 FragColor; + +void main() +{ + FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); +} diff --git a/src/uui/opengl/shaders/main.vert b/src/uui/opengl/shaders/main.vert new file mode 100644 index 0000000..234598a --- /dev/null +++ b/src/uui/opengl/shaders/main.vert @@ -0,0 +1,8 @@ +#version 460 core + +layout (location = 0) in vec3 aPos; + +void main() +{ + gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); +} diff --git a/src/uui/opengl/window.cpp b/src/uui/opengl/window.cpp index 8a76246..5ace100 100644 --- a/src/uui/opengl/window.cpp +++ b/src/uui/opengl/window.cpp @@ -2,32 +2,43 @@ #include +#include "uui/opengl/box.hpp" + uui::GlWindow::GlWindow(const uui::GlApplication& app, int width, int height, const std::string& title): app(app) { - std::cout << "Creating a Window" << std::endl; + std::cout << "Creating a GlWindow" << std::endl; this->title = title; glfw_window = glfwCreateWindow(width, height, title.c_str(), NULL, NULL); if(glfw_window == NULL) throw std::runtime_error("GLWindow : failed to create GLFW window"); - glfwMakeContextCurrent(glfw_window); + if(!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) throw std::runtime_error("GLWindow : Failed to initialize OpenGL context"); - glViewport(0, 0, width, height); } uui::GlWindow::~GlWindow() { - std::cout << "Closing a Window" << std::endl; + std::cout << "Closing a GlWindow" << std::endl; glfwMakeContextCurrent(glfw_window); + components.clear(); glfwDestroyWindow(glfw_window); } void uui::GlWindow::draw() { glfwMakeContextCurrent(glfw_window); - glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); + + for(auto& component: components) component->render(); + glfwSwapBuffers(glfw_window); } + +void uui::GlWindow::add_box() +{ + glfwMakeContextCurrent(glfw_window); + components.push_back(std::make_unique()); +}