feat(render) Render shaders!

Implements the rendering pipeline to dispaly a 2D triangle using
shaders!
This commit is contained in:
Ritchie Cunningham 2025-09-12 21:49:15 +01:00
parent 7eb86f9389
commit 6b7684ba92
6 changed files with 184 additions and 6 deletions

View File

@ -0,0 +1,7 @@
#version 330 core
out vec4 FragColor;
void main() {
FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); /* Orange??!? */
}

View File

@ -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);
}

View File

@ -1,10 +1,10 @@
#include <GL/glew.h>
#include <SDL3/SDL_error.h>
/* FINE LSP!! I'll play your games!!!! */
#include <SDL3/SDL_events.h> /* ~HJAPPY?!?!?! */
#include <SDL3/SDL_stdinc.h>
#include <SDL3/SDL_timer.h>
#include <SDL3/SDL_video.h>
#include <chrono>
#include <cstddef>
#include <cstdio>
#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);
}

View File

@ -2,6 +2,8 @@
#include <SDL3/SDL.h>
#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;
};

96
src/graphics/shader.cpp Normal file
View File

@ -0,0 +1,96 @@
#include <GL/glew.h>
#include <cstdio>
#include <fstream>
#include <sstream>
#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();
}

18
src/graphics/shader.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include <string>
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;
};