shader abstracted into it own class

This commit is contained in:
MichaelFisher1997 2025-01-14 22:57:09 +00:00
parent ed0e9d8947
commit 6b0cc46045
6 changed files with 223 additions and 176 deletions

View File

@ -1,6 +1,7 @@
#include "Renderer.h"
#include <GL/glew.h>
#include <iostream>
#include "Renderer.h"
void GLClearError() {

View File

@ -1,9 +1,9 @@
#pragma once
#include "colormod.h"
#include <iostream>
#include <assert.h>
#include <GL/glew.h>
#include "colormod.h"
#if defined(_MSC_VER) // Microsoft Visual C++
#include <intrin.h>
@ -33,5 +33,8 @@
ASSERT(GLLogCall())
#define INT2VOIDP(i) (void*)(uintptr_t)(i)
// Declare global functions
void GLClearError();
bool GLLogCall();

157
src/Shader.cpp Normal file
View File

@ -0,0 +1,157 @@
#include "Shader.h"
#include <cstdio>
#include <iostream>
#include <string>
#include <sstream>
#include "VertexBuffer.h"
#include "VertexArray.h"
#include "IndexBuffer.h"
#include "fstream"
#include "Renderer.h"
Shader::Shader(const std::string& filepath)
: m_FilePath(filepath), m_RendererID(0)
{
ShaderProgramSource source = ParseShader(filepath);
std::cout << "VERTEX" << std::endl << source.VertexSource << std::endl;
std::cout << "FRAGMENT" << std::endl << source.FragmentSource << std::endl;
m_RendererID = CreateShader(source.VertexSource, source.FragmentSource);
GLCall( glUseProgram(m_RendererID) );
}
Shader::~Shader()
{
GLCall( glDeleteProgram(m_RendererID) );
}
void Shader::Bind() const
{
GLCall( glUseProgram(m_RendererID) );
}
void Shader::Unbind() const
{
GLCall( glUseProgram(0) );
}
int Shader::GetUniformLocation(const std::string& name)
{
if (m_UniformLocationCache.find(name) != m_UniformLocationCache.end())
return m_UniformLocationCache[name];
GLCall( int location = glGetUniformLocation(m_RendererID, name.c_str()) );
if (location == -1)
std::cout << "No active uniform variable with name " << name << " found" << std::endl;
m_UniformLocationCache[name] = location;
return location;
}
void Shader::SetUniform1f(const std::string& name, float value)
{
GLCall( glUniform1f(GetUniformLocation(name), value) );
}
void Shader::SetUniform4f(const std::string& name, float f0, float f1, float f2, float f3)
{
GLCall( glUniform4f(GetUniformLocation(name), f0, f1, f2, f3) );
}
enum ShaderType
{
NONE = -1, VERTEX = 0, FRAGMENT = 1
};
struct ShaderProgramSource Shader::ParseShader(const std::string& filepath)
{
std::ifstream stream(filepath);
std::string line;
std::stringstream ss[2];
ShaderType type = NONE;
while (getline(stream, line))
{
if (line.find("#shader") != std::string::npos)
{
if (line.find("vertex") != std::string::npos)
type = VERTEX;
else if (line.find("fragment") != std::string::npos)
type = FRAGMENT;
}
else
{
ss[(int)type] << line << '\n';
}
}
struct ShaderProgramSource sps = { ss[0].str(), ss[1].str() };
return sps;
}
unsigned int Shader::CompileShader(unsigned int type, const std::string& source)
{
GLCall( unsigned int id = glCreateShader(type) );
const char* src = source.c_str();
GLCall( glShaderSource(id, 1, &src, nullptr) );
GLCall( glCompileShader(id) );
// Error handling
int result;
GLCall( glGetShaderiv(id, GL_COMPILE_STATUS, &result) );
std::cout << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << " shader compile status: " << result << std::endl;
if ( result == GL_FALSE )
{
int length;
GLCall( glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length) );
char* message = (char*) alloca(length * sizeof(char));
GLCall( glGetShaderInfoLog(id, length, &length, message) );
std::cout
<< "Failed to compile "
<< (type == GL_VERTEX_SHADER ? "vertex" : "fragment")
<< "shader"
<< std::endl;
std::cout << message << std::endl;
GLCall( glDeleteShader(id) );
return 0;
}
return id;
}
unsigned int Shader::CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
{
// create a shader program
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
GLCall( glAttachShader(program, vs) );
GLCall( glAttachShader(program, fs) );
GLCall( glLinkProgram(program) );
GLint program_linked;
GLCall( glGetProgramiv(program, GL_LINK_STATUS, &program_linked) );
std::cout << "Program link status: " << program_linked << std::endl;
if (program_linked != GL_TRUE)
{
GLsizei log_length = 0;
GLchar message[1024];
GLCall( glGetProgramInfoLog(program, 1024, &log_length, message) );
std::cout << "Failed to link program" << std::endl;
std::cout << message << std::endl;
}
GLCall( glValidateProgram(program) );
GLCall( glDeleteShader(vs) );
GLCall( glDeleteShader(fs) );
return program;
}

