From 5d030ffe6594a32f066e61c864dd3afba478c355 Mon Sep 17 00:00:00 2001 From: David Allemang Date: Mon, 9 Mar 2020 00:00:52 -0400 Subject: [PATCH] using raii shaders --- vis/include/cgl/render.hpp | 249 +++++++++++++++++++++++++++++++++++++ vis/src/main.cpp | 148 ++++++++-------------- 2 files changed, 304 insertions(+), 93 deletions(-) create mode 100644 vis/include/cgl/render.hpp diff --git a/vis/include/cgl/render.hpp b/vis/include/cgl/render.hpp new file mode 100644 index 0000000..a0c1f0a --- /dev/null +++ b/vis/include/cgl/render.hpp @@ -0,0 +1,249 @@ +#pragma once + +#include + +#include + +namespace cgl { + template + class buffer { + GLuint id; + + public: + buffer() : id(0) { + glCreateBuffers(1, &id); + std::cout << "create " << id << std::endl; + } + + buffer(buffer &) = delete; + + buffer(buffer &&o) noexcept { + id = std::exchange(o.id, 0); + }; + + ~buffer() { + glDeleteBuffers(1, &id); + id = 0; + } + + operator GLuint() const { + return id; + } + }; + + class shader { + protected: + GLuint id; + GLenum mode; + + public: + shader(GLenum mode) : mode(mode), id(0) { + id = glCreateShader(mode); + } + + shader(shader &) = delete; + + shader(shader &&o) noexcept { + mode = o.mode; + id = std::exchange(o.id, 0); + }; + + ~shader() { + glDeleteShader(id); + } + + operator GLuint() const { + return id; + } + + [[nodiscard]] GLenum get_mode() const { + return mode; + } + + [[nodiscard]] int get(GLenum pname) const { + GLint res; + glGetShaderiv(id, pname, &res); + return (int) res; + } + + [[nodiscard]] std::string get_info_log() const { + auto len = (size_t) get(GL_INFO_LOG_LENGTH); + char buffer[len]; + glGetShaderInfoLog(id, len, nullptr, buffer); + return std::string(buffer); + } + + void set_source(const std::string &src) { + const char *c_src = src.c_str(); + glShaderSource(id, 1, &c_src, nullptr); + } + + bool compile() { + glCompileShader(id); + return (bool) get(GL_COMPILE_STATUS); + } + }; + + class program { + protected: + GLuint id; + + public: + program() : id(0) { + id = glCreateProgram(); + } + + program(program &) = delete; + + program(program &&o) noexcept { + id = std::exchange(o.id, 0); + }; + + ~program() { + glDeleteProgram(id); + } + + operator GLuint() const { + return id; + } + + [[nodiscard]] int get(GLenum pname) const { + GLint res; + glGetProgramiv(id, pname, &res); + return (int) res; + } + + [[nodiscard]] std::string get_info_log() const { + auto len = (size_t) get(GL_INFO_LOG_LENGTH); + char buffer[len]; + glGetProgramInfoLog(id, len, nullptr, buffer); + return std::string(buffer); + } + + void attach(const shader &sh) { + glAttachShader(id, sh); + } + + void detach(const shader &sh) { + glDetachShader(id, sh); + } + + bool link() { + glLinkProgram(id); + return (bool) get(GL_LINK_STATUS); + } + }; + + class shaderprogram : public program { + protected: + GLenum mode; + + public: + shaderprogram(GLenum mode) : program(), mode(mode) { + glProgramParameteri(id, GL_PROGRAM_SEPARABLE, GL_TRUE); + } + + shaderprogram(shaderprogram &&o) noexcept : program(std::move(o)) { + mode = o.mode; + } + + [[nodiscard]] GLenum get_mode() const { + return mode; + } + }; + + class pipeline { + protected: + GLuint id; + + public: + pipeline() : id(0) { + glCreateProgramPipelines(1, &id); + } + + pipeline(pipeline &) = delete; + + pipeline(pipeline &&o) noexcept { + id = std::exchange(o.id, 0); + } + + ~pipeline() { + glDeleteProgramPipelines(1, &id); + id = 0; + } + + operator GLuint() const { + return id; + } + + void use_stages(const shaderprogram &pgm) { + GLbitfield bits; + switch (pgm.get_mode()) { + case GL_VERTEX_SHADER: + bits = GL_VERTEX_SHADER_BIT; + break; + case GL_TESS_CONTROL_SHADER: + bits = GL_TESS_CONTROL_SHADER_BIT; + break; + case GL_TESS_EVALUATION_SHADER: + bits = GL_TESS_EVALUATION_SHADER_BIT; + break; + case GL_GEOMETRY_SHADER: + bits = GL_GEOMETRY_SHADER_BIT; + break; + case GL_FRAGMENT_SHADER: + bits = GL_FRAGMENT_SHADER_BIT; + break; + } + + glUseProgramStages(id, bits, pgm); + } + + [[nodiscard]] int get(GLenum pname) const { + GLint res; + glGetProgramPipelineiv(id, pname, &res); + return (int) res; + } + + [[nodiscard]] std::string get_info_log() const { + auto len = (size_t) get(GL_INFO_LOG_LENGTH); + char buffer[len]; + glGetProgramPipelineInfoLog(id, len, nullptr, buffer); + return std::string(buffer); + } + }; + + shader compile_shader(GLenum mode, const std::string &src) { + shader res(mode); + + res.set_source(src); + + if (!res.compile()) + throw shader_error(res.get_info_log()); + + return res; + } + + shader compile_shader_file(GLenum mode, const std::string &file) { + return compile_shader(mode, utilReadFile(file)); + } + + shaderprogram compile_shaderprogram(GLenum mode, const std::string &src) { + shader sh = compile_shader(mode, src); + + shaderprogram res(mode); + + res.attach(sh); + + if (!res.link()) + throw shader_error(res.get_info_log()); + + res.detach(sh); + + return res; + } + + shaderprogram compile_shaderprogram_file(GLenum mode, const std::string &file) { + return compile_shaderprogram(mode, utilReadFile(file)); + } +} diff --git a/vis/src/main.cpp b/vis/src/main.cpp index f3739ce..09af24f 100644 --- a/vis/src/main.cpp +++ b/vis/src/main.cpp @@ -11,6 +11,8 @@ #include "mirror.hpp" #include "geometry.hpp" +#include + #ifdef _WIN32 extern "C" { __attribute__((unused)) __declspec(dllexport) int NvOptimusEnablement = 0x00000001; @@ -42,9 +44,6 @@ struct MeshRef { glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, ibo); glBufferData(GL_ARRAY_BUFFER, sizeof(Primitive) * primitive_count, &mesh.prims[0], GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribIPointer(0, N, GL_INT, 0, nullptr); - glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } }; @@ -75,74 +74,34 @@ Matrices build(GLFWwindow *window, float st) { return Matrices(proj, view); } -int main(int argc, char *argv[]) { - //region init window - if (!glfwInit()) { - std::cerr << "Failed to initialize GLFW" << std::endl; - return EXIT_FAILURE; - } - - auto window = glfwCreateWindow( - 1920, 1080, - "Coset Visualization", - nullptr, nullptr); - - if (!window) { - std::cerr << "Failed to create window" << std::endl; - glfwTerminate(); - exit(EXIT_FAILURE); - } - - glfwMakeContextCurrent(window); - gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); - glfwSwapInterval(0); - glClear(GL_COLOR_BUFFER_BIT); - glfwSwapBuffers(window); - //endregion - - std::cout << utilInfo(); - +void run(GLFWwindow *window) { glEnable(GL_PROGRAM_POINT_SIZE); glEnable(GL_POINT_SMOOTH); glEnable(GL_DEPTH_TEST); // glEnable(GL_CULL_FACE); glCullFace(GL_BACK); - //region shaders - GLuint slice_pipe; - glCreateProgramPipelines(1, &slice_pipe); + auto defer = cgl::compile_shaderprogram_file( + GL_VERTEX_SHADER, "shaders/slice/deferred.vs.glsl"); + auto direct_ortho = cgl::compile_shaderprogram_file( + GL_VERTEX_SHADER, "shaders/direct-ortho.vs.glsl"); + auto direct_stereo = cgl::compile_shaderprogram_file( + GL_VERTEX_SHADER, "shaders/direct-stereo.vs.glsl"); - GLuint proj_pipe; - glCreateProgramPipelines(1, &proj_pipe); + auto slice = cgl::compile_shaderprogram_file( + GL_GEOMETRY_SHADER, "shaders/slice/slice.gm.glsl"); + auto curve_stereo = cgl::compile_shaderprogram_file( + GL_GEOMETRY_SHADER, "shaders/curve-stereo.gm.glsl"); + auto curve_ortho = cgl::compile_shaderprogram_file( + GL_GEOMETRY_SHADER, "shaders/curve-ortho.gm.glsl"); - GLuint defer, direct_ortho, direct_stereo; - GLuint slice, curve_ortho, curve_stereo; - GLuint solid; + auto solid = cgl::compile_shaderprogram_file( + GL_FRAGMENT_SHADER, "shaders/solid.fs.glsl"); - try { - defer = utilCreateShaderProgramFile(GL_VERTEX_SHADER, {"shaders/slice/deferred.vs.glsl"}); - direct_ortho = utilCreateShaderProgramFile(GL_VERTEX_SHADER, {"shaders/direct-ortho.vs.glsl"}); - direct_stereo = utilCreateShaderProgramFile(GL_VERTEX_SHADER, {"shaders/direct-stereo.vs.glsl"}); - - slice = utilCreateShaderProgramFile(GL_GEOMETRY_SHADER, {"shaders/slice/slice.gm.glsl"}); - curve_stereo = utilCreateShaderProgramFile(GL_GEOMETRY_SHADER, {"shaders/curve-stereo.gm.glsl"}); - curve_ortho = utilCreateShaderProgramFile(GL_GEOMETRY_SHADER, {"shaders/curve-ortho.gm.glsl"}); - - solid = utilCreateShaderProgramFile(GL_FRAGMENT_SHADER, {"shaders/solid.fs.glsl"}); - - glUseProgramStages(proj_pipe, GL_VERTEX_SHADER_BIT, direct_stereo); -// glUseProgramStages(proj_pipe, GL_GEOMETRY_SHADER_BIT, curve_stereo); - glUseProgramStages(proj_pipe, GL_FRAGMENT_SHADER_BIT, solid); - - glUseProgramStages(slice_pipe, GL_VERTEX_SHADER_BIT, defer); - glUseProgramStages(slice_pipe, GL_GEOMETRY_SHADER_BIT, slice); - glUseProgramStages(slice_pipe, GL_FRAGMENT_SHADER_BIT, solid); - } catch (const gl_error &e) { - std::cerr << e.what() << std::endl; - glfwTerminate(); - exit(EXIT_FAILURE); - } - //endregion + cgl::pipeline proj_pipe; + proj_pipe.use_stages(direct_stereo); + proj_pipe.use_stages(curve_stereo); + proj_pipe.use_stages(solid); //region points auto group = tc::group::H(4); @@ -167,16 +126,6 @@ int main(int argc, char *argv[]) { wires.emplace_back(s); } - const unsigned SLICES_N = 4; - const GLenum SLICES_MODE = GL_POINTS; - std::vector> slices; - - for (const auto &sg_gens : Combos(g_gens, SLICES_N - 1)) { - const auto s = triangulate(group, sg_gens).tile(group, g_gens, sg_gens); - - slices.emplace_back(s); - } - //endregion GLuint vbo; @@ -206,35 +155,18 @@ int main(int argc, char *argv[]) { glBufferData(GL_UNIFORM_BUFFER, sizeof(mats), &mats, GL_STATIC_DRAW); glBindBuffer(GL_UNIFORM_BUFFER, 0); - const auto wires_dark = glm::vec3(.3, .3,.3); + glLineWidth(1.5); + const auto wires_dark = glm::vec3(.3, .3, .3); const auto wires_light = wires_dark; glBindProgramPipeline(proj_pipe); - for (int i = 0; i < wires.size(); i++) { - const auto &ref = wires[i]; - - const float f = factor(i, slices.size()); - glm::vec3 c = glm::mix(wires_dark, wires_light, f); - glProgramUniform3f(solid, 2, c.r, c.g, c.b); + for (auto ref : wires) { + glProgramUniform3f(solid, 2, 1, 1, 1); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ref.ibo); glDrawElements(WIRE_MODE, ref.index_count, GL_UNSIGNED_INT, nullptr); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } - const auto slice_dark = glm::vec3(.5, .3, .7); - const auto slice_light = glm::vec3(.9, .9, .95); - glBindProgramPipeline(slice_pipe); - for (int i = 0; i < slices.size(); i++) { - const auto &ref = slices[i]; - - const float f = factor(i, slices.size()); - glm::vec3 c = glm::mix(slice_dark, slice_light, f); - glProgramUniform3f(solid, 2, c.r, c.g, c.b); - - glBindVertexArray(ref.vao); - glDrawArrays(SLICES_MODE, 0, ref.primitive_count); - } - glBindProgramPipeline(0); glBindVertexArray(0); @@ -242,6 +174,36 @@ int main(int argc, char *argv[]) { glfwPollEvents(); } +} + +int main(int argc, char *argv[]) { + //region init window + if (!glfwInit()) { + std::cerr << "Failed to initialize GLFW" << std::endl; + return EXIT_FAILURE; + } + + auto window = glfwCreateWindow( + 1920, 1080, + "Coset Visualization", + nullptr, nullptr); + + if (!window) { + std::cerr << "Failed to create window" << std::endl; + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwMakeContextCurrent(window); + gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); + glfwSwapInterval(1); + glClear(GL_COLOR_BUFFER_BIT); + glfwSwapBuffers(window); + //endregion + + std::cout << utilInfo(); + + run(window); glfwTerminate(); return EXIT_SUCCESS;