Compare commits

...

10 Commits

Author SHA1 Message Date
4374b83464 Add Shader::OnCompilationErrorMessag
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m6s
2025-04-15 19:11:07 -05:00
2a2410e9bf Merge pull request 'Shader Implementation' (#42) from shaders_again into master
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m29s
Reviewed-on: #42
2025-04-15 01:21:42 -04:00
fdabbe866f Implement doxygen annotation for Shader class.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m55s
2025-04-14 22:12:28 -04:00
dac830fc7c Implement ineffectual shader for basis testing.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m44s
2025-04-14 21:45:42 -04:00
019b4aa5ae Implement Shader::UseDefault()
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has been cancelled
2025-04-14 21:44:33 -04:00
3a293a2e0c Even Epicer
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m56s
2025-04-14 21:37:27 -04:00
73de143ec5 Epic Color Transition Fragment Shader
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has been cancelled
2025-04-14 21:36:08 -04:00
5068b4660e Josh Attempts Shaders
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 3m24s
2025-04-14 21:28:06 -04:00
fd656cd543 Upgrade mcolor version.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 3m11s
2025-02-26 15:19:46 -05:00
291b3f3778 Fix the wireframe AABB not rendering correctly.
Some checks are pending
Run ReCI Build Test / Explore-Gitea-Actions (push) Waiting to run
2025-02-23 22:04:20 -05:00
8 changed files with 436 additions and 16 deletions

View File

@@ -17,7 +17,7 @@ include(cmake/CPM.cmake)
CPMAddPackage(
NAME mcolor
URL https://git.redacted.cc/maxine/mcolor/archive/Prerelease-5.zip
URL https://git.redacted.cc/maxine/mcolor/archive/Prerelease-6.2.zip
)
CPMAddPackage(

View File

@@ -1,5 +1,50 @@
#version 120
void main() {
gl_FragColor = vec4(1, 1, 1, 1);
#ifdef GL_ES
precision mediump float;
#endif
attribute vec4 gl_Color;
uniform vec2 u_resolution;
uniform float u_time;
vec3 rgb2hsb( in vec3 c ){
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz),
vec4(c.gb, K.xy),
step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r),
vec4(c.r, p.yzx),
step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)),
d / (q.x + e),
q.x);
}
// Function from Iñigo Quiles
// https://www.shadertoy.com/view/MsS3Wc
vec3 hsb2rgb( in vec3 c ){
vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),
6.0)-3.0)-1.0,
0.0,
1.0 );
rgb = rgb*rgb*(3.0-2.0*rgb);
return c.z * mix(vec3(1.0), rgb, c.y);
}
void main(){
vec2 st = gl_FragCoord.xy/u_resolution;
vec3 color = vec3(0.0);
// We map x (0.0 - 1.0) to the hue (0.0 - 1.0)
// And the y (0.0 - 1.0) to the brightness
color = hsb2rgb(vec3(st.x,1.0,st.y));
gl_FragColor = vec4(color,1.0);
gl_FragColor = gl_Color;
}

View File