36
src/Shader.h Normal file
View File

@ -0,0 +1,36 @@
#pragma once
#include <string>
#include <unordered_map>
struct ShaderProgramSource
{
std::string VertexSource;
std::string FragmentSource;
};
class Shader
{
private:
unsigned int m_RendererID;
std::string m_FilePath;
std::unordered_map<std::string, int> m_UniformLocationCache;
public:
Shader(const std::string& filepath);
~Shader();
void Bind() const;
void Unbind() const;
// Set uniforms
void SetUniform4f(const std::string& name, float f0, float f1, float f2, float f3);
void SetUniform1f(const std::string& name, float value);
private:
int GetUniformLocation(const std::string& name);
struct ShaderProgramSource ParseShader(const std::string& filepath);
unsigned int CompileShader(unsigned int type, const std::string& source);
unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader);
};

View File

@ -1,54 +1,19 @@
#include <GL/glew.h> // Include GLEW before <SDL2/SDL.h>?
#include "sdl.hpp"
#include "VertexBufferLayout.h"
#include "colormod.h"
#include <SDL2/SDL_video.h>
#include <alloca.h>
#include <cstdio>
#include <iostream>
#include <string>
#include <fstream>
//#include <iterator>
#include <ostream>
#include <string>
#include <sstream>
#include "Renderer.h"
#include "VertexBuffer.h"
#include "VertexArray.h"
#include "IndexBuffer.h"
#if defined(_MSC_VER) // Microsoft Visual C++
#include <intrin.h>
#define DEBUG_BREAK() __debugbreak()
#elif defined(__i386__) || defined(__x86_64__)
// Use inline assembly for x86/x86_64
#define DEBUG_BREAK() __asm__ volatile("int3")
#else
// Fallback on non-x86 platforms
#include <signal.h>
#define DEBUG_BREAK() raise(SIGTRAP)
#endif
// ASSERT macro that shows file, line, and the failed expression
#define ASSERT(x) \
do { \
if (!(x)) { \
std::cerr << "Assertion Failed: " << #x << '\n' \
<< "File: " << __FILE__ << '\n' \
<< "Line: " << __LINE__ << std::endl; \
DEBUG_BREAK(); \
} \
} while (false)
#define GLCall(x) GLClearError();\
x;\
ASSERT(GLLogCall())
struct ShaderProgramSource {
std::string VertexSource, FragmentSource;
};
#include "Shader.h"
SdlWindow::SdlWindow(const char* title, int width, int height)
: m_window(nullptr),
@ -62,7 +27,7 @@ SdlWindow::SdlWindow(const char* title, int width, int height)
r(0.5f),
m_glContext(nullptr),
increment(0.05f),
m_shader(0),
m_Shader(nullptr),
m_Location(-1),
m_IB(nullptr),
m_VB(nullptr),
@ -146,26 +111,10 @@ SdlWindow::SdlWindow(const char* title, int width, int height)
m_VA->AddBuffer(*m_VB, layout);
ShaderProgramSource source = parseShader("res/shaders/Basic.shader");
std::cout << "VERTEX" << std::endl << source.VertexSource << std::endl;
std::cout << "FRAGMENT" << std::endl << source.FragmentSource << std::endl;
m_Shader = new Shader("res/shaders/Basic.shader");
m_Shader->Bind();
unsigned int shader = createShader(source.VertexSource, source.FragmentSource);
m_shader = shader;
std::cout << "shader: " << m_shader << std::endl;
std::cout << "shader: " << m_shader << std::endl;
GLCall(glUseProgram(m_shader));
GLCall(m_Location = glGetUniformLocation(m_shader, "u_Color"));
ASSERT(m_Location != -1); // -1 is an error
GLCall(glUniform4f(m_Location, 0.8f, 0.3f, 0.8f, 1.0f));
GLCall(glBindVertexArray(0));
GLCall(glUseProgram(0));
GLCall(glBindBuffer(GL_ARRAY_BUFFER, 0));
GLCall(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
}
@ -186,11 +135,8 @@ SdlWindow::~SdlWindow() {
SDL_DestroyWindow(m_window);
m_window = nullptr;
}
if (m_shader) {
glDeleteProgram(m_shader);
m_shader = 0;
}
////TODO
//some point check everything is being deleted
SDL_Quit();
}
//
@ -201,7 +147,6 @@ void SdlWindow::run() {
update();
render();
}
GLCall(glDeleteProgram(m_shader));
}
//
void SdlWindow::processEvents() {
@ -266,11 +211,8 @@ void SdlWindow::render() {
//
GLCall(glClear(GL_COLOR_BUFFER_BIT));
GLCall(glUseProgram(m_shader));
std::cout << "m_shader: " << m_shader << std::endl;
std::cout << "location: " << m_Location << std::endl;
std::cout << "R: " << r << std::endl;
GLCall(glUniform4f(m_Location, r, 0.3f, 0.8f, 1.0f));
m_Shader->Bind();
m_Shader->SetUniform4f("u_Color", r, 0.3, 0.8, 1.0);
m_VA->Bind();
m_IB->Bind();
@ -304,94 +246,3 @@ void SdlWindow::setFullscreen(bool fullscreen) {
}
}
}
//
unsigned int SdlWindow::compileShader(unsigned int type, const std::string& source) {
GLCall(unsigned int id = glCreateShader(type));
const char* src = source.c_str(); // <--- this string needs to exist when compiling/running
GLCall(glShaderSource(id, 1, &src, nullptr));
GLCall(glCompileShader(id));
//TODO: error handling
int result;
GLCall(glGetShaderiv(id, GL_COMPILE_STATUS, &result));
if (result == GL_FALSE) {
int length;
GLCall(glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length));
char* message = (char*)alloca(length * sizeof(char)); //do i need to deallocate this??
GLCall(glGetShaderInfoLog(id, length, &length, message));
std::cout << "Failed to compile " << (type == GL_VERTEX_SHADER ? "vertex":"fragment") << " shader" << std::endl; // print out what type of shader it is
std::cout << message << std::endl;
GLCall(glDeleteShader(id));
return 0;
}
//
return id;
}
unsigned int SdlWindow::createShader(const std::string& vertexShader, const std::string& fragmentShader) {
GLCall(unsigned int program = glCreateProgram());
unsigned int vs = compileShader(GL_VERTEX_SHADER, vertexShader);
unsigned int fs = compileShader(GL_FRAGMENT_SHADER, fragmentShader);
GLCall(glAttachShader(program, vs));
GLCall(glAttachShader(program, fs));
GLCall(glLinkProgram(program));
GLCall(glValidateProgram(program));
GLCall(glDeleteShader(vs));
GLCall(glDeleteShader(fs));
return program;
}
SdlWindow::ShaderProgramSource SdlWindow::parseShader(const std::string& filepath) {
//can be changed to c standard which is a bit faster
std::ifstream stream(filepath);
if (!stream.is_open()) {
std::cerr << "parseShader ERROR: Could not open file " << filepath << std::endl;
// Return empty (or handle however you prefer)
return {"", ""};
}
enum class ShaderType {
NONE = -1, VERTEX = 0, FRAGMENT = 1
};
std::string line;
std::stringstream ss[2]; //vertex - fragment
ShaderType type = ShaderType::NONE;
while (getline(stream, line)) {
if (line.find("#shader") != std::string::npos) {
if (line.find("vertex") != std::string::npos) {
type = ShaderType::VERTEX;
}
else if (line.find("fragment") != std::string::npos) {
type = ShaderType::FRAGMENT;
}
}
else {
ss[(int)type] << line << '\n';
}
}
return {ss[0].str(), ss[1].str() };
}
void SdlWindow::GLClearError() {
while (glGetError() != GL_NO_ERROR);
}
bool SdlWindow::GLLogCall() {
Color::Modifier red(Color::FG_RED);
Color::Modifier def(Color::FG_DEFAULT);
while (GLenum error = glGetError()) {
std::cout << red << "[OpenGL Error] (" << error << ")" << def << std::endl; //if error, it will return a number, this needs to be converted to hex to then look up that value inn GL docs
return false;
}
return true;
}

