--- a/Shark.cpp Sat Dec 02 15:02:56 2023 +0100
+++ b/Shark.cpp Sat Dec 02 15:43:51 2023 +0100
@@ -36,6 +36,14 @@
// std::cerr << "~Shark()" << std::endl;
}
+void Shark::setTitle(const std::string& suffix) {
+ std::stringstream title;
+ title << "ShaderShark";
+ if (suffix.size()) title << ": " << suffix.c_str();
+ XStoreName(dpy, win, title.str().c_str());
+ XFlush(dpy);
+}
+
void Shark::run() {
dpy = XOpenDisplay(NULL);
@@ -68,7 +76,7 @@
CWColormap | CWEventMask, &swa);
XMapWindow(dpy, win);
- XStoreName(dpy, win, "ShaderShark");
+ setTitle();
setX11PID(dpy, win);
// XSetWindowBackground(dpy, win, 0) vs. glClearColor()
@@ -117,6 +125,7 @@
int epollEventCount = epoll.wait();
//std::cout << "trace: epoll.wait() = " << epollEventCount << std::endl;
for (int epollEvent = 0; epollEvent < epollEventCount; epollEvent++) {
+ bool redraw = false;
if (epoll[epollEvent].data.fd == x11fd) {
if (!XPending(dpy)) {
// otherwise STDIN events are held until the first X11 event
@@ -125,7 +134,6 @@
}
XWindowAttributes gwa;
XNextEvent(dpy, &xev);
- bool redraw = false;
if (xev.type == Expose) {
std::cout << "XEvent: Expose" << std::endl;
@@ -193,11 +201,6 @@
} else {
std::cout << "XEvent: type=" << xev.type << std::endl;
}
-
- if (redraw) {
- runShaders();
- glXSwapBuffers(dpy, win);
- }
} else if (epoll[epollEvent].data.fd == STDIN_FILENO) {
int epollFD = epoll[epollEvent].data.fd;
logOutput << "other event: fd=" << epollFD << " data=";
@@ -215,10 +218,20 @@
} else if (epoll[epollEvent].data.fd == fileMonitor.getFD()) {
std::cout << "FileMonitor event:" << std::endl;
for (FileEvent fe; fileMonitor.readEvent(fe);) {
- std::cout << " "
- << " file: " << fe.fileName
- << " mask: " << fe.mask
+ logOutput << " "
+ << " file=" << fe.fileName
+ << " mask=" << fe.mask
<< std::endl;
+ try {
+ redraw |= reloadTexture(fe.fileName);
+ redraw |= reloadShader(fe.fileName);
+ setTitle();
+ } catch (const std::exception& e) {
+ setTitle("[ERROR]");
+ logOutput << "error while reloading '"
+ << fe.fileName.c_str()
+ << "': " << e.what() << std::endl;
+ }
}
} else {
logOutput
@@ -226,6 +239,11 @@
<< epoll[epollEvent].data.fd
<< std::endl;
}
+
+ if (redraw) {
+ runShaders();
+ glXSwapBuffers(dpy, win);
+ }
}
}
}
@@ -370,6 +388,16 @@
}
}
+bool Shark::reloadTexture(const std::string& fileName) {
+ for (const Configuration::Texture& tex : cfg.textures) {
+ if (tex.fileName == fileName) {
+ logOutput << "TODO: reload texture: " << fileName.c_str() << "\n";
+ return true;
+ }
+ }
+ return false;
+}
+
std::shared_ptr<Program> Shark::loadShaders() {
try {
// Vertex Array Object (VAO)
@@ -412,6 +440,8 @@
shaders.push_back(shader);
watchedFiles.push_back(fileMonitor.watch(fileName));
std::cerr << "GLSL loaded: " << fileName.c_str() << std::endl;
+ // We may detach and delete shaders,
+ // but our shaders are small, so we keep them for later reloading.
}
// GLSL compiler does very efficient / aggressive optimization.
@@ -441,3 +471,13 @@
throw std::logic_error("GLSL: loadShaders() failed");
}
+bool Shark::reloadShader(const std::string& fileName) {
+ for (auto shader : shaders) {
+ if (shader->getFileName() == fileName) {
+ shader->update(MappedFile(fileName));
+ shaderProgram->link();
+ return true;
+ }
+ }
+ return false;
+}
--- a/Shark.h Sat Dec 02 15:02:56 2023 +0100
+++ b/Shark.h Sat Dec 02 15:43:51 2023 +0100
@@ -193,8 +193,11 @@
int setNonBlocking(int fd);
void loadVertices();
Texture loadTexture(const std::string& fileName);
+ bool reloadTexture(const std::string& fileName);
void loadTextures();
std::shared_ptr<Program> loadShaders();
+ bool reloadShader(const std::string& fileName);
+ void setTitle(const std::string& suffix = "");
public:
Shark(const Configuration& cfg);
virtual ~Shark();