@@ -1,7 +1,5 @@
#version 120
attribute vec2 position;
void main() {
gl_Position = vec4(position.x, position.y, 1.0, 1.0);
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

115
include/JGL/types/Shader.h Normal file
View File

@@ -0,0 +1,115 @@
#pragma once
#include <filesystem>
#include <J3ML/LinearAlgebra.hpp>
#include <fstream>
#include <iostream>
#include "glad/glad.h"
#include <Event.h>
// LearnOpenGL::Shader
// OpenGL Shader Class Wrapper
// Updated by dawsh
// https://learnopengl.com/code_viewer_gh.php?code=includes/learnopengl/shader.h
namespace JGL {
using namespace J3ML::LinearAlgebra;
class Shader;
}
/// TODO: Eventually support Hot-reloading shaders like in shadertoy. Should help tremendously with debugging.
class JGL::Shader {
public:
static inline Event<std::string, std::string> OnCompilationErrorMessage;
/// The default constructor does not initialize any member values.
Shader() = default;
/// Creates a shader by compiling a vertex and fragment program from the sources in the respective filesystem paths.
Shader(std::filesystem::path vertex_source_path, std::filesystem::path fragment_source_path);
/// Creates a shader by compiling a vertex and fragment program from the respective GLSL source-strings.
Shader(const std::string& vertex_code, const std::string& fragment_code);
/// @return True if the shader program successfully loaded and compiled.
bool Loaded() const;
/// @return The integer handle that OpenGL links to this shader program.
unsigned int Handle() const;
/// Enable this shader. All rendering performed thereafter will be affected by this shader code.
/// @see UseDefault.
void Use();
static void Use(GLuint shader_program_id);
static void UseDefault();
// TODO: Implement for hot-reloading.
void Reload();
// TODO: Implement for hot-reloading.
void Unload();
/// @return The Uniform variable linked to the specified name.
/// A Uniform is global a variable that is unique per shader program object, and can be accessed from any shader at any stage in the shader program.
GLint Uniform(const std::string& name) const;
/// @return The Attribute variable linked to the specified name.
/// Attributes differ from Uniforms in that their value is different for each instance of the shader-program as it is running.
GLint Attribute(const std::string& name) const;
/// Sets a `uniform bool name = value` in the shader program.
void SetBool (const std::string& name, bool value) const;
/// Sets a `uniform int name = value` in the shader program.
void SetInt (const std::string& name, int value) const;
/// Sets a `uniform float name = value` in the shader program.
void SetFloat(const std::string& name, float value) const;
/// Sets a `uniform vec2 name = value` in the shader program.
/// @note GLSL has builtin vec2, while we implement a Vector2 type. Please be aware there may be differences in implementation between them!
/// @see class J3ML::LinearAlgebra::Vector2.
void SetVector2(const std::string& name, const Vector2& value) const;
/// Sets a `uniform vec2 name = value` in the shader program.
/// @note GLSL has builtin vec2, while we implement a Vector2 type. Please be aware there may be differences in implementation between them!
/// @see class J3ML::LinearAlgebra::Vector2.
void SetVector2(const std::string& name, float x, float y) const;
/// Sets a `uniform vec3 name = value` in the shader program.
/// @note GLSL has builtin vec3, while we implement a Vector3 type. Please be aware there may be differences in implementation between them!
/// @see class J3ML::LinearAlgebra::Vector3.
void SetVector3(const std::string& name, const Vector3& value) const;
/// Sets a `uniform vec3 name = value` in the shader program.
/// @note GLSL has builtin vec3, while we implement a Vector3 type. Please be aware there may be differences in implementation between them!
/// @see class J3ML::LinearAlgebra::Vector3.
void SetVector3(const std::string& name, float x, float y, float z) const;
/// Sets a `uniform vec4 name = value` in the shader program.
/// @note GLSL has builtin vec4, while we implement aVector4 type. Please be aware there may be differences in implementation between them!
/// @see class J3ML::LinearAlgebra::Vector4.
void SetVector4(const std::string& name, const Vector4& value) const;
/// Sets a `uniform vec4 name = value` in the shader program.
/// @note GLSL has builtin vec4, while we implement a Vector4 type. Please be aware there may be differences in implementation between them!
/// @see class J3ML::LinearAlgebra::Vector4.
void SetVector4(const std::string& name, float x, float y, float z, float w) const;
/// Sets a `uniform mat2 name = value` in the shader program.
/// @note GLSL has builtin mat2, while we implement a Matrix2x2 type. Please be aware there may be differences in implementation between them!
/// @see class J3ML::LinearAlgebra::Matrix2x2
void SetMatrix2x2(const std::string& name, const Matrix2x2& value) const;
/// Sets a `uniform mat3 name = value` in the shader program.
/// @note GLSL has builtin mat3, while we implement a Matrix3x3 type. Please be aware there may be differences in implementation between them!
/// @see class J3ML::LinearAlgebra::Matrix3x3
void SetMatrix3x3(const std::string& name, const Matrix3x3& value) const;
/// Sets a `uniform mat4 name = value` in the shader program.
/// @note GLSL has builtin mat4, while we implement a Matrix4x4 type. Please be aware there may be differences in implementation between them!
/// @see class J3ML::LinearAlgebra::Matrix4x4
void SetMatrix4x4(const std::string& name, const Matrix4x4& value) const;
// TODO: Implement Uniform-Setters for GLSL types that do not have a J3ML corollary (dmat3x4, dvec4, etc).
protected:
private:
unsigned int id = 0;
std::string vertexPath;
std::string fragmentPath;
static void checkCompileErrors(GLuint shader, const std::string& type);
};

View File

@@ -7,6 +7,7 @@
#include <J3ML/Geometry/AABB.hpp>
#include <ReWindow/Logger.h>
#include <JGL/types/VertexArray.h>
#include <JGL/types/Shader.h>
using J3ML::LinearAlgebra::Vector2;
using namespace JGL::Fonts;
@@ -111,6 +112,8 @@ JGL::Font FreeSans;
Texture* image;
Texture* image_mask;
RenderTarget* j2d_render_target;
Shader shader;
float u_time = 0;
class JGLDemoWindow : public ReWindow::OpenGLWindow
{
@@ -134,17 +137,22 @@ public:
SampleRate::NONE, FilteringMode::MIPMAP_TRILINEAR);
//Texture::MultiplyByAlphaMask(*image, *image_mask);
shader = Shader(std::filesystem::path("assets/shader_programs/test_vertex.glsl"), std::filesystem::path("assets/shader_programs/test_fragment.glsl"));
}
EulerAngleXYZ textAngle = {0,0,0};
float fov = 90;
u8 pulse = 0;
float pulse = 0;
float sprite_radians = 0;
bool fov_increasing = true;
int blit_pos = 0;
void display() {
pulse++;
Shader::UseDefault();
pulse += 20 * delta_time;
float dt = GetDeltaTime();
JGL::Update({ GetSize().x, GetSize().y });
@@ -166,6 +174,8 @@ public:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
camera->render();
// All 3D elements of the scene and JGL elements *must* be rendered before the 2D stuff
/* if rendering to screen space directly. */
@@ -177,17 +187,15 @@ public:
J3D::DrawLine(Colors::Red, {-0.33,-0.125,1}, {-0.33,0.25,1});
J3D::DrawString(Colors::Red, "JGL Sample Text", {-0.33, -0.1, 1.0f}, 1.f, 32, FreeSans, textAngle, true);
//J3D::WireframeSphere(Colors::Green, {0,0,0.5f}, 0.25f, 1, 128, 128);
Sphere sphere = {{0,0, 0.5f}, 0.2125};
Sphere sphere = {{1,0, 0.5f}, 0.2125};
J3D::BatchWireframeRevoSphere(Colors::Green, &sphere, 1, 1, 8, 8, true);
J3D::RequiredLight(&test_light);
J3D::FillAABB(Colors::Whites::AliceBlue, {0,0,0.5f}, {0.05f, 0.05f, 0.05f});
J3D::WireframeAABB(Colors::Gray, {0,0,0.5f}, {0.11f, 0.06f, 0.11f});
AABB boxes[1] = {{Vector3(-0.2125, -0.2125,0.28750), Vector3(0.2125,0.2125,0.7125)}};
J3D::BatchWireframeAABB(Colors::Yellow, boxes, 1, 1);
J3D::WireframeAABB(Colors::Yellow, {0.5, 0, 0.5}, {0.125, 0.125, 0.125}, 1);
J3D::End();
J2D::Begin(j2d_render_target, true);
J2D::FillRect(Colors::Blue, {0,52}, {100,100});
J2D::DrawSprite(image, {300, 400}, sprite_radians * 0.10f, {0.5,0.5}, {1, 1}, Colors::White);
J2D::DrawMirrorSprite(image, {400, 300}, Direction::Horizontal | Direction::Vertical, sprite_radians, {0.5,0.5}, {1, 1}, Colors::White);
@@ -224,17 +232,32 @@ public:
b.Draw();
c.Draw();
d.Draw();
J2D::End();
shader.Use();
J2D::Begin();
J2D::DrawRenderTarget(j2d_render_target, {0, 0});
J2D::DrawSprite(image, image_mask, {0, 0}, 0.25, {0.5, 0.5}, {1,1});
J2D::End();
}
void OnRefresh(float elapsed) override {
u_time += elapsed;
shader.SetFloat("u_time", u_time);
auto dimensions = GetSize();
shader.SetVector2("u_resolution", Vector2(dimensions.x, dimensions.y));
fps = GetRefreshRate();
if (IsKeyDown(Keys::RightArrow))
@@ -309,6 +332,10 @@ int main(int argc, char** argv) {
if (!file.is_open())
return -1;
Shader::OnCompilationErrorMessage += [] (std::string type, std::string info) {
std::cout << type << ", " << info << std::endl;
};
/*
std::stringstream buffer;
buffer << file.rdbuf();

View File

@@ -48,7 +48,7 @@ void JGL::J3D::Begin(bool two_pass) {
auto aspect = (float) window_size.x / (float) window_size.y;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMultMatrixf(OpenGLPerspectiveProjectionRH(fov, aspect, 0.001, far_plane).data());
glLoadMatrixf(OpenGLPerspectiveProjectionRH(fov, aspect, 0.001, far_plane).data());
glMatrixMode(GL_MODELVIEW);
//Get what the draw color was before we did anything.
@@ -248,7 +248,7 @@ void JGL::J3D::BatchWireframeRevoSphere(const Color4& color, const Sphere* spher
glDrawArrays(GL_LINE_LOOP, 0, vertex_data.GetLength());
if (draw_stacks)
glRotatef(90, 0, 1, 0),
glDrawArrays(GL_LINE_LOOP, 0, vertex_data.GetLength());
glDrawArrays(GL_LINE_LOOP, 0, vertex_data.GetLength());
glPopMatrix();
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -373,6 +373,7 @@ void JGL::J3D::BatchWireframeAABB(const Color4& color, const AABB* boxes, const
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_vertex_data->GetHandle());
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ShapeCache::cube_index_data->GetHandle());
for (size_t i = 0; i < box_count; i++) {
Vector3 delta = (boxes[i].maxPoint - boxes[i].minPoint) / 2;
@@ -380,7 +381,7 @@ void JGL::J3D::BatchWireframeAABB(const Color4& color, const AABB* boxes, const
glPushMatrix();
glTranslatef(center.x, center.y, center.z);
glScalef(delta.x, delta.y, delta.z);
glDrawArrays(GL_LINES, 0, ShapeCache::cube_vertex_data->GetLength());
glDrawElements(GL_LINE_LOOP, ShapeCache::cube_index_data->GetLength(), GL_UNSIGNED_INT, nullptr);
glPopMatrix();
}
glBindBuffer(GL_ARRAY_BUFFER, 0);

View File

@@ -15,6 +15,8 @@ namespace JGL {
class JGL::State {
public:
//Matrix4x4 transformation = Matrix4x4::Identity;
GLfloat clear_color[4] = {0, 0, 0, 1};
GLfloat draw_color[4] = {1, 1, 1, 1};
GLint viewport[4] = {0, 0, 0, 0};

232
src/types/Shader.cpp Normal file
View File

@@ -0,0 +1,232 @@
#include <JGL/types/Shader.h>
#include <glad/glad.h>
namespace JGL {
Shader::Shader(std::filesystem::path vertex_source_path, std::filesystem::path fragment_source_path) {
std::string vertex_code;
std::string fragment_code;
std::string geometry_code; // Currently unused, might be supported later.
std::string compute_code; // Currently unused, might be supported later.
std::ifstream vShaderFile;
std::ifstream fShaderFile;
std::ifstream gShaderFile;
std::ifstream cShaderFile;
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
gShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
cShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
// Open Files
vShaderFile.open(vertex_source_path);
fShaderFile.open(fragment_source_path);
std::stringstream vShaderStream, fShaderStream;
// Read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// close file handlers
vShaderFile.close();
fShaderFile.close();
// convert stream into string
vertex_code = vShaderStream.str();
fragment_code = fShaderStream.str();
if (false) {
gShaderFile.open("");
std::stringstream gShaderStream;
gShaderStream << gShaderFile.rdbuf();
gShaderFile.close();
geometry_code = gShaderStream.str();
}
} catch (std::ifstream::failure& e) {
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << std::endl;
}
const char* vShaderCode = vertex_code.c_str();
const char* fShaderCode = fragment_code.c_str();
// 2. Compile shaders.
unsigned int vertex, fragment;
// vertex shader.
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// if geometry shader is given, compile geometry shader.
unsigned int geometry;
if (false) {
// const char* gShaderCode = geometry_code.c_str();
// geometry = glCreateShader(GL_GEOMETRY_SHADER);
// glShaderSource(geometry, 1 &gShaderCode, NULL);
// glCompileShader(geometry);
// checkCompileErrors(geometry, "GEOMETRY");
}
// shader Program
id = glCreateProgram();
glAttachShader(id, vertex);
glAttachShader(id, fragment);
if (false)
glAttachShader(id, geometry);
glLinkProgram(id);
checkCompileErrors(id, "PROGRAM");
// delete the shaders as they're linked into our program now and are no longer necessary
glDeleteShader(vertex);
glDeleteShader(fragment);
if (false)
glDeleteShader(geometry);
}
void Shader::checkCompileErrors(GLuint shader, const std::string& type) {
GLint success;
GLchar infoLog[1024];
if (type != "PROGRAM") {
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
OnCompilationErrorMessage.Invoke( std::format("COMPILATION_ERROR: {}", type), infoLog);
}
} else {
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shader, 1024, NULL, infoLog);
OnCompilationErrorMessage.Invoke(std::format("COMPILATION_ERROR: {}", type), infoLog);
}
}
if (success)
std::cout << "Shader compiled successfully" << std::endl;
}
GLint Shader::Uniform(const std::string &name) const {
return glGetUniformLocation(id, name.c_str());
}
GLint Shader::Attribute(const std::string &name) const {
return glGetAttribLocation(id, name.c_str());
}
Shader::Shader(const std::string &vertex_code, const std::string &fragment_code) {
const char* vShaderCode = vertex_code.c_str();
const char* fShaderCode = fragment_code.c_str();
// 2. Compile shaders.
unsigned int vertex, fragment;
// vertex shader.
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// if geometry shader is given, compile geometry shader.
unsigned int geometry;
if (false) {
// const char* gShaderCode = geometry_code.c_str();
// geometry = glCreateShader(GL_GEOMETRY_SHADER);
// glShaderSource(geometry, 1 &gShaderCode, NULL);
// glCompileShader(geometry);
// checkCompileErrors(geometry, "GEOMETRY");
}
// shader Program
id = glCreateProgram();
glAttachShader(id, vertex);
glAttachShader(id, fragment);
if (false)
glAttachShader(id, geometry);
glLinkProgram(id);
checkCompileErrors(id, "PROGRAM");
// delete the shaders as they're linked into our program now and are no longer necessary
glDeleteShader(vertex);
glDeleteShader(fragment);
if (false)
glDeleteShader(geometry);
}
void Shader::Use() {
glUseProgram(id);
}
bool Shader::Loaded() const { return id != 0; }
unsigned int Shader::Handle() const { return id;}
void Shader::UseDefault() {
glUseProgram(0);
}
void Shader::Use(GLuint shader_program_id) {
glUseProgram(shader_program_id);
}
void Shader::SetBool(const std::string &name, bool value) const { glUniform1i(Uniform(name), (int)value); }
void Shader::SetInt(const std::string &name, int value) const { glUniform1i(Uniform(name), value); }
void Shader::SetFloat(const std::string &name, float value) const { glUniform1f(Uniform(name), value); }
void Shader::SetVector2(const std::string &name, const Vector2 &value) const { glUniform2f(Uniform(name), value.x, value.y); }
void Shader::SetVector2(const std::string &name, float x, float y) const { glUniform2f(Uniform(name), x, y); }
void Shader::SetVector3(const std::string &name, const Vector3 &value) const { glUniform3f(Uniform(name), value.x, value.y, value.z); }
void Shader::SetVector3(const std::string &name, float x, float y, float z) const { glUniform3f(Uniform(name), x, y, z); }
void Shader::SetVector4(const std::string &name, const Vector4 &value) const { glUniform4f(Uniform(name), value.x, value.y, value.z, value.w); }
void Shader::SetVector4(const std::string &name, float x, float y, float z, float w) const { glUniform4f(Uniform(name), x, y, z, w); }
void Shader::SetMatrix2x2(const std::string &name, const Matrix2x2 &value) const {
/// TODO: Verify if glsl expects row-major or col-major!!
bool transpose = false;
glUniformMatrix2fv(Uniform(name), 4, transpose, value.ptr());
}
void Shader::SetMatrix3x3(const std::string &name, const Matrix3x3 &value) const {
/// TODO: Verify if glsl expects row-major or col-major!!
bool transpose = false;
glUniformMatrix3fv(Uniform(name), 9, transpose, value.ptr());
}
void Shader::SetMatrix4x4(const std::string &name, const Matrix4x4 &value) const {
/// TODO: Verify if glsl expects row-major or col-major!!
bool transpose = false;
glUniformMatrix4fv(Uniform(name), 16, transpose, value.ptr());
}
}