View File

@ -13,6 +13,7 @@
#include "IndexBuffer.h"
#include "VertexBufferLayout.h"
#include "VertexArray.h"
#include "Shader.h"
// Forward declaration of classes and structs if needed
// class SomethingElse;
@ -27,20 +28,18 @@ public:
// Run the main loop
void run();
unsigned int compileShader(unsigned int type, const std::string& source);
unsigned int createShader(const std::string& vetexShader, const std::string& fragmentShader);
// for spliting our shaders
// unsigned int compileShader(unsigned int type, const std::string& source);
// unsigned int createShader(const std::string& vetexShader, const std::string& fragmentShader);
// // for spliting our shaders
// //struct ShaderProgramSource {
// // std::string VetexSource, FragmentSource;
// struct ShaderProgramSource {
// std::string VetexSource, FragmentSource;
struct ShaderProgramSource {
std::string VertexSource;
std::string FragmentSource;
};
ShaderProgramSource parseShader(const std::string& filepath);
// std::string VertexSource;
// std::string FragmentSource;
// };
// ShaderProgramSource parseShader(const std::string& filepath);
void setFullscreen(bool fullscreen);
void GLClearError();
bool GLLogCall();
private:
@ -57,11 +56,11 @@ private:
SDL_GLContext m_glContext;
float increment;
// // temp shader stuff
unsigned int m_shader;
GLint m_Location;
VertexArray* m_VA;
IndexBuffer* m_IB;
VertexBuffer* m_VB;
Shader* m_Shader;
// Private methods
void processEvents();