2023-07-31 00:08:17 +02:00
|
|
|
#include "gfx.hpp"
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
2023-08-06 15:49:59 +02:00
|
|
|
#include "glm/glm.hpp"
|
|
|
|
#include "glm/gtc/matrix_transform.hpp"
|
|
|
|
|
2023-07-31 00:08:17 +02:00
|
|
|
#include "io.hpp"
|
|
|
|
|
2023-08-12 00:16:35 +02:00
|
|
|
float aspect_;
|
2023-08-06 15:49:59 +02:00
|
|
|
|
|
|
|
// Initialize GLFW, OpenGL and GLEW, open a window and make it the current context.
|
|
|
|
// Returns 0 for success, and -1 for any failure.
|
|
|
|
// Failures are printed to STDERR.
|
|
|
|
int initGraphics(GLFWwindow** window, const std::string& title)
|
|
|
|
{
|
|
|
|
// Set up GLFW, OpenGL and GLEW.
|
|
|
|
if (!glfwInit())
|
|
|
|
{
|
|
|
|
std::cerr << "Failed to initialize GLFW" << std::endl;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
|
|
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
2023-08-12 00:16:35 +02:00
|
|
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
|
|
|
|
|
|
|
|
*window = glfwCreateWindow(640, 480, title.c_str(), NULL, NULL);
|
2023-08-06 15:49:59 +02:00
|
|
|
|
|
|
|
if (!window)
|
|
|
|
{
|
|
|
|
glfwTerminate();
|
|
|
|
std::cerr << "Failed to open window with GLFW" << std::endl;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-08-12 00:16:35 +02:00
|
|
|
glfwSetWindowSizeCallback(*window, windowSizeCallback);
|
|
|
|
|
2023-08-06 15:49:59 +02:00
|
|
|
glfwMakeContextCurrent(*window);
|
|
|
|
|
|
|
|
glewExperimental = GL_TRUE;
|
|
|
|
if (glewInit() != GLEW_OK)
|
|
|
|
{
|
|
|
|
std::cerr << "Failed to initialize GLEW" << std::endl;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-08-12 00:16:35 +02:00
|
|
|
void windowSizeCallback(GLFWwindow* window, int width, int height)
|
|
|
|
{
|
|
|
|
aspect_ = (float)width / (float)height;
|
|
|
|
glViewport(0, 0, width, height);
|
|
|
|
}
|
|
|
|
|
2023-07-31 00:08:17 +02:00
|
|
|
GLuint compileShader(const std::string& shaderPath, GLenum shaderType)
|
|
|
|
{
|
|
|
|
GLuint shader;
|
|
|
|
GLint success;
|
|
|
|
|
|
|
|
std::string shaderSource = readFile(shaderPath);
|
|
|
|
const char* source = shaderSource.c_str();
|
|
|
|
|
|
|
|
shader = glCreateShader(shaderType);
|
|
|
|
glShaderSource(shader, 1, &source, NULL);
|
|
|
|
glCompileShader(shader);
|
|
|
|
|
|
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
|
|
|
if (!success)
|
|
|
|
{
|
|
|
|
GLchar infoLog[512];
|
|
|
|
glGetShaderInfoLog(shader, 512, NULL, infoLog);
|
|
|
|
std::cerr << "shader compilation failed" << std::endl
|
|
|
|
<< infoLog << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
return shader;
|
|
|
|
}
|
|
|
|
|
2023-08-06 13:08:49 +02:00
|
|
|
GLuint compileShaderProgram(const std::string& fragShaderPath)
|
2023-07-31 00:08:17 +02:00
|
|
|
{
|
|
|
|
GLuint vertShader = compileShader("./vert.glsl", GL_VERTEX_SHADER);
|
2023-08-06 13:08:49 +02:00
|
|
|
GLuint fragShader = compileShader(fragShaderPath, GL_FRAGMENT_SHADER);
|
2023-07-31 00:08:17 +02:00
|
|
|
|
|
|
|
GLuint shaderProgram = glCreateProgram();
|
|
|
|
glAttachShader(shaderProgram, vertShader);
|
|
|
|
glAttachShader(shaderProgram, fragShader);
|
|
|
|
glLinkProgram(shaderProgram);
|
|
|
|
|
|
|
|
GLint success;
|
|
|
|
GLchar infoLog[512];
|
|
|
|
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
|
|
|
|
if (!success)
|
|
|
|
{
|
|
|
|
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
|
|
|
|
std::cerr << "shader linking failed" << std::endl
|
|
|
|
<< infoLog << std::endl;
|
2023-08-03 10:26:27 +02:00
|
|
|
exit(-1);
|
2023-07-31 00:08:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// We no longer need the individual shaders
|
|
|
|
glDeleteShader(vertShader);
|
|
|
|
glDeleteShader(fragShader);
|
|
|
|
|
|
|
|
return shaderProgram;
|
|
|
|
}
|
|
|
|
|
2023-08-06 15:49:59 +02:00
|
|
|
void updateProjectionMatrix(GLuint shaderProgram)
|
|
|
|
{
|
2024-08-20 01:35:43 +02:00
|
|
|
float left = -aspect_, right = aspect_, bottom = -1.0, top = 1.0, near = -2.0, far = 1.0;
|
2023-08-06 15:49:59 +02:00
|
|
|
glm::mat4 projection = glm::ortho(left, right, bottom, top, near, far);
|
|
|
|
GLint projectionLocation = getShaderUniformLocation(shaderProgram, "_Projection");
|
|
|
|
glUniformMatrix4fv(projectionLocation, 1, GL_FALSE, &projection[0][0]);
|
|
|
|
}
|
|
|
|
|
2023-08-13 22:44:06 +02:00
|
|
|
void updateModelMatrix(GLuint shaderProgram)
|
2023-08-06 15:49:59 +02:00
|
|
|
{
|
2023-08-13 22:44:06 +02:00
|
|
|
glm::mat4 model = glm::mat4(1.0);
|
2023-08-06 15:49:59 +02:00
|
|
|
GLint modelLocation = getShaderUniformLocation(shaderProgram, "_Model");
|
|
|
|
glUniformMatrix4fv(modelLocation, 1, GL_FALSE, &model[0][0]);
|
|
|
|
}
|
|
|
|
|
2023-08-13 22:44:06 +02:00
|
|
|
void updateViewMatrix(GLuint shaderProgram, float time)
|
2023-08-06 15:49:59 +02:00
|
|
|
{
|
|
|
|
glm::mat4 view = glm::mat4(1.0);
|
2023-08-13 22:44:06 +02:00
|
|
|
|
|
|
|
// Rotation
|
|
|
|
constexpr float angle = glm::radians(10.0);
|
|
|
|
glm::vec3 axis = glm::vec3(0.0, 1.0, 0.0);
|
|
|
|
view = glm::rotate(view, angle * time, axis);
|
|
|
|
|
2023-08-06 15:49:59 +02:00
|
|
|
GLint viewLocation = getShaderUniformLocation(shaderProgram, "_View");
|
|
|
|
glUniformMatrix4fv(viewLocation, 1, GL_FALSE, &view[0][0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void updateModelViewProjectionMatrix(GLuint shaderProgram, float time)
|
|
|
|
{
|
|
|
|
// Calculate matrices
|
|
|
|
updateProjectionMatrix(shaderProgram);
|
2023-08-13 22:44:06 +02:00
|
|
|
updateModelMatrix(shaderProgram);
|
|
|
|
updateViewMatrix(shaderProgram, time);
|
2023-08-06 15:49:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
GLint getShaderUniformLocation(GLuint shaderProgram, const std::string& uniformName)
|
|
|
|
{
|
|
|
|
GLint location = glGetUniformLocation(shaderProgram, uniformName.c_str());
|
|
|
|
if (location == -1)
|
|
|
|
{
|
|
|
|
std::cerr << "Could not find uniform: " << uniformName << std::endl;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return location;
|
|
|
|
}
|
|
|
|
|