summaryrefslogtreecommitdiff
path: root/util/ogl_renderer/c++
diff options
context:
space:
mode:
authorClaudius "keldu" Holeksa <mail@keldu.de>2026-01-10 23:20:05 +0100
committerClaudius "keldu" Holeksa <mail@keldu.de>2026-01-10 23:20:05 +0100
commit1563ca95b44ea3e0f7384bc3109f366ed761668f (patch)
treea721eafa2955737a467b6bff7df78569d7f29a4c /util/ogl_renderer/c++
parent393e58b20ece6c9d24af432299dfab6be2402ba8 (diff)
downloadlibs-lbm-1563ca95b44ea3e0f7384bc3109f366ed761668f.tar.gz
Minor renderer for particles
Diffstat (limited to 'util/ogl_renderer/c++')
-rw-r--r--util/ogl_renderer/c++/SConscript26
-rw-r--r--util/ogl_renderer/c++/common.hpp13
-rw-r--r--util/ogl_renderer/c++/lbm_ogl_renderer.cpp60
-rw-r--r--util/ogl_renderer/c++/program.hpp65
-rw-r--r--util/ogl_renderer/c++/shader.hpp8
-rw-r--r--util/ogl_renderer/c++/shaders/basic.hpp36
-rw-r--r--util/ogl_renderer/c++/state.hpp144
7 files changed, 352 insertions, 0 deletions
diff --git a/util/ogl_renderer/c++/SConscript b/util/ogl_renderer/c++/SConscript
new file mode 100644
index 0000000..96d33fb
--- /dev/null
+++ b/util/ogl_renderer/c++/SConscript
@@ -0,0 +1,26 @@
+#!/bin/false
+
+import os
+import os.path
+import glob
+
+
+Import('env')
+
+dir_path = Dir('.').abspath
+
+# Environment for base library
+core_env = env.Clone();
+
+core_env.sources = sorted(glob.glob(dir_path + "/*.cpp"));
+core_env.headers = sorted(glob.glob(dir_path + "/*.hpp"));
+
+env.sources += core_env.sources;
+env.headers += core_env.headers;
+
+## Static lib
+objects = []
+core_env.add_source_files(objects, core_env.sources, shared=False);
+env.lbm_ogl_renderer = core_env.Program('#build/kel_lbm_ogl_renderer', [objects]);
+
+env.Install('$prefix/bin/', env.lbm_ogl_renderer);
diff --git a/util/ogl_renderer/c++/common.hpp b/util/ogl_renderer/c++/common.hpp
new file mode 100644
index 0000000..8f425e9
--- /dev/null
+++ b/util/ogl_renderer/c++/common.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <glad/gl.h>
+#include <SDL3/SDL.h>
+#include <SDL3/SDL_opengl.h>
+
+namespace kel {
+namespace lbm {
+namespace sch {
+using namespace saw::schema;
+}
+}
+}
diff --git a/util/ogl_renderer/c++/lbm_ogl_renderer.cpp b/util/ogl_renderer/c++/lbm_ogl_renderer.cpp
new file mode 100644
index 0000000..b8b687d
--- /dev/null
+++ b/util/ogl_renderer/c++/lbm_ogl_renderer.cpp
@@ -0,0 +1,60 @@
+#include <kel/lbm/lbm.hpp>
+
+#include "state.hpp"
+
+namespace kel {
+namespace lbm {
+namespace sch {
+using namespace saw::schema;
+}
+
+}
+
+saw::error_or<void> lbm_main(int argc, char** argv){
+ auto eo_state = lbm::create_ogl_renderer();
+ if(eo_state.is_error()){
+ return std::move(eo_state.get_error());
+ }
+ auto& state = *(eo_state.get_value());
+
+ bool running{true};
+ while(running){
+ state.clear();
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
+ SDL_GL_SwapWindow(state.window);
+
+ SDL_Event event;
+ while(SDL_PollEvent(&event)){
+ switch(event.type){
+ case SDL_EVENT_QUIT:
+ running = false;
+ break;
+ case SDL_EVENT_KEY_UP:
+ if(event.key.key== SDLK_ESCAPE){
+ running = false;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ return saw::make_void();
+}
+}
+
+int main(int argc, char** argv){
+ auto eov = kel::lbm_main(argc, argv);
+ if(eov.is_error()){
+ auto& err = eov.get_error();
+ std::cerr<<"[Error] "<<err.get_category();
+ auto err_msg = err.get_message();
+ if(err_msg.size() > 0u){
+ std::cerr<<" - "<<err_msg;
+ }
+ std::cerr<<std::endl;
+ return err.get_id();
+ }
+ return 0;
+}
diff --git a/util/ogl_renderer/c++/program.hpp b/util/ogl_renderer/c++/program.hpp
new file mode 100644
index 0000000..acf3016
--- /dev/null
+++ b/util/ogl_renderer/c++/program.hpp
@@ -0,0 +1,65 @@
+#pragma once
+
+#include "common.hpp"
+
+namespace kel {
+namespace lbm {
+GLuint create_ogl_program(const char * vertex_data,const char * fragment_data){
+ // Create the shaders
+ GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
+ GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
+
+ GLint Result = GL_FALSE;
+ int InfoLogLength;
+
+ // Compile Vertex Shader
+ glShaderSource(VertexShaderID, 1, &vertex_data, NULL);
+ glCompileShader(VertexShaderID);
+
+ // Check Vertex Shader
+ glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
+ glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
+ if ( InfoLogLength > 0 ){
+ std::vector<char> VertexShaderErrorMessage(InfoLogLength+1);
+ glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
+ printf("%s\n", &VertexShaderErrorMessage[0]);
+ }
+
+ // Compile Fragment Shader
+ glShaderSource(FragmentShaderID, 1, &fragment_data , NULL);
+ glCompileShader(FragmentShaderID);
+
+ // Check Fragment Shader
+ glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
+ glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
+ if ( InfoLogLength > 0 ){
+ std::vector<char> FragmentShaderErrorMessage(InfoLogLength+1);
+ glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
+ printf("%s\n", &FragmentShaderErrorMessage[0]);
+ }
+
+ // Link the program
+ GLuint ProgramID = glCreateProgram();
+ glAttachShader(ProgramID, VertexShaderID);
+ glAttachShader(ProgramID, FragmentShaderID);
+ glLinkProgram(ProgramID);
+
+ // Check the program
+ glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
+ glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
+ if ( InfoLogLength > 0 ){
+ std::vector<char> ProgramErrorMessage(InfoLogLength+1);
+ glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
+ printf("%s\n", &ProgramErrorMessage[0]);
+ }
+
+ glDetachShader(ProgramID, VertexShaderID);
+ glDetachShader(ProgramID, FragmentShaderID);
+
+ glDeleteShader(VertexShaderID);
+ glDeleteShader(FragmentShaderID);
+
+ return ProgramID;
+}
+}
+}
diff --git a/util/ogl_renderer/c++/shader.hpp b/util/ogl_renderer/c++/shader.hpp
new file mode 100644
index 0000000..6e84f21
--- /dev/null
+++ b/util/ogl_renderer/c++/shader.hpp
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "common.hpp"
+
+namespace kel {
+namespace lbm {
+}
+}
diff --git a/util/ogl_renderer/c++/shaders/basic.hpp b/util/ogl_renderer/c++/shaders/basic.hpp
new file mode 100644
index 0000000..2b0a65f
--- /dev/null
+++ b/util/ogl_renderer/c++/shaders/basic.hpp
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <string_view>
+
+namespace kel {
+namespace lbm {
+constexpr std::string_view shader_basic_vertex = R"(
+#version 330 core
+
+layout(location=0) in vec2 vertices;
+layout(location=1) in vec2 v_uv;
+
+out vec2 uv;
+
+void main(){
+ uv = v_uv;
+ gl_Position = vec4(vertices, 0.0, 1.0);
+}
+)";
+
+constexpr std::string_view shader_basic_fragment = R"(
+#version 330 core
+
+in vec2 uv;
+out vec4 color;
+
+uniform sampler2D tex_sampler;
+
+void main(){
+ color = texture(tex_sampler, uv);
+ color.r = 0.8;
+}
+)";
+
+}
+}
diff --git a/util/ogl_renderer/c++/state.hpp b/util/ogl_renderer/c++/state.hpp
new file mode 100644
index 0000000..c429195
--- /dev/null
+++ b/util/ogl_renderer/c++/state.hpp
@@ -0,0 +1,144 @@
+#pragma once
+
+#include "common.hpp"
+#include "program.hpp"
+
+#include "shaders/basic.hpp"
+
+namespace kel {
+namespace lbm {
+namespace sch {
+using namespace saw::schema;
+}
+
+struct ogl_state final {
+public:
+ SDL_Window* window;
+ SDL_GLContext context;
+ int version;
+ GLuint vao_id;
+ GLuint vbo_id;
+ GLuint veo_id;
+
+ GLuint program_id;
+ GLuint fbo_id;
+ GLuint tex_id;
+
+ uint64_t w, h;
+
+public:
+ ogl_state():
+ window{nullptr},
+ version{0},
+ vao_id{0u},
+ vbo_id{0u},
+ program_id{0u},
+ fbo_id{0u},
+ tex_id{0u},
+ w{1024},
+ h{1024}
+ {
+ SDL_Init(SDL_INIT_VIDEO);
+ }
+
+ ~ogl_state(){
+ SDL_GL_DestroyContext(context);
+ if(window){
+ SDL_DestroyWindow(window);
+ window = nullptr;
+ }
+ SDL_Quit();
+ }
+
+ void clear(){
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+};
+
+saw::error_or<saw::own<ogl_state>> create_ogl_renderer(){
+ auto owned_state = saw::heap<ogl_state>();
+
+ auto& st = *owned_state;
+
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION,3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION,3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+
+ st.window = SDL_CreateWindow("Kel'LBM Renderer",st.w,st.h,SDL_WINDOW_OPENGL /*| SDL_WINDOW_HIDDEN*/);
+ if(not st.window){
+ return saw::make_error<saw::err::critical>("Window not created");
+ }
+ st.context = SDL_GL_CreateContext(st.window);
+
+ st.version = gladLoadGL((GLADloadfunc)SDL_GL_GetProcAddress);
+ glGenVertexArrays(1,&st.vao_id);
+ glBindVertexArray(st.vao_id);
+ glClearColor(0.0,0.0,0.0,1.0);
+
+ glGenBuffers(1,&st.vbo_id);
+ glGenBuffers(1,&st.veo_id);
+ static constexpr GLfloat vertex_buffer_data[] = {
+ -1.f, -1.f, 0.f, 0.f,
+ 1.f, -1.f, 1.f, 0.f,
+ 1.f, 1.f, 1.f, 1.f,
+ -1.f, 1.f, 0.f, 1.f
+ };
+ static unsigned int index_buffer_data[] = {
+ 0, 1, 2,
+ 2, 3, 0
+ };
+ glBindBuffer(GL_ARRAY_BUFFER, st.vbo_id);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_buffer_data), vertex_buffer_data, GL_STATIC_DRAW);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, st.veo_id);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(index_buffer_data), index_buffer_data, GL_STATIC_DRAW);
+
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
+ glEnableVertexAttribArray(0);
+
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));
+ glEnableVertexAttribArray(1);
+
+ glGenFramebuffers(1,&st.fbo_id);
+ //glBindFramebuffer(GL_FRAMEBUFFER, st.fbo_id);
+
+ glGenTextures(1,&st.tex_id);
+ glBindTexture(GL_TEXTURE_2D,st.tex_id);
+
+ glTexImage2D(
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 1024,
+ 1024,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ NULL
+ );
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glFramebufferTexture2D(
+ GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ st.tex_id,
+ 0
+ );
+
+ glViewport(0,0,1024,1024);
+ st.program_id = create_ogl_program(shader_basic_vertex.data(), shader_basic_fragment.data());
+ glUseProgram(st.program_id);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, st.tex_id);
+
+ glUniform1i(glGetUniformLocation(st.program_id, "tex_sampler"), 0);
+ st.clear();
+
+ return owned_state;
+}
+}
+}