diff -r 53ba7e52c67c -r 8382173bfc35 Shark.cpp --- a/Shark.cpp Sat Dec 02 19:33:31 2023 +0100 +++ b/Shark.cpp Sat Dec 02 21:25:02 2023 +0100 @@ -15,28 +15,211 @@ * along with this program. If not, see . */ +#include +#include +#include #include +#include +#include +#include + +#include "x11.h" +#include "opengl.h" +#include "EPoll.h" +#include "Logger.h" +#include "MappedFile.h" +#include "ImageLoader.h" +#include "Shader.h" +#include "Program.h" +#include "FileMonitor.h" #include "Shark.h" +class Shark::Impl { +public: + + struct { + GLint aVertexXYZ = -2; + GLint aTextureXY = -2; + + GLint fColor = -2; + + GLint uModel = -2; + GLint uView = -2; + GLint uProjection = -2; + GLint uTexture = -2; + } ProgAttr; + + struct { + float yaw = -90.f; + float pitch = 0.f; + float roll = 0.f; + float fov = 45.0f; + glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f); + glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f); + glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f); + + void adjustFov(float diff) { + fov += diff; + if (fov < 1.0f) fov = 1.0f; + else if (fov > 120.0f) fov = 120.0f; + std::cerr << "field of view: " << fov << " °" << std::endl; + } + + void moveForward(const float cameraSpeed) { + cameraPos += cameraSpeed * cameraFront; + } + + void moveBackward(const float cameraSpeed) { + cameraPos -= cameraSpeed * cameraFront; + } + + void moveLeft(const float cameraSpeed) { + cameraPos -= glm::normalize( + glm::cross(cameraFront, cameraUp)) * cameraSpeed; + } + + void moveRight(const float cameraSpeed) { + cameraPos += glm::normalize( + glm::cross(cameraFront, cameraUp)) * cameraSpeed; + } + + void moveUp(const float cameraSpeed) { + cameraPos += cameraSpeed * glm::normalize(cameraUp); + } + + void moveDown(const float cameraSpeed) { + cameraPos -= cameraSpeed * glm::normalize(cameraUp); + } + + void updateCameraFrontAndUp() { + std::cerr << "--- updateCameraFrontAndUp() --------" << std::endl; + dump("pitch, yaw, roll", glm::vec3(pitch, yaw, roll)); + dump("cameraPos", cameraPos); + dump("cameraFront", cameraFront); + const auto pitchR = glm::radians(pitch); // around X axis + const auto yawR = glm::radians(yaw); // around Y axis + const auto rollR = glm::radians(roll); // around Z axis + + cameraFront.x = cos(pitchR) * cos(yawR); + cameraFront.y = sin(pitchR); + cameraFront.z = cos(pitchR) * sin(yawR); + cameraFront = glm::normalize(cameraFront); + dump("cameraFront", cameraFront); + dump("cameraUp", cameraUp); + + // TODO: review ROLL rotation and default angle + glm::mat4 rollMatrix = glm::rotate( + glm::mat4(1.0f), rollR, cameraFront); + cameraUp = glm::mat3(rollMatrix) * glm::vec3(0., 1., 0.); + dump("cameraUp", cameraUp); + std::cerr << "-------------------------------------" << std::endl; + } + + void limitPitch() { + if (pitch > +89.0f) pitch = +89.0f; + if (pitch < -89.0f) pitch = -89.0f; + } + + void turnLeft(const float angleSpeed) { + yaw -= angleSpeed; + updateCameraFrontAndUp(); + } + + void turnRight(const float angleSpeed) { + yaw += angleSpeed; + updateCameraFrontAndUp(); + } + + void turnUp(const float angleSpeed) { + pitch += angleSpeed; + limitPitch(); + updateCameraFrontAndUp(); + } + + void turnDown(const float angleSpeed) { + pitch -= angleSpeed; + limitPitch(); + updateCameraFrontAndUp(); + } + + void rollLeft(const float angleSpeed) { + roll += angleSpeed; + updateCameraFrontAndUp(); + } + + void rollRight(const float angleSpeed) { + roll -= angleSpeed; + updateCameraFrontAndUp(); + } + + } initialCtx, ctx; + + class Texture { + public: + GLuint id; + std::string fileName; + int width; + int height; + + GLfloat getRatio() const { + return (GLfloat) width / (GLfloat) height; + } + }; + + Display* dpy; + Window win; + XVisualInfo* vi; + GLXContext glc; + + FileMonitor fileMonitor; + std::vector watchedFiles; + ImageLoader imageLoader; + std::vector> shaders; + std::shared_ptr shaderProgram; + std::vector textures; + + Configuration cfg; + std::ostream& logOutput = std::cerr; + + Impl(Configuration cfg) : cfg(cfg) { + } + + void run(); + void clear(); + void runShaders(); + Window getRootWindow(Window defaultValue); + void log(LogLevel level, std::string message); + int setNonBlocking(int fd); + void loadVertices(); + Texture loadTexture(const std::string& fileName); + bool reloadTexture(const std::string& fileName); + void loadTextures(); + std::shared_ptr loadShaders(); + bool reloadShader(const std::string& fileName); + void setTitle(const std::string& suffix = ""); + +}; + Shark::Shark(const Configuration& configuration) : -cfg(configuration) { +impl(new Impl(configuration)) { } Shark::~Shark() { // TODO: more SBRM - shaders.clear(); - shaderProgram = nullptr; - XFree(vi); + impl->shaders.clear(); + impl->shaderProgram = nullptr; + XFree(impl->vi); // for (auto page : pdfTextures) glDeleteTextures(1, &page.texture); - glXMakeCurrent(dpy, None, NULL); - glXDestroyContext(dpy, glc); - XDestroyWindow(dpy, win); - XCloseDisplay(dpy); + glXMakeCurrent(impl->dpy, None, NULL); + glXDestroyContext(impl->dpy, impl->glc); + XDestroyWindow(impl->dpy, impl->win); + XCloseDisplay(impl->dpy); + delete impl; // std::cerr << "~Shark()" << std::endl; } -void Shark::setTitle(const std::string& suffix) { +void Shark::Impl::setTitle(const std::string& suffix) { std::stringstream title; title << "ShaderShark"; if (suffix.size()) title << ": " << suffix.c_str(); @@ -45,6 +228,10 @@ } void Shark::run() { + impl->run(); +} + +void Shark::Impl::run() { dpy = XOpenDisplay(NULL); if (dpy == NULL) throw std::logic_error("Unable to connect to X server"); @@ -248,7 +435,7 @@ } } -void Shark::clear() { +void Shark::Impl::clear() { glClearColor( (cfg.backgroundColor >> 16 & 0xFF) / 256., (cfg.backgroundColor >> 8 & 0xFF) / 256., @@ -257,7 +444,7 @@ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } -void Shark::runShaders() { +void Shark::Impl::runShaders() { shaderProgram->use(); checkError(&std::cerr); @@ -293,17 +480,17 @@ std::cerr << "GLSL: glDrawArrays()" << std::endl; } -void Shark::log(LogLevel level, std::string message) { +void Shark::Impl::log(LogLevel level, std::string message) { ::log(logOutput, level, message); } -int Shark::setNonBlocking(int fd) { +int Shark::Impl::setNonBlocking(int fd) { int flags = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, flags | O_NONBLOCK); return fd; } -void Shark::loadVertices() { +void Shark::Impl::loadVertices() { for (int i = 0; i < textures.size(); i++) { const Texture& tex = textures[i]; GLfloat ratio = tex.getRatio(); @@ -349,7 +536,7 @@ } } -Shark::Texture Shark::loadTexture(const std::string& fileName) { +Shark::Impl::Texture Shark::Impl::loadTexture(const std::string& fileName) { Texture tex; tex.fileName = fileName; MappedFile file(tex.fileName); @@ -377,7 +564,7 @@ return tex; } -void Shark::loadTextures() { +void Shark::Impl::loadTextures() { for (const Configuration::Texture& tex : cfg.textures) { textures.push_back(loadTexture(tex.fileName)); watchedFiles.push_back(fileMonitor.watch(tex.fileName)); @@ -388,7 +575,7 @@ } } -bool Shark::reloadTexture(const std::string& fileName) { +bool Shark::Impl::reloadTexture(const std::string& fileName) { for (const Configuration::Texture& tex : cfg.textures) { if (tex.fileName == fileName) { logOutput << "TODO: reload texture: " << fileName.c_str() << "\n"; @@ -398,7 +585,7 @@ return false; } -std::shared_ptr Shark::loadShaders() { +std::shared_ptr Shark::Impl::loadShaders() { try { // Vertex Array Object (VAO) GLuint vao; @@ -471,7 +658,7 @@ throw std::logic_error("GLSL: loadShaders() failed"); } -bool Shark::reloadShader(const std::string& fileName) { +bool Shark::Impl::reloadShader(const std::string& fileName) { for (auto shader : shaders) { if (shader->getFileName() == fileName) { shader->update(MappedFile(fileName));