From 35d6299688d32d2ed79a044c37499e843232207d Mon Sep 17 00:00:00 2001 From: DaniTheSkunk <> Date: Thu, 12 Jan 2023 05:10:47 +0000 Subject: [PATCH] added framebuffer; also opengl debugging --- gfx.png | Bin 20478 -> 20478 bytes include/framebuffer.h | 20 +++++++ include/scaler.h | 8 +++ include/window.h | 5 ++ meson.build | 1 + src/framebuffer.c | 134 ++++++++++++++++++++++++++++++++++++++++++ src/gsa.c | 15 +++-- src/shader.c | 12 ++++ src/window.c | 53 +++++++++++++++-- 9 files changed, 240 insertions(+), 8 deletions(-) create mode 100644 include/framebuffer.h create mode 100644 include/scaler.h create mode 100644 src/framebuffer.c diff --git a/gfx.png b/gfx.png index b9465fd00f458bc0c58ac0f5688d5221b64931cf..c4c6ba5b5e593b40ca2a48edff7630f320e36a52 100644 GIT binary patch delta 33 pcmex2pYh*(#tCN3n-ml_2Hs(sm>@A(mzk60^?7-l%~s4ud;sXA48{Ne delta 32 qcmV+*0N?-qp8@`#0gyHV|NpT;>;jQs36m`Y2?Uar!V|MP1H?@DrVXh8 diff --git a/include/framebuffer.h b/include/framebuffer.h new file mode 100644 index 0000000..9f10a49 --- /dev/null +++ b/include/framebuffer.h @@ -0,0 +1,20 @@ +#ifndef GUARD_4770FE04EA612B028DF68960A453BD0B +#define GUARD_4770FE04EA612B028DF68960A453BD0B + +#include "types.h" +#include "vec2i.h" + +struct sw_framebuffer { + struct sw_vec2i size; + u32 _fb, _fbtex, _fbdepth; +}; + +struct sw_framebuffer *sw_framebuffer_create(struct sw_vec2i size); +void sw_framebuffer_destroy(struct sw_framebuffer *fb); + +void sw_framebuffer_static_init(); + +void sw_framebuffer_copy_to_screen(struct sw_framebuffer *fb); +void sw_framebuffer_resize(struct sw_framebuffer *fb, struct sw_vec2i new_size); + +#endif /* GUARD_4770FE04EA612B028DF68960A453BD0B */ diff --git a/include/scaler.h b/include/scaler.h new file mode 100644 index 0000000..c481798 --- /dev/null +++ b/include/scaler.h @@ -0,0 +1,8 @@ +#ifndef GUARD_D3B2B8EAB7F3D9A513B3C06FAAF6357E +#define GUARD_D3B2B8EAB7F3D9A513B3C06FAAF6357E + +#define SW_SCALE_STRETCH 0 +#define SW_SCALE_ASPECT 1 +#define SW_SCALE_INTEGER 2 + +#endif /* GUARD_D3B2B8EAB7F3D9A513B3C06FAAF6357E */ diff --git a/include/window.h b/include/window.h index 33f5532..349132d 100644 --- a/include/window.h +++ b/include/window.h @@ -1,14 +1,19 @@ #ifndef GUARD_F247452E0BF1EC9CD9131C2A6FD281CA #define GUARD_F247452E0BF1EC9CD9131C2A6FD281CA +#include "framebuffer.h" +#include "types.h" #include "vec2i.h" struct GLFWwindow; struct sw_window { struct sw_vec2i size; + struct sw_vec2i real_size; + i32 scaler; struct GLFWwindow *_window; + struct sw_framebuffer *_scaler_fb; }; struct sw_window *sw_window_create(struct sw_vec2i size, char *title); diff --git a/meson.build b/meson.build index 7ff324f..5061726 100644 --- a/meson.build +++ b/meson.build @@ -43,6 +43,7 @@ skunk_sources = [ 'src/color32.c', 'src/error.c', 'src/file.c', + 'src/framebuffer.c', 'src/gsa.c', 'src/image32.c', 'src/image8.c', diff --git a/src/framebuffer.c b/src/framebuffer.c new file mode 100644 index 0000000..ddcb6b7 --- /dev/null +++ b/src/framebuffer.c @@ -0,0 +1,134 @@ +#include "framebuffer.h" +#include "error.h" +#include "gl.h" +#include "shader.h" +#include + +static struct sw_shaderprogram program_copy; + +static char *vert_copy = "#version 300 es\n\ +precision highp float;\ +in vec2 pos;\ +out vec2 out_tex_coord;\ +void main() {\ + gl_Position = vec4(pos, 0.0f, 1.0f);\ + out_tex_coord = vec2(pos.x * 0.5 + 0.5, pos.y * 0.5 + 0.5);\ +}"; + +static char *frag_copy = "#version 300 es\n\ +precision highp float;\ +in vec2 out_tex_coord;\ +uniform sampler2D tex;\ +out vec4 color;\ +void main() {\ + vec4 col = texture(tex, out_tex_coord);\ +if(col.a > 0.0) {\ + color = col;\ +}\ +}"; + +static f32 screen_rect[12] = { + -1.f, -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f}; +static u32 vao, vbo; + +struct sw_framebuffer *sw_framebuffer_create(struct sw_vec2i size) { + struct sw_framebuffer *fb; + + sw_log("init framebuffer"); + fb = malloc(sizeof(struct sw_framebuffer)); + glGenFramebuffers(1, &fb->_fb); + glGenTextures(1, &fb->_fbtex); + glGenTextures(1, &fb->_fbdepth); + sw_framebuffer_resize(fb, size); + + return fb; +} + +void sw_framebuffer_destroy(struct sw_framebuffer *fb) { + glDeleteTextures(1, &fb->_fbtex); + glDeleteFramebuffers(1, &fb->_fb); +} + +void sw_framebuffer_static_init() { + sw_log("init static framebuffer"); + + program_copy = sw_shaderprogram_create(vert_copy, frag_copy); + + sw_log("init static framebuffer vao"); + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + sw_log("init static framebuffer vbo"); + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData( + GL_ARRAY_BUFFER, sizeof(f32) * 12, screen_rect, GL_STATIC_DRAW + ); + glGetAttribLocation(program_copy._program, "pos"); + glVertexAttribPointer( + glGetAttribLocation(program_copy._program, "pos"), + 2, + GL_FLOAT, + GL_FALSE, + 0, + 0 + ); + + glEnableVertexAttribArray(glGetAttribLocation(program_copy._program, "pos") + ); + + glBindVertexArray(0); + sw_log("init static framebuffer done"); +} + +void sw_framebuffer_copy_to_screen(struct sw_framebuffer *fb) { + glBindVertexArray(vao); + sw_shaderprogram_use(program_copy); + glBindTexture(GL_TEXTURE_2D, fb->_fbtex); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glDrawArrays(GL_TRIANGLES, 0, 12); + glBindVertexArray(0); +} + +void sw_framebuffer_resize( + struct sw_framebuffer *fb, struct sw_vec2i new_size +) { + sw_log("resize framebuffer to %ix%i", new_size.x, new_size.y); + fb->size = new_size; + glBindFramebuffer(GL_FRAMEBUFFER, fb->_fb); + glBindTexture(GL_TEXTURE_2D, fb->_fbtex); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA8, + new_size.x, + new_size.y, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + 0 + ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, fb->_fbtex, 0); + + glBindTexture(GL_TEXTURE_2D, fb->_fbdepth); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_DEPTH_COMPONENT, + new_size.x, + new_size.y, + 0, + GL_DEPTH_COMPONENT, + GL_UNSIGNED_SHORT, + 0 + ); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, fb->_fbdepth, 0); +} diff --git a/src/gsa.c b/src/gsa.c index 281def9..2c6b584 100644 --- a/src/gsa.c +++ b/src/gsa.c @@ -54,18 +54,17 @@ static i32 next_render_vert; static struct render_vert render_verts[MAX_RENDER_VERTS * 4]; static sw_color32 palette[256]; static f32 palette_gl[1024]; +static u32 tex; int gsa_main(int argc, char *argv[]) { (void)argc; (void)argv; - u32 tex; i32 max_components; sw_log("Initialising GameSkunkAdvance v0.0"); _win = sw_window_create(sw_vec2i(304, 176), "Game Skunk Advance v0.0"); program = sw_shaderprogram_create(vert_source, frag_source); - sw_shaderprogram_use(program); glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &max_components); sw_log("GL_MAX_VERTEX_UNIFORM_COMPONENTS: %i", max_components); @@ -88,9 +87,11 @@ int gsa_main(int argc, char *argv[]) { _gfx->_data ); - glGenBuffers(1, &vao); + sw_log("setup gsa vao"); + glGenVertexArrays(1, &vao); glBindVertexArray(vao); + sw_log("setup gsa vbo"); glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glVertexAttribPointer( @@ -112,7 +113,9 @@ int gsa_main(int argc, char *argv[]) { glEnableVertexAttribArray(glGetAttribLocation(program._program, "pos")); glEnableVertexAttribArray(glGetAttribLocation(program._program, "tex_coord") ); + glBindVertexArray(0); + sw_log("gsa setup done"); init(); sw_window_run(_win, _gsa_tick); @@ -202,8 +205,11 @@ void _gsa_tick() { sw_color32_get_bf(palette[0]), sw_color32_get_af(palette[0]) ); - + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBindVertexArray(vao); + sw_shaderprogram_use(program); + glBindTexture(GL_TEXTURE_2D, tex); + /* TODO: only do when palette changed */ update_palette_gl(); glUniform4fv( @@ -216,5 +222,6 @@ void _gsa_tick() { GL_DYNAMIC_DRAW ); glDrawArrays(GL_TRIANGLES, 0, next_render_vert); + glBindVertexArray(0); /* glEnd(); */ } diff --git a/src/shader.c b/src/shader.c index 487778f..9fc340a 100644 --- a/src/shader.c +++ b/src/shader.c @@ -11,6 +11,8 @@ struct sw_shader sw_shader_create(char const *source, i32 type) { i32 length; i32 ret; + sw_log("create shader"); + switch(type) { case SW_SHADER_VERTEX: gltype = GL_VERTEX_SHADER; @@ -44,14 +46,24 @@ struct sw_shaderprogram sw_shaderprogram_create(char const *vertex, char const *fragment) { struct sw_shaderprogram program; struct sw_shader v, f; + i32 ret; + sw_log("create shader program"); v = sw_shader_create(vertex, SW_SHADER_VERTEX); f = sw_shader_create(fragment, SW_SHADER_FRAGMENT); program._program = glCreateProgram(); glAttachShader(program._program, v._shader); glAttachShader(program._program, f._shader); + sw_log("link shader"); glLinkProgram(program._program); + glGetProgramiv(program._program, GL_LINK_STATUS, &ret); + if(!ret) { + char str[256]; + i32 len; + glGetProgramInfoLog(program._program, 256, &len, str); + sw_error("Shader Link Error: %s", str); + } return program; } diff --git a/src/window.c b/src/window.c index 1db09b1..6efc476 100644 --- a/src/window.c +++ b/src/window.c @@ -2,11 +2,22 @@ #include +#include "error.h" +#include "framebuffer.h" #include "gl.h" -void _tick(); -struct sw_window *_tick_window; -void (*_tick_fn)(); +static void _tick(); +static struct sw_window *_tick_window; +static void (*_tick_fn)(); +static void GLAPIENTRY gldebug( + GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const char *msg, + const void *user +); struct sw_window *sw_window_create(struct sw_vec2i size, char *title) { struct sw_window *win; @@ -14,6 +25,7 @@ struct sw_window *sw_window_create(struct sw_vec2i size, char *title) { win = malloc(sizeof(struct sw_window)); win->size = size; + sw_log("init glfw"); glfwInit(); glfwDefaultWindowHints(); @@ -21,16 +33,24 @@ struct sw_window *sw_window_create(struct sw_vec2i size, char *title) { glfwShowWindow(win->_window); glfwMakeContextCurrent(win->_window); glewInit(); + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallback(gldebug, 0); glfwSwapInterval(1); + sw_log("setup ogl defaults"); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glEnable(GL_DEPTH_TEST); + sw_framebuffer_static_init(); /* TODO: move elsewhere */ + win->_scaler_fb = sw_framebuffer_create(size); + glClearColor(0.1f, 0.2f, 0.3f, 1.f); + sw_log("window setup complete"); return win; } void sw_window_run(struct sw_window *window, void (*callback)()) { + sw_log("run window"); _tick_window = window; _tick_fn = callback; #ifdef __EMSCRIPTEN__ @@ -45,8 +65,33 @@ void sw_window_run(struct sw_window *window, void (*callback)()) { /* private functions */ void _tick() { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, _tick_window->_scaler_fb->_fb); _tick_fn(); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + sw_framebuffer_copy_to_screen(_tick_window->_scaler_fb); glfwSwapBuffers(_tick_window->_window); glfwPollEvents(); } + +void GLAPIENTRY gldebug( + GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const char *msg, + const void *user +) { + (void)source; + (void)id; + (void)severity; + (void)length; + (void)user; + + if(type == GL_DEBUG_TYPE_ERROR) { + sw_error("%s", msg); + } else { + sw_log("%s", msg); + } +}