# HG changeset patch # User František Kučera # Date 1701458749 -3600 # Node ID ee4ba9f5a053de9246646f612a55a07090e9125d # Parent 9aba96f0b001380173e029f04e2d3c1b3d567961 OOP for Shader and ShaderProgram diff -r 9aba96f0b001 -r ee4ba9f5a053 CLIParser.h --- a/CLIParser.h Wed Nov 29 01:27:05 2023 +0100 +++ b/CLIParser.h Fri Dec 01 20:25:49 2023 +0100 @@ -26,6 +26,7 @@ private: static const std::string OPTION_TEXTURE; + static const std::string OPTION_SHADER; static const std::string OPTION_BACKGROUND_COLOR; static const std::string OPTION_ROOT_WINDOW; @@ -70,6 +71,12 @@ Configuration::Texture tex; tex.fileName = readNext(arguments, i); c.textures.push_back(tex); + } else if (option == OPTION_SHADER) { + const auto type = readNext(arguments, i); + const auto file = readNext(arguments, i); + if (type == "fragment") c.fragmentShaders.push_back({file}); + else if (type == "vertex") c.vertexShaders .push_back({file}); + else throw std::invalid_argument("unsupported shader type"); } else if (option == OPTION_BACKGROUND_COLOR) { c.backgroundColor = parseHexColor(readNext(arguments, i)); } else if (option == OPTION_ROOT_WINDOW) { @@ -82,5 +89,6 @@ }; const std::string CLIParser::OPTION_TEXTURE = "--texture"; +const std::string CLIParser::OPTION_SHADER = "--shader"; const std::string CLIParser::OPTION_BACKGROUND_COLOR = "--background-color"; const std::string CLIParser::OPTION_ROOT_WINDOW = "--root-window"; diff -r 9aba96f0b001 -r ee4ba9f5a053 Configuration.h --- a/Configuration.h Wed Nov 29 01:27:05 2023 +0100 +++ b/Configuration.h Fri Dec 01 20:25:49 2023 +0100 @@ -43,8 +43,8 @@ // TODO: support loading whole directory and monitoring using inotify std::vector textures; - VertexShader vertexShader; - FragmentShader fragmentShader; + std::vector vertexShaders; + std::vector fragmentShaders; unsigned long backgroundColor = (0x33 << 16 | 0x33 << 8 | 0x33); Window rootWindow = 0; diff -r 9aba96f0b001 -r ee4ba9f5a053 Makefile --- a/Makefile Wed Nov 29 01:27:05 2023 +0100 +++ b/Makefile Fri Dec 01 20:25:49 2023 +0100 @@ -26,7 +26,7 @@ build: mkdir -p $(@) -SRC=Shark.cpp shader-shark.cpp ImageLoader.cpp +SRC=Shark.cpp shader-shark.cpp ImageLoader.cpp Shader.cpp Program.cpp build/shader-shark: $(SRC) build *.h $(CXX) -std=c++20 -g -o $(@) $(SRC) $$(pkg-config --cflags --libs \ diff -r 9aba96f0b001 -r ee4ba9f5a053 Program.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Program.cpp Fri Dec 01 20:25:49 2023 +0100 @@ -0,0 +1,76 @@ +/** + * ShaderShark + * Copyright © 2023 František Kučera (Frantovo.cz, GlobalCode.info) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "Program.h" + +class Program::Impl { +public: + GLuint id; +}; + +Program::Program() : impl(new Impl()) { + impl->id = glCreateProgram(); +} + +Program::~Program() { + glDeleteProgram(impl->id); + delete impl; +} + +void Program::attachShader(const Shader& shader) { + glAttachShader(impl->id, shader.getId()); +} + +void Program::detachShader(const Shader& shader) { + glDetachShader(impl->id, shader.getId()); +} + +void Program::link() { + glLinkProgram(impl->id); + GLint linkStatus; + glGetProgramiv(impl->id, GL_LINK_STATUS, &linkStatus); + if (linkStatus != GL_TRUE) { + char error[512]; + glGetProgramInfoLog(impl->id, sizeof (error), NULL, error); + throw std::logic_error( + std::string("GLSL: program failed to link: ") + error); + } +} + +void Program::use() { + glUseProgram(impl->id); + checkError(); +} + +GLint Program::getAttribLocation(const std::string& name) { + return glGetAttribLocation(impl->id, name.c_str()); +} + +GLint Program::getUniformLocation(const std::string& name) { + return glGetUniformLocation(impl->id, name.c_str()); +} + +GLint Program::getFragDataLocation(const std::string& name) { + return glGetFragDataLocation(impl->id, name.c_str()); +} + +void Program::bindFragDataLocation(const std::string& name, const GLint color) { + glBindFragDataLocation(impl->id, color, name.c_str()); +} diff -r 9aba96f0b001 -r ee4ba9f5a053 Program.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Program.h Fri Dec 01 20:25:49 2023 +0100 @@ -0,0 +1,40 @@ +/** + * ShaderShark + * Copyright © 2023 František Kučera (Frantovo.cz, GlobalCode.info) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "opengl.h" +#include "Shader.h" + +class Program { +public: + class Impl; + Program(); + virtual ~Program(); + void attachShader(const Shader& shader); + void detachShader(const Shader& shader); + void link(); + void use(); + GLint getAttribLocation(const std::string& name); + GLint getUniformLocation(const std::string& name); + GLint getFragDataLocation(const std::string& name); + void bindFragDataLocation(const std::string& name, const GLint color); +private: + Impl* impl; + Program(const Program&) = delete; + Program& operator=(const Program&) = delete; +}; diff -r 9aba96f0b001 -r ee4ba9f5a053 Shader.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Shader.cpp Fri Dec 01 20:25:49 2023 +0100 @@ -0,0 +1,68 @@ +/** + * ShaderShark + * Copyright © 2023 František Kučera (Frantovo.cz, GlobalCode.info) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "Shader.h" + +class Shader::Impl { +public: + Shader::Type type; + GLuint id; + std::string fileName; +}; + +Shader::Shader( + const Type type, + const Buffer& source, + const std::string& fileName) : impl(new Impl()) { + impl->type = type; + impl->fileName = fileName; + impl->id = glCreateShader((GLenum) impl->type); + update(source); +} + +Shader::~Shader() { + glDeleteShader(impl->id); + delete impl; +} + +GLuint Shader::getId() const { + return impl->id; +} + +const std::string Shader::getFileName() const { + return impl->fileName; +} + +void Shader::update(const Buffer& source) { + auto fileData = source.getData(); + GLint fileSize = source.getSize(); + glShaderSource(impl->id, 1, &fileData, &fileSize); + glCompileShader(impl->id); + + GLint compileStatus; + glGetShaderiv(impl->id, GL_COMPILE_STATUS, &compileStatus); + + if (compileStatus != GL_TRUE) { + char error[512]; + glGetShaderInfoLog(impl->id, sizeof (error), NULL, error); + throw std::logic_error( + std::string("GLSL: shader failed to compile: ") + error); + } +} diff -r 9aba96f0b001 -r ee4ba9f5a053 Shader.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Shader.h Fri Dec 01 20:25:49 2023 +0100 @@ -0,0 +1,45 @@ +/** + * ShaderShark + * Copyright © 2023 František Kučera (Frantovo.cz, GlobalCode.info) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +#include +#include + +#include "Buffer.h" + +class Shader { +public: + class Impl; + + enum class Type : GLenum { + FRAGMENT = GL_FRAGMENT_SHADER, + VERTEX = GL_VERTEX_SHADER, + }; + + Shader(Type type, const Buffer& source, const std::string& fileName); + virtual ~Shader(); + GLuint getId() const; + const std::string getFileName() const; + void update(const Buffer& source); +private: + Impl* impl; + Shader(const Shader&) = delete; + Shader& operator=(const Shader&) = delete; +}; diff -r 9aba96f0b001 -r ee4ba9f5a053 Shark.cpp --- a/Shark.cpp Wed Nov 29 01:27:05 2023 +0100 +++ b/Shark.cpp Fri Dec 01 20:25:49 2023 +0100 @@ -24,15 +24,25 @@ } Shark::~Shark() { + // TODO: more SBRM + shaders.clear(); + shaderProgram = nullptr; + XFree(vi); + // for (auto page : pdfTextures) glDeleteTextures(1, &page.texture); + glXMakeCurrent(dpy, None, NULL); + glXDestroyContext(dpy, glc); + XDestroyWindow(dpy, win); + XCloseDisplay(dpy); + // std::cerr << "~Shark()" << std::endl; } void Shark::run() { - Display* dpy = XOpenDisplay(NULL); + dpy = XOpenDisplay(NULL); if (dpy == NULL) throw std::logic_error("Unable to connect to X server"); GLint att[] = {GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None}; - XVisualInfo* vi = glXChooseVisual(dpy, 0, att); + vi = glXChooseVisual(dpy, 0, att); Window root = DefaultRootWindow(dpy); Window parent = cfg.rootWindow ? cfg.rootWindow : root; @@ -52,7 +62,7 @@ height = parentAttr.height; } - Window win = XCreateWindow( + win = XCreateWindow( dpy, parent, 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &swa); @@ -62,7 +72,7 @@ setX11PID(dpy, win); // XSetWindowBackground(dpy, win, 0) vs. glClearColor() - GLXContext glc = glXCreateContext(dpy, vi, NULL, GL_TRUE); + glc = glXCreateContext(dpy, vi, NULL, GL_TRUE); glXMakeCurrent(dpy, win, glc); clear(); @@ -209,14 +219,6 @@ } } } - - XFree(vi); - // for (auto page : pdfTextures) glDeleteTextures(1, &page.texture); - - glXMakeCurrent(dpy, None, NULL); - glXDestroyContext(dpy, glc); - XDestroyWindow(dpy, win); - XCloseDisplay(dpy); } void Shark::clear() { @@ -229,7 +231,7 @@ } void Shark::runShaders() { - glUseProgram(shaderProgram); + shaderProgram->use(); checkError(&std::cerr); clear(); @@ -358,7 +360,7 @@ } } -GLuint Shark::loadShaders() { +std::shared_ptr Shark::loadShaders() { try { // Vertex Array Object (VAO) GLuint vao; @@ -379,36 +381,17 @@ "shaders/first.frag", }; - std::vector shaders; - - GLuint program = glCreateProgram(); + std::shared_ptr program = std::make_shared(); // glBindFragDataLocation(program, 0, "outColor"); // glBindAttribLocation(program, LOC.input, "vertices"); for (const std::string& fileName : fileNames) { MappedFile file(fileName); - GLuint shader = glCreateShader(toShaderType(fileName)); - auto fileData = file.getData(); - GLint fileSize = file.getSize(); - glShaderSource(shader, 1, &fileData, &fileSize); - glCompileShader(shader); + std::shared_ptr shader = std::make_shared( + toShaderType(fileName), file, fileName); - GLint compileStatus; - glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus); - std::cerr << "GLSL shader compile status: " - << compileStatus - << (compileStatus == GL_TRUE ? " = OK" : " = ERROR") - << std::endl; - - if (compileStatus != GL_TRUE) { - char error[512]; - glGetShaderInfoLog(shader, sizeof (error), NULL, error); - std::cerr << "GLSL shader error: " << error; - throw std::logic_error("GLSL: shader failed to compile"); - } - - glAttachShader(program, shader); + program->attachShader(*shader.get()); shaders.push_back(shader); std::cerr << "GLSL loaded: " << fileName.c_str() << std::endl; } @@ -419,27 +402,18 @@ // the variable is still deleted and considered „inactive“. // Functions glGetAttribLocation() and glGetUniformLocation() return -1. - glLinkProgram(program); + program->link(); - ProgAttr.aVertexXYZ = glGetAttribLocation(program, "aVertexXYZ"); - ProgAttr.aTextureXY = glGetAttribLocation(program, "aTextureXY"); - ProgAttr.uModel = glGetUniformLocation(program, "uModel"); - ProgAttr.uView = glGetUniformLocation(program, "uView"); - ProgAttr.uProjection = glGetUniformLocation(program, "uProjection"); - ProgAttr.uTexture = glGetUniformLocation(program, "uTexture"); - ProgAttr.fColor = glGetFragDataLocation(program, "fColor"); - glBindFragDataLocation(program, ProgAttr.fColor, "fColor"); + ProgAttr.aVertexXYZ = program->getAttribLocation("aVertexXYZ"); + ProgAttr.aTextureXY = program->getAttribLocation("aTextureXY"); + ProgAttr.uModel = program->getUniformLocation("uModel"); + ProgAttr.uView = program->getUniformLocation("uView"); + ProgAttr.uProjection = program->getUniformLocation("uProjection"); + ProgAttr.uTexture = program->getUniformLocation("uTexture"); + ProgAttr.fColor = program->getFragDataLocation("fColor"); + program->bindFragDataLocation("fColor", ProgAttr.fColor); // listVariables(program); - GLint linkStatus; - glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); - if (linkStatus != GL_TRUE) { - char error[512]; - glGetProgramInfoLog(program, sizeof (error), NULL, error); - std::cerr << "GLSL program error: " << error; - throw std::logic_error("GLSL: program failed to link"); - } std::cerr << "GLSL shader count: " << shaders.size() << std::endl; - return program; } catch (const std::exception& e) { std::cerr << "Error while loading shaders: " << e.what() << std::endl; diff -r 9aba96f0b001 -r ee4ba9f5a053 Shark.h --- a/Shark.h Wed Nov 29 01:27:05 2023 +0100 +++ b/Shark.h Fri Dec 01 20:25:49 2023 +0100 @@ -35,6 +35,8 @@ #include "Logger.h" #include "MappedFile.h" #include "ImageLoader.h" +#include "Shader.h" +#include "Program.h" class Shark { private: @@ -167,10 +169,15 @@ return (GLfloat) width / (GLfloat) height; } }; + + Display* dpy; + Window win; + XVisualInfo* vi; + GLXContext glc; ImageLoader imageLoader; - - GLuint shaderProgram; + std::vector> shaders; + std::shared_ptr shaderProgram; std::vector textures; Configuration cfg; @@ -184,7 +191,7 @@ void loadVertices(); Texture loadTexture(const std::string& fileName); void loadTextures(); - GLuint loadShaders(); + std::shared_ptr loadShaders(); public: Shark(const Configuration& cfg); virtual ~Shark(); diff -r 9aba96f0b001 -r ee4ba9f5a053 bash-completion.sh --- a/bash-completion.sh Wed Nov 29 01:27:05 2023 +0100 +++ b/bash-completion.sh Fri Dec 01 20:25:49 2023 +0100 @@ -28,13 +28,23 @@ "147258" ) + local SHADER_TYPE=( + "vertex" + "fragment" + ) + if [[ "$w1" == "--texture" ]]; then COMPREPLY=($(compgen -f -- "$w0"; compgen -d -S / -- "$w0")) + elif [[ "$w1" == "--shader" ]]; then + COMPREPLY=($(compgen -W "${SHADER_TYPE[*]}" -- "$w0")) + elif [[ "$w2" == "--shader" ]]; then + COMPREPLY=($(compgen -f -- "$w0"; compgen -d -S / -- "$w0")) elif [[ "$w1" == "--background-color" ]]; then COMPREPLY=($(compgen -W "${COLOR[*]}" -- "$w0")) else local OPTIONS=( "--texture" + "--shader" "--background-color" "--root-window" ) diff -r 9aba96f0b001 -r ee4ba9f5a053 nbproject/configurations.xml --- a/nbproject/configurations.xml Wed Nov 29 01:27:05 2023 +0100 +++ b/nbproject/configurations.xml Fri Dec 01 20:25:49 2023 +0100 @@ -3,6 +3,8 @@ ImageLoader.cpp + Program.cpp + Shader.cpp Shark.cpp shader-shark.cpp @@ -57,6 +59,14 @@ + + + + + + + + diff -r 9aba96f0b001 -r ee4ba9f5a053 opengl.h --- a/opengl.h Wed Nov 29 01:27:05 2023 +0100 +++ b/opengl.h Fri Dec 01 20:25:49 2023 +0100 @@ -17,6 +17,7 @@ #pragma once +#include #include #include @@ -27,6 +28,8 @@ #include #include +#include "Shader.h" + inline void quads(GLfloat tx, GLfloat ty, GLfloat x, GLfloat y, GLfloat z) { glTexCoord2f(tx, ty); @@ -34,7 +37,7 @@ } inline -void checkError(std::ostream* out) { +void checkError(std::ostream* out = nullptr) { GLenum code = glGetError(); if (code == GL_NO_ERROR) { if (out) *out << "GL check: OK" << std::endl; @@ -46,9 +49,9 @@ } inline -GLenum toShaderType(const std::string& fileName) { - if (fileName.ends_with(".vert")) return GL_VERTEX_SHADER; - else if (fileName.ends_with(".frag")) return GL_FRAGMENT_SHADER; +Shader::Type toShaderType(const std::string& fileName) { + if (fileName.ends_with(".vert")) return Shader::Type::VERTEX; + else if (fileName.ends_with(".frag")) return Shader::Type::FRAGMENT; else throw std::invalid_argument("Expecting *.vert or *.frag file"); }