--- 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";
--- 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<Texture> textures;
- VertexShader vertexShader;
- FragmentShader fragmentShader;
+ std::vector<VertexShader> vertexShaders;
+ std::vector<FragmentShader> fragmentShaders;
unsigned long backgroundColor = (0x33 << 16 | 0x33 << 8 | 0x33);
Window rootWindow = 0;
--- 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 \
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <string>
+#include <exception>
+
+#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());
+}
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#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;
+};
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <string>
+#include <stdexcept>
+
+#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);
+ }
+}
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <epoxy/gl.h>
+#include <epoxy/glx.h>
+
+#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;
+};
--- 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<Program> Shark::loadShaders() {
try {
// Vertex Array Object (VAO)
GLuint vao;
@@ -379,36 +381,17 @@
"shaders/first.frag",
};
- std::vector<GLuint> shaders;
-
- GLuint program = glCreateProgram();
+ std::shared_ptr<Program> program = std::make_shared<Program>();
// 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> shader = std::make_shared<Shader>(
+ 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;
--- 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<std::shared_ptr<Shader>> shaders;
+ std::shared_ptr<Program> shaderProgram;
std::vector<Texture> textures;
Configuration cfg;
@@ -184,7 +191,7 @@
void loadVertices();
Texture loadTexture(const std::string& fileName);
void loadTextures();
- GLuint loadShaders();
+ std::shared_ptr<Program> loadShaders();
public:
Shark(const Configuration& cfg);
virtual ~Shark();
--- 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"
)
--- 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 @@
<logicalFolder name="root" displayName="root" projectFiles="true" kind="ROOT">
<df root="." name="0">
<in>ImageLoader.cpp</in>
+ <in>Program.cpp</in>
+ <in>Shader.cpp</in>
<in>Shark.cpp</in>
<in>shader-shark.cpp</in>
</df>
@@ -57,6 +59,14 @@
<ccTool flags="0">
</ccTool>
</item>
+ <item path="Program.cpp" ex="false" tool="1" flavor2="0">
+ <ccTool flags="0">
+ </ccTool>
+ </item>
+ <item path="Shader.cpp" ex="false" tool="1" flavor2="0">
+ <ccTool flags="0">
+ </ccTool>
+ </item>
<item path="Shark.cpp" ex="false" tool="1" flavor2="0">
<ccTool flags="0">
</ccTool>
--- 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 <iostream>
#include <string>
#include <stdexcept>
@@ -27,6 +28,8 @@
#include <glm/glm.hpp>
#include <glm/ext.hpp>
+#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");
}