This repository has been archived on 2024-12-30. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
2024CG-project-render/glHelper.h
github-classroom[bot] 686dcaf351
Initial commit
2024-11-29 09:50:03 +00:00

265 lines
No EOL
6.7 KiB
C++

#ifndef GLHELPERS_H
#define GLHELPERS_H
#include "path_glsl_files.h"
class GlHelper {
public:
GLFWwindow* window;
std::vector<std::string> all_paths;
std::vector<std::string> vertex_shader_paths;
std::vector<std::string> tess_control_shader_paths;
std::vector<std::string> tess_evaluation_shader_paths;
std::vector<std::string> fragment_shader_paths;
double time_of_last_shader_compilation = 0;
bool isFirstCompilation = true;
GlHelper(int task) {
last_time = get_seconds();
setShaderPaths(task, all_paths, vertex_shader_paths, tess_control_shader_paths, tess_evaluation_shader_paths, fragment_shader_paths);
}
// Use GLFW and GLAD to create a window
GLFWwindow* createWindow() {
// Initialize GLFW
if (!glfwInit()) {
std::cerr << "Failed to initialize GLFW" << std::endl;
return NULL;
}
// Set GLFW to create an OpenGL context (version 440 core)
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
GLFWwindow* window = glfwCreateWindow(width, height, "shader-pipeline", NULL, NULL);
if (!window) {
std::cerr << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return NULL;
}
// Make the OpenGL context current
glfwMakeContextCurrent(window);
// Initialize GLAD
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cerr << "Failed to initialized GLAD" << std::endl;
glfwTerminate();
return NULL;
}
this->window = window;
return window;
}
// Handle window rescaling and update the projection matrix accordingly
void setPerspectiveMatrixBasedOnWindowScale() {
const auto& reshape = [](
GLFWwindow* window,
int _width,
int _height)
{
::width = _width, ::height = _height;
// windows can't handle variables named near and far.
float nearVal = 0.01f;
float farVal = 100.0f;
float top = static_cast<float>(tan(35. / 360. * M_PI)) * nearVal;
float right = top * (float)::width / (float)::height;
float left = -right;
float bottom = -top;
proj.setConstant(4, 4, 0.);
proj(0, 0) = (2.0f * nearVal) / (right - left);
proj(1, 1) = (2.0f * nearVal) / (top - bottom);
proj(0, 2) = (right + left) / (right - left);
proj(1, 2) = (top + bottom) / (top - bottom);
proj(2, 2) = -(farVal + nearVal) / (farVal - nearVal);
proj(3, 2) = -1.0f;
proj(2, 3) = -(2.0f * farVal * nearVal) / (farVal - nearVal);
};
// Set up window resizing
glfwSetWindowSizeCallback(window, reshape);
{
int width_window, height_window;
glfwGetWindowSize(window, &width_window, &height_window);
reshape(window, width_window, height_window);
}
}
// Setup a VAO from a mesh
void createVAO() {
icosahedron(V, F);
mesh_to_vao(V, F, VAO);
igl::opengl::report_gl_error("mesh_to_vao");
}
// Make GLFW listen for keyboard and mouse inputs
// and change the user input state accordingly
void setKeyboardAndMouseCallbacks() {
std::cout << R"(
Usage:
[] the window can be rescaled
[Click and drag] to orbit view
[Scroll] to translate view in and out
A,a toggle animation
L,l toggle wireframe rending
Z,z reset view to look along z-axis
)";
// Close the window if user presses ESC or CTRL+C
glfwSetKeyCallback(
window,
[](GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == 256 || (key == 67 && (mods & GLFW_MOD_CONTROL)))
{
glfwSetWindowShouldClose(window, true);
}
});
// Listen to keypresses on A, L and Z
glfwSetCharModsCallback(
window,
[](GLFWwindow* window, unsigned int codepoint, int modifier)
{
switch (codepoint)
{
case 'A':
case 'a':
is_animating ^= 1;
if (is_animating)
{
last_time = get_seconds();
}
break;
case 'L':
case 'l':
wire_frame ^= 1;
if (wire_frame) {
glDisable(GL_CULL_FACE);
}
else {
glEnable(GL_CULL_FACE);
}
break;
case 'Z':
case 'z':
view.matrix().block(0, 0, 3, 3).setIdentity();
break;
default:
std::cout << "Unrecognized key: " << (unsigned char)codepoint << std::endl;
break;
}
});
glfwSetMouseButtonCallback(
window,
[](GLFWwindow* window, int button, int action, int mods)
{
mouse_down = action == GLFW_PRESS;
});
glfwSetCursorPosCallback(
window,
[](GLFWwindow* window, double x, double y)
{
static double mouse_last_x = x;
static double mouse_last_y = y;
float dx = static_cast<float>(x - mouse_last_x);
float dy = static_cast<float>(y - mouse_last_y);
if (mouse_down)
{
// Two axis valuator with fixed up
float factor = std::abs(view.matrix()(2, 3));
view.rotate(
Eigen::AngleAxisf(
dx * factor / float(width),
Eigen::Vector3f(0, 1, 0)));
view.rotate(
Eigen::AngleAxisf(
dy * factor / float(height),
view.matrix().topLeftCorner(3, 3).inverse() * Eigen::Vector3f(1, 0, 0)));
}
mouse_last_x = x;
mouse_last_y = y;
});
glfwSetScrollCallback(window,
[](GLFWwindow* window, double xoffset, double yoffset)
{
view.matrix()(2, 3) =
std::min(std::max(view.matrix()(2, 3) + (float)yoffset, -100.0f), -2.0f);
});
}
bool glslFileChanged() {
for (std::string& path : all_paths)
{
if (last_modification_time(path) > time_of_last_shader_compilation)
{
if (isFirstCompilation) {
isFirstCompilation = false;
}
else {
std::cout << path << " has changed since last compilation attempt." << std::endl;
}
return true;
}
}
return false;
}
bool compileShaderIfChanged() {
if (glslFileChanged()) {
time_of_last_shader_compilation = get_seconds();
// (re)compile shader
if (!create_shader_program_from_files(
vertex_shader_paths,
tess_control_shader_paths,
tess_evaluation_shader_paths,
fragment_shader_paths,
prog_id)) {
// failed to compile shader
glDeleteProgram(prog_id);
prog_id = 0;
return false;
}
}
return true;
}
// Update the uniforms used in the GLSL shaders
void updateShaderUniforms() {
// select program
glUseProgram(prog_id);
// Attach uniforms
{
if (is_animating)
{
double now = get_seconds();
animation_seconds += now - last_time;
last_time = now;
}
glUniform1f(glGetUniformLocation(prog_id, "animation_seconds"), static_cast<GLfloat>(animation_seconds));
}
glUniformMatrix4fv(
glGetUniformLocation(prog_id, "proj"), 1, false, proj.data());
glUniformMatrix4fv(
glGetUniformLocation(prog_id, "view"), 1, false, view.matrix().data());
// Draw mesh as wireframe
if (wire_frame)
{
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
else
{
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
}
};
#endif