summaryrefslogtreecommitdiff
path: root/gfx/gl
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/gl')
-rw-r--r--gfx/gl/camera.cpp46
-rw-r--r--gfx/gl/camera.h24
-rw-r--r--gfx/gl/shader.cpp100
-rw-r--r--gfx/gl/shader.h35
-rw-r--r--gfx/gl/shaders/basicShader.fs13
-rw-r--r--gfx/gl/shaders/basicShader.vs18
-rw-r--r--gfx/gl/transform.cpp27
-rw-r--r--gfx/gl/transform.h58
8 files changed, 321 insertions, 0 deletions
diff --git a/gfx/gl/camera.cpp b/gfx/gl/camera.cpp
new file mode 100644
index 0000000..b4a76d0
--- /dev/null
+++ b/gfx/gl/camera.cpp
@@ -0,0 +1,46 @@
+#include "camera.h"
+#include <glm/gtx/transform.hpp>
+
+Camera::Camera(glm::vec3 pos, float fov, float aspect, float zNear, float zFar) :
+ projection {glm::perspective(fov, aspect, zNear, zFar)}, pos {pos}, forward {0.0F, 0.0F, 1.0F}, up {0.0F, 1.0F,
+ 0.0F}
+{
+}
+
+glm::mat4
+Camera::GetViewProjection() const
+{
+ return projection * glm::lookAt(pos, pos + forward, up);
+}
+
+void
+Camera::MoveForward(float amt)
+{
+ pos += forward * amt;
+}
+
+void
+Camera::MoveRight(float amt)
+{
+ pos += glm::cross(up, forward) * amt;
+}
+
+void
+Camera::Pitch(float angle)
+{
+ const auto right = glm::normalize(glm::cross(up, forward));
+
+ forward = glm::vec3(glm::normalize(glm::rotate(angle, right) * glm::vec4(forward, 0.0)));
+ up = glm::normalize(glm::cross(forward, right));
+}
+
+void
+Camera::RotateY(float angle)
+{
+ static constexpr glm::vec3 UP {0.0F, 1.0F, 0.0F};
+
+ const auto rotation = glm::rotate(angle, UP);
+
+ forward = glm::vec3(glm::normalize(rotation * glm::vec4(forward, 0.0)));
+ up = glm::vec3(glm::normalize(rotation * glm::vec4(up, 0.0)));
+}
diff --git a/gfx/gl/camera.h b/gfx/gl/camera.h
new file mode 100644
index 0000000..fa4296d
--- /dev/null
+++ b/gfx/gl/camera.h
@@ -0,0 +1,24 @@
+#ifndef CAMERA_INCLUDED_H
+#define CAMERA_INCLUDED_H
+
+#include <glm/glm.hpp>
+
+class Camera {
+public:
+ Camera(glm::vec3 pos, float fov, float aspect, float zNear, float zFar);
+
+ [[nodiscard]] glm::mat4 GetViewProjection() const;
+
+ void MoveForward(float amt);
+ void MoveRight(float amt);
+ void Pitch(float angle);
+ void RotateY(float angle);
+
+private:
+ glm::mat4 projection;
+ glm::vec3 pos;
+ glm::vec3 forward;
+ glm::vec3 up;
+};
+
+#endif
diff --git a/gfx/gl/shader.cpp b/gfx/gl/shader.cpp
new file mode 100644
index 0000000..33fdf61
--- /dev/null
+++ b/gfx/gl/shader.cpp
@@ -0,0 +1,100 @@
+#include "shader.h"
+#include "transform.h"
+#include <gfx/gl/shaders/fs-basicShader.h>
+#include <gfx/gl/shaders/vs-basicShader.h>
+#include <glm/glm.hpp>
+#include <stdexcept>
+
+Shader::Shader(const std::string &) :
+ m_program {glCreateProgram()}, m_shaders {CreateShader(
+ (GLchar *)(basicShader_vs), basicShader_vs_len, GL_VERTEX_SHADER),
+ CreateShader(
+ (GLchar *)basicShader_fs, basicShader_fs_len, GL_FRAGMENT_SHADER)},
+ m_uniforms {}
+{
+ for (auto m_shader : m_shaders) {
+ glAttachShader(m_program, m_shader);
+ }
+
+ glBindAttribLocation(m_program, 0, "position");
+ glBindAttribLocation(m_program, 1, "texCoord");
+ glBindAttribLocation(m_program, 2, "normal");
+
+ glLinkProgram(m_program);
+ CheckShaderError(m_program, GL_LINK_STATUS, true, "Error linking shader program");
+
+ glValidateProgram(m_program);
+ CheckShaderError(m_program, GL_VALIDATE_STATUS, true, "Invalid shader program");
+
+ m_uniforms = {glGetUniformLocation(m_program, "MVP"), glGetUniformLocation(m_program, "Normal"),
+ glGetUniformLocation(m_program, "lightDirection")};
+}
+
+Shader::~Shader()
+{
+ for (auto m_shader : m_shaders) {
+ glDetachShader(m_program, m_shader);
+ glDeleteShader(m_shader);
+ }
+
+ glDeleteProgram(m_program);
+}
+
+void
+Shader::Bind() const
+{
+ glUseProgram(m_program);
+}
+
+void
+Shader::Update(const Transform & transform, const Camera & camera) const
+{
+ glm::mat4 MVP = transform.GetMVP(camera);
+ glm::mat4 Normal = transform.GetModel();
+
+ glUniformMatrix4fv(m_uniforms[0], 1, GL_FALSE, &MVP[0][0]);
+ glUniformMatrix4fv(m_uniforms[1], 1, GL_FALSE, &Normal[0][0]);
+ glUniform3f(m_uniforms[2], 0.0F, 0.0F, 1.0F);
+}
+
+void
+Shader::CheckShaderError(GLuint shader, GLuint flag, bool isProgram, const std::string & errorMessage)
+{
+ GLint success = 0;
+ std::array<GLchar, 1024> error {};
+
+ if (isProgram) {
+ glGetProgramiv(shader, flag, &success);
+ }
+ else {
+ glGetShaderiv(shader, flag, &success);
+ }
+
+ if (success == GL_FALSE) {
+ if (isProgram) {
+ glGetProgramInfoLog(shader, error.size(), nullptr, error.data());
+ }
+ else {
+ glGetShaderInfoLog(shader, error.size(), nullptr, error.data());
+ }
+
+ throw std::runtime_error {errorMessage + ": '" + std::string {error.data(), error.size()} + "'"};
+ }
+}
+
+GLuint
+Shader::CreateShader(const GLchar * text, GLint len, unsigned int type)
+{
+ GLuint shader = glCreateShader(type);
+
+ if (shader == 0) {
+ throw std::runtime_error {"Error compiling shader type " + std::to_string(type)};
+ }
+
+ glShaderSource(shader, 1, &text, &len);
+ glCompileShader(shader);
+
+ CheckShaderError(shader, GL_COMPILE_STATUS, false, "Error compiling shader!");
+
+ return shader;
+}
diff --git a/gfx/gl/shader.h b/gfx/gl/shader.h
new file mode 100644
index 0000000..2072199
--- /dev/null
+++ b/gfx/gl/shader.h
@@ -0,0 +1,35 @@
+#ifndef SHADER_INCLUDED_H
+#define SHADER_INCLUDED_H
+
+#include <GL/glew.h>
+#include <array>
+#include <special_members.hpp>
+#include <string>
+
+class Camera;
+class Transform;
+
+class Shader {
+public:
+ explicit Shader(const std::string & fileName);
+ virtual ~Shader();
+
+ NO_COPY(Shader);
+ NO_MOVE(Shader);
+
+ void Bind() const;
+ void Update(const Transform & transform, const Camera & camera) const;
+
+private:
+ static constexpr unsigned int NUM_SHADERS = 2;
+ static constexpr unsigned int NUM_UNIFORMS = 3;
+
+ static void CheckShaderError(GLuint shader, GLuint flag, bool isProgram, const std::string & errorMessage);
+ static GLuint CreateShader(const GLchar * text, GLint len, unsigned int type);
+
+ GLuint m_program;
+ std::array<GLuint, NUM_SHADERS> m_shaders;
+ std::array<GLint, NUM_UNIFORMS> m_uniforms;
+};
+
+#endif
diff --git a/gfx/gl/shaders/basicShader.fs b/gfx/gl/shaders/basicShader.fs
new file mode 100644
index 0000000..3aa974f
--- /dev/null
+++ b/gfx/gl/shaders/basicShader.fs
@@ -0,0 +1,13 @@
+#version 120
+
+varying vec2 texCoord0;
+varying vec3 normal0;
+
+uniform sampler2D sampler;
+uniform vec3 lightDirection;
+
+void main()
+{
+ gl_FragColor = texture2D(sampler, texCoord0) *
+ clamp(dot(-lightDirection, normal0), 0.0, 1.0);
+}
diff --git a/gfx/gl/shaders/basicShader.vs b/gfx/gl/shaders/basicShader.vs
new file mode 100644
index 0000000..e673548
--- /dev/null
+++ b/gfx/gl/shaders/basicShader.vs
@@ -0,0 +1,18 @@
+#version 120
+
+attribute vec3 position;
+attribute vec2 texCoord;
+attribute vec3 normal;
+
+varying vec2 texCoord0;
+varying vec3 normal0;
+
+uniform mat4 MVP;
+uniform mat4 Normal;
+
+void main()
+{
+ gl_Position = MVP * vec4(position, 1.0);
+ texCoord0 = texCoord;
+ normal0 = (Normal * vec4(normal, 0.0)).xyz;
+}
diff --git a/gfx/gl/transform.cpp b/gfx/gl/transform.cpp
new file mode 100644
index 0000000..7b256af
--- /dev/null
+++ b/gfx/gl/transform.cpp
@@ -0,0 +1,27 @@
+#include "transform.h"
+#include "camera.h"
+#include <glm/gtx/transform.hpp>
+
+Transform::Transform(glm::vec3 pos, glm::vec3 rot, glm::vec3 scale) : pos {pos}, rot {rot}, scale {scale} { }
+
+glm::mat4
+Transform::GetModel() const
+{
+ const auto posMat = glm::translate(pos);
+ const auto scaleMat = glm::scale(scale);
+ const auto rotX = glm::rotate(rot.x, glm::vec3(1.0, 0.0, 0.0));
+ const auto rotY = glm::rotate(rot.y, glm::vec3(0.0, 1.0, 0.0));
+ const auto rotZ = glm::rotate(rot.z, glm::vec3(0.0, 0.0, 1.0));
+ const auto rotMat = rotX * rotY * rotZ;
+
+ return posMat * rotMat * scaleMat;
+}
+
+glm::mat4
+Transform::GetMVP(const Camera & camera) const
+{
+ const auto VP = camera.GetViewProjection();
+ const auto M = GetModel();
+
+ return VP * M;
+}
diff --git a/gfx/gl/transform.h b/gfx/gl/transform.h
new file mode 100644
index 0000000..07040ae
--- /dev/null
+++ b/gfx/gl/transform.h
@@ -0,0 +1,58 @@
+#ifndef TRANSFORM_INCLUDED_H
+#define TRANSFORM_INCLUDED_H
+
+#include <glm/glm.hpp>
+
+class Camera;
+
+class Transform {
+public:
+ explicit Transform(glm::vec3 pos = {}, glm::vec3 rot = {}, glm::vec3 scale = {1.0F, 1.0F, 1.0F});
+
+ [[nodiscard]] glm::mat4 GetModel() const;
+
+ [[nodiscard]] glm::mat4 GetMVP(const Camera & camera) const;
+
+ [[nodiscard]] inline glm::vec3 &
+ GetPos()
+ {
+ return pos;
+ }
+
+ [[nodiscard]] inline glm::vec3 &
+ GetRot()
+ {
+ return rot;
+ }
+
+ [[nodiscard]] inline glm::vec3 &
+ GetScale()
+ {
+ return scale;
+ }
+
+ inline void
+ SetPos(glm::vec3 && pos)
+ {
+ this->pos = pos;
+ }
+
+ inline void
+ SetRot(glm::vec3 && rot)
+ {
+ this->rot = rot;
+ }
+
+ inline void
+ SetScale(glm::vec3 && scale)
+ {
+ this->scale = scale;
+ }
+
+private:
+ glm::vec3 pos;
+ glm::vec3 rot;
+ glm::vec3 scale;
+};
+
+#endif