/**
* 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 <iostream>
#include <iomanip>
#include <string>
#include <memory>
#include <functional>
#include <sstream>
#include <vector>
#include <chrono>
#include <unistd.h>
#include <sys/stat.h>
#include "Configuration.h"
#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"
class Shark {
private:
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<WatchedFile> watchedFiles;
ImageLoader imageLoader;
std::vector<std::shared_ptr<Shader>> shaders;
std::shared_ptr<Program> shaderProgram;
std::vector<Texture> textures;
Configuration cfg;
std::ostream& logOutput = std::cerr;
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<Program> loadShaders();
bool reloadShader(const std::string& fileName);
void setTitle(const std::string& suffix = "");
public:
Shark(const Configuration& cfg);
virtual ~Shark();
Shark(const Shark&) = delete;
Shark& operator=(const Shark&) = delete;
void run();
};