From 6b7684ba9241d4cf3eb8fb5dfbb9454dfe5e8389 Mon Sep 17 00:00:00 2001 From: Ritchie Cunningham Date: Fri, 12 Sep 2025 21:49:15 +0100 Subject: [PATCH] feat(render) Render shaders! Implements the rendering pipeline to dispaly a 2D triangle using shaders! --- assets/shaders/simple.frag | 7 +++ assets/shaders/simple.vert | 7 +++ src/bettola.cpp | 55 +++++++++++++++++++--- src/bettola.h | 7 +++ src/graphics/shader.cpp | 96 ++++++++++++++++++++++++++++++++++++++ src/graphics/shader.h | 18 +++++++ 6 files changed, 184 insertions(+), 6 deletions(-) create mode 100644 assets/shaders/simple.frag create mode 100644 assets/shaders/simple.vert create mode 100644 src/graphics/shader.cpp create mode 100644 src/graphics/shader.h diff --git a/assets/shaders/simple.frag b/assets/shaders/simple.frag new file mode 100644 index 0000000..e1c3b40 --- /dev/null +++ b/assets/shaders/simple.frag @@ -0,0 +1,7 @@ +#version 330 core + +out vec4 FragColor; + +void main() { + FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); /* Orange??!? */ +} diff --git a/assets/shaders/simple.vert b/assets/shaders/simple.vert new file mode 100644 index 0000000..7f80b12 --- /dev/null +++ b/assets/shaders/simple.vert @@ -0,0 +1,7 @@ +#version 330 core + +layout (location = 0) in vec3 aPos; + +void main() { + gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); +} diff --git a/src/bettola.cpp b/src/bettola.cpp index 7d02714..6812fb0 100644 --- a/src/bettola.cpp +++ b/src/bettola.cpp @@ -1,10 +1,10 @@ #include #include +/* FINE LSP!! I'll play your games!!!! */ +#include /* ~HJAPPY?!?!?! */ #include #include #include -#include -#include #include #include "bettola.h" @@ -16,7 +16,9 @@ const int SCREEN_HEIGHT = 600; Bettola::Bettola(void) : _is_running(false), _window(nullptr), - _gl_context(nullptr) {} + _gl_context(nullptr), + _vao(0), + _vbo(0) {} Bettola::~Bettola(void) { if(_gl_context) { @@ -28,6 +30,9 @@ Bettola::~Bettola(void) { } SDL_Quit(); + + glDeleteVertexArrays(1, &_vao); + glDeleteBuffers(1, &_vbo); } int Bettola::run(void) { @@ -36,6 +41,13 @@ int Bettola::run(void) { if(!create_gl_context()) return -1; if(!init_glew()) return -1; + if(!_shader.load_from_files("assets/shaders/simple.vert", + "assets/shaders/simple.frag")) { + return -1; + } + + setup_triangle(); + glViewport(0,0,SCREEN_WIDTH, SCREEN_HEIGHT); _is_running = true; @@ -81,6 +93,12 @@ void Bettola::update(double dt) { void Bettola::render(void) { glClearColor(0.1f, 0.1f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); + + _shader.use(); + glBindVertexArray(_vao); + glDrawArrays(GL_TRIANGLES, 0, 3); + glBindVertexArray(0); + SDL_GL_SwapWindow(_window); } @@ -107,11 +125,13 @@ bool Bettola::create_window(void) { SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + /* Don't you dare f.ckin fail to open!!!!! */ + _window = SDL_CreateWindow("Bettola Makes No Sense!", SCREEN_WIDTH, SCREEN_HEIGHT, + SDL_WINDOW_OPENGL); + if(!_window) { - /* Don't you dare f.ckin fail to open!!!!! */ - _window = SDL_CreateWindow("Bettola Makes No Sense!", SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_OPENGL); fprintf(stderr, "Failed to create window! SDL_ERROR: %s\n", SDL_GetError()); + return false; } return true; @@ -126,3 +146,26 @@ bool Bettola::create_gl_context(void) { return true; } +void Bettola::setup_triangle(void) { + float vertices[] = { + /* Should be a triangle??!?? */ + -0.5f, -0.5f, 0.0f, + 0.5f, -0.5f, 0.0f, + 0.0f, 0.5f, 0.0f, + }; + + glGenVertexArrays(1, &_vao); + glGenBuffers(1, &_vbo); + + glBindVertexArray(_vao); + + glBindBuffer(GL_ARRAY_BUFFER, _vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); +} + diff --git a/src/bettola.h b/src/bettola.h index 05b6068..3bfb9c7 100644 --- a/src/bettola.h +++ b/src/bettola.h @@ -2,6 +2,8 @@ #include +#include "graphics/shader.h" + class Bettola { public: Bettola(void); @@ -18,9 +20,14 @@ private: bool init_glew(void); bool create_window(void); bool create_gl_context(void); + void setup_triangle(void); bool _is_running; SDL_Window* _window; SDL_GLContext _gl_context; + + Shader _shader; + unsigned int _vao; + unsigned int _vbo; }; diff --git a/src/graphics/shader.cpp b/src/graphics/shader.cpp new file mode 100644 index 0000000..fc1bf6f --- /dev/null +++ b/src/graphics/shader.cpp @@ -0,0 +1,96 @@ +#include +#include +#include +#include + +#include "shader.h" + +Shader::Shader(void) : _program_id(0) {} + +Shader::~Shader(void) { + if(_program_id != 0) { + glDeleteProgram(_program_id); + } +} + +bool Shader::load_from_files(const std::string& vert_path, const std::string& frag_path) { + std::string vert_source = read_file(vert_path); + if(vert_source.empty()) { + fprintf(stderr, "Failed to read vertex shader file: %s\n", vert_path.c_str()); + return false; + } + + std::string frag_source = read_file(frag_path); + if(frag_source.empty()) { + fprintf(stderr, "Failed to read fragment shader file: %s\n", frag_path.c_str()); + return false; + } + + unsigned int vert_shader_id; + if(!compile_shader(vert_shader_id, vert_source.c_str(), GL_VERTEX_SHADER)) { + return false; + } + + unsigned int frag_shader_id; + if(!compile_shader(frag_shader_id, frag_source.c_str(), GL_FRAGMENT_SHADER)) { + glDeleteShader(vert_shader_id); + return false; + } + + _program_id = glCreateProgram(); + glAttachShader(_program_id, vert_shader_id); + glAttachShader(_program_id, frag_shader_id); + glLinkProgram(_program_id); + + int success; + char info_log[512]; + glGetProgramiv(_program_id, GL_LINK_STATUS, &success); + if(!success) { + glGetProgramInfoLog(_program_id, 512, NULL, info_log); + fprintf(stderr, "ERROR::SHADER::PROGRAM::LINKING_FAILED\n%s\n", info_log); + glDeleteShader(vert_shader_id); + glDeleteShader(frag_shader_id); + return false; + } + + glDetachShader(_program_id, vert_shader_id); + glDetachShader(_program_id, frag_shader_id); + glDeleteShader(vert_shader_id); + glDeleteShader(frag_shader_id); + + return true; +} + +void Shader::use(void) { + if(_program_id != 0) { + glUseProgram(_program_id); + } +} + +bool Shader::compile_shader(unsigned int& shader_id, const char* shader_source, int shader_type) { + shader_id = glCreateShader(shader_type); + glShaderSource(shader_id, 1, &shader_source, NULL); + glCompileShader(shader_id); + + int success; + char info_log[512]; + glGetShaderiv(shader_id, GL_COMPILE_STATUS, &success); + + if(!success) { + glGetShaderInfoLog(shader_id, 512, NULL, info_log); + fprintf(stderr, "ERROR::SHADER::COMPILATION\n%s\n", info_log); + return false; + } + + return true; +} + +std::string Shader::read_file(const std::string& path) { + std::ifstream file(path); + if(!file.is_open()) { + return ""; + } + std::stringstream buffer; + buffer << file.rdbuf(); + return buffer.str(); +} diff --git a/src/graphics/shader.h b/src/graphics/shader.h new file mode 100644 index 0000000..d3a0bc7 --- /dev/null +++ b/src/graphics/shader.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +class Shader { +public: + Shader(void); + ~Shader(void); + + bool load_from_files(const std::string& vert_path, const std::string& frag_path); + void use(void); + unsigned int get_id(void) const { return _program_id; } +private: + bool compile_shader(unsigned int& shader_id, const char* shader_source, int shader_type); + + std::string read_file(const std::string& path); + unsigned int _program_id; +};