From 42d42c9ba3b741d167eaa2196c686962559686f1 Mon Sep 17 00:00:00 2001 From: sanine-a Date: Sat, 31 Oct 2020 22:43:41 -0500 Subject: add basic framebuffer operations --- demo/ScreenQuad.lua | 47 ++++++++++++++++++++++++ demo/main.lua | 37 ++++++++++++++++--- src/honey.c | 63 +++++++++++++++++++++++++++++++- src/honey.h | 8 ++++ src/primitives/primitives.c | 2 +- src/texture/texture.c | 89 +++++++++++++++++++++++++++++++++++++++++---- src/texture/texture.h | 21 +++++++---- 7 files changed, 244 insertions(+), 23 deletions(-) create mode 100644 demo/ScreenQuad.lua diff --git a/demo/ScreenQuad.lua b/demo/ScreenQuad.lua new file mode 100644 index 0000000..938674c --- /dev/null +++ b/demo/ScreenQuad.lua @@ -0,0 +1,47 @@ +local ScreenQuad = {} + +ScreenQuad.quad = honey.primitives.plane(2,2) + +local vertexShader = [[ +#version 330 core + +layout(location = 0) in vec3 position; +layout(location = 1) in vec3 normal; +layout(location = 2) in vec2 uv; + +out vec2 UV; + +void main() +{ + gl_Position = vec4(position.xy, 0, 1) - vec4(1,1,0,0); + UV = uv; +} ]] + +local fragmentShader = [[ +#version 330 core + +in vec2 UV; + +uniform sampler2D tex; + +out vec4 color; + +void main() +{ + color = vec4(texture(tex, UV)); +} ]] + +ScreenQuad.shader = honey.shader.new(vertexShader, fragmentShader) + +ScreenQuad.texture = honey.texture.new() +honey.texture.create(ScreenQuad.texture, 'rgba', 640, 480); +--honey.texture.load(ScreenQuad.texture, 'checkerboard.png', false) + +ScreenQuad.fb = honey.texture.new_framebuffer(ScreenQuad.texture, nil, 640, 480) + +ScreenQuad.draw = function(self) + honey.texture.use(self.texture, 0) + honey.mesh.draw(self.quad, self.shader) +end + +return ScreenQuad diff --git a/demo/main.lua b/demo/main.lua index 3c32b6f..5474609 100644 --- a/demo/main.lua +++ b/demo/main.lua @@ -1,6 +1,7 @@ local Vector = require('Vector') local Matrix = require('Matrix') local FPSCamera = require('FPSCamera') +local ScreenQuad = require('ScreenQuad') FPSCamera.movement_speed = 5 local model = Matrix.Mat4.eye() @@ -10,9 +11,11 @@ print(model) honey.input.key.bind(honey.input.key.escape, honey.exit) +local buffer = false +honey.input.key.bind(honey.input.key.f, function(action) if action == 1 then buffer = not buffer end end) + local tex = honey.texture.new() honey.texture.load(tex, 'checkerboard.png', false) -honey.texture.use(tex, 0) local vertex_shader = [[ #version 330 core @@ -49,12 +52,13 @@ uniform sampler2D tex; out vec4 color; void main() { - vec2 texture_coords = UV + (time * vec2(100,100)); - color = vec4(texture(tex, texture_coords).xyz, 1); + //vec2 texture_coords = UV + (time * vec2(100,100)); + color = vec4(texture(tex, UV).xyz, 1); } ]] local shader = honey.shader.new(vertex_shader, fragment_shader) -local plane = honey.mesh.load('Suzanne.obj')[1] +local suzanne = honey.mesh.load('Suzanne.obj')[1] +local plane = honey.primitives.plane(4,4) local color1 = Vector.Vec4.new{1,0,0,1} local color2 = Vector.Vec4.new{0,0,1,1} @@ -73,11 +77,32 @@ function honey.update(dt) end end -function honey.draw() - total_frames = total_frames + 1 +function draw_suzanne() + honey.texture.use(tex, 0) honey.shader.set_mat4(shader, 'model', model.array) honey.shader.set_mat4(shader, 'view', FPSCamera.view.array) honey.shader.set_mat4(shader, 'projection', FPSCamera.projection.array) honey.shader.set_float(shader, 'time', total_time) + honey.mesh.draw(suzanne, shader) honey.mesh.draw(plane, shader) end + +function honey.draw() + total_frames = total_frames + 1 + + if buffer then + honey.set_framebuffer(ScreenQuad.fb) + honey.enable_depth_test(true) + honey.clear_color(Vector.Vec4.new().array, true, true, false) + draw_suzanne() + + honey.set_framebuffer(0) + honey.enable_depth_test(true) + honey.clear_color(Vector.Vec4.new{0,0,1,1}.array, true, true, false) + ScreenQuad:draw() + else + honey.clear_color(Vector.Vec4.new{1,1,0,1}.array, true, true, false) + honey.enable_depth_test(true) + draw_suzanne() + end +end diff --git a/src/honey.c b/src/honey.c index 1328a5f..ce1a38c 100644 --- a/src/honey.c +++ b/src/honey.c @@ -53,6 +53,48 @@ bool honey_parse_options(honey_options* options, int argc, char** argv) return true; } +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +static int honey_lua_clear_color(lua_State* L) +{ + float* color_array; + bool color, depth, stencil; + honey_lua_parse_arguments(L, 4, + HONEY_USERDATA, &color_array, + HONEY_BOOLEAN, &color, + HONEY_BOOLEAN, &depth, + HONEY_BOOLEAN, &stencil); + float r = color_array[0]; + float g = color_array[1]; + float b = color_array[2]; + float a = color_array[3]; + + int clear_flags = 0; + if (color) + clear_flags = clear_flags | GL_COLOR_BUFFER_BIT; + if (depth) + clear_flags = clear_flags | GL_DEPTH_BUFFER_BIT; + if (stencil) + clear_flags = clear_flags | GL_STENCIL_BUFFER_BIT; + + glClearColor(r, g, b, a); + glClear(clear_flags); + return 0; +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +int honey_lua_enable_depth_test(lua_State* L) +{ + bool enable; + honey_lua_parse_arguments(L, 1, HONEY_BOOLEAN, &enable); + if (enable) + glEnable(GL_DEPTH_TEST); + else + glDisable(GL_DEPTH_TEST); + return 0; +} + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ bool honey_setup(lua_State** L) @@ -88,6 +130,15 @@ bool honey_setup(lua_State** L) lua_pushcfunction(*L, honey_exit); lua_setfield(*L, -2, "exit"); + lua_pushcfunction(*L, honey_set_framebuffer); + lua_setfield(*L, -2, "set_framebuffer"); + + lua_pushcfunction(*L, honey_lua_clear_color); + lua_setfield(*L, -2, "clear_color"); + + lua_pushcfunction(*L, honey_lua_enable_depth_test); + lua_setfield(*L, -2, "enable_depth_test"); + lua_setglobal(*L, "honey"); return true; @@ -145,8 +196,6 @@ bool honey_run(lua_State* L, honey_options opts) { if (drawTime > 0.016) { drawTime -= 0.016; - glClearColor(0,0,0,1); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (draw_callback != LUA_NOREF) { lua_rawgeti(L, LUA_REGISTRYINDEX, draw_callback); @@ -185,3 +234,13 @@ int honey_get_callback(lua_State* L, char* callback) return ref; } + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +int honey_set_framebuffer(lua_State* L) +{ + int framebuffer; + honey_lua_parse_arguments(L, 1, HONEY_INTEGER, &framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); + return 0; +} diff --git a/src/honey.h b/src/honey.h index 8231b70..5a2e6c2 100644 --- a/src/honey.h +++ b/src/honey.h @@ -68,4 +68,12 @@ bool honey_run(lua_State* L, honey_options opts); */ int honey_get_callback(lua_State* L, char* callback); +/** @brief Set the current render target. + * + * @param[in] framebuffer The framebuffer to target, or 0 to target the window's framebuffer. + * + * @returns Nothing. + */ +int honey_set_framebuffer(lua_State* L); + #endif diff --git a/src/primitives/primitives.c b/src/primitives/primitives.c index 8293d4d..d499248 100644 --- a/src/primitives/primitives.c +++ b/src/primitives/primitives.c @@ -60,7 +60,7 @@ honey_result honey_mesh_new_textured_plane(honey_mesh* mesh, unsigned int indices[] = { 0, 1, 2, - 1, 2, 3 }; + 3, 2, 1 }; unsigned int attrib_sizes[] = { 3, 3, 2 }; diff --git a/src/texture/texture.c b/src/texture/texture.c index 6df19a7..9ddf441 100644 --- a/src/texture/texture.c +++ b/src/texture/texture.c @@ -6,6 +6,37 @@ static int honey_lua_texture_new(lua_State* L) return 1; } +static int honey_lua_texture_create(lua_State* L) +{ + honey_texture* texture; + int width, height; + char* type; + honey_lua_parse_arguments(L, 4, + HONEY_USERDATA, &texture, + HONEY_STRING, &type, + HONEY_INTEGER, &width, + HONEY_INTEGER, &height); + + if (strcmp(type, "greyscale") == 0) + honey_texture_new_greyscale(texture, width, height, NULL); + else if (strcmp(type, "rgb") == 0) + honey_texture_new_rgb(texture, width, height, NULL); + else if (strcmp(type, "rgba") == 0) + honey_texture_new_rgba(texture, width, height, NULL); + else if (strcmp(type, "depth") == 0) + honey_texture_new_depth(texture, width, height, NULL); + else { + char* error; + honey_format_string(&error, + "unknown texture type '%s'", + type); + lua_pushstring(L, error); + free(error); + lua_error(L); + } + return 0; +} + static int honey_lua_texture_load(lua_State* L) { honey_texture* texture; @@ -38,15 +69,43 @@ static int honey_lua_texture_use(lua_State* L) return 0; } +static int honey_lua_framebuffer_new(lua_State* L) +{ + honey_texture* draw, *depth; + if (lua_isuserdata(L, 1)) + draw = lua_touserdata(L, 1); + else + draw = NULL; + + if (lua_isuserdata(L, 2)) + depth = lua_touserdata(L, 2); + else + depth = NULL; + + int width, height; + honey_lua_parse_arguments(L, 4, HONEY_ANY, HONEY_ANY, + HONEY_INTEGER, &width, + HONEY_INTEGER, &height); + + unsigned int framebuffer; + honey_texture_framebuffer_object_new(&framebuffer, + draw, depth, + width, height); + lua_pushinteger(L, framebuffer); + return 1; +} + void honey_setup_texture(lua_State* L) { honey_lua_element texture_elements[] = { { "new", HONEY_FUNCTION, { .function = honey_lua_texture_new } }, + { "new_framebuffer", HONEY_FUNCTION, { .function = honey_lua_framebuffer_new } }, + { "create", HONEY_FUNCTION, { .function = honey_lua_texture_create } }, { "load", HONEY_FUNCTION, { .function = honey_lua_texture_load } }, { "use", HONEY_FUNCTION, { .function = honey_lua_texture_use } }, }; - honey_lua_create_table(L, texture_elements, 3); + honey_lua_create_table(L, texture_elements, 5); } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ @@ -182,10 +241,26 @@ void honey_texture_use(honey_texture texture, int texture_unit) { /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -//honey_result honey_texture_framebuffer_object_new(unsigned int* destination, -// int width, int height) -//{ -// glGenFramebuffers(1, destination); -// glBindFramebuffer(GL_FRAMEBUFFER, *destination); +void honey_texture_framebuffer_object_new(unsigned int* destination, + honey_texture* draw, + honey_texture* depth, + int width, int height) +{ + glGenFramebuffers(1, destination); + glBindFramebuffer(GL_FRAMEBUFFER, *destination); + + if (draw != NULL) + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, draw->id, 0); + else { + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + } - + if (depth != NULL) + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth->id, 0); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + printf("framebuffer is not complete!\n"); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} diff --git a/src/texture/texture.h b/src/texture/texture.h index 785fef0..9dc0308 100644 --- a/src/texture/texture.h +++ b/src/texture/texture.h @@ -37,7 +37,7 @@ void honey_setup_texture(lua_State* L); * @param[in] height The height in pixels of the texture to create. * @param[in] data The data to populate the texture with, or NULL to leave it unpopulated. * - * @returns HONEY_OK on success, and appropriate error on failure. + * @returns Nothing. */ void honey_texture_new_greyscale(honey_texture* texture, int width, int height, @@ -50,7 +50,7 @@ void honey_texture_new_greyscale(honey_texture* texture, * @param[in] height The height in pixels of the texture to create. * @param[in] data The data to populate the texture with, or NULL to leave it unpopulated. * - * @returns HONEY_OK on success, and appropriate error on failure. + * @returns Nothing. */ void honey_texture_new_rgb(honey_texture* texture, int width, int height, @@ -63,7 +63,7 @@ void honey_texture_new_rgb(honey_texture* texture, * @param[in] height The height in pixels of the texture to create. * @param[in] data The data to populate the texture with, or NULL to leave it unpopulated. * - * @returns HONEY_OK on success, and appropriate error on failure. + * @returns Nothing. */ void honey_texture_new_rgba(honey_texture* texture, int width, int height, @@ -76,7 +76,7 @@ void honey_texture_new_rgba(honey_texture* texture, * @param[in] height The height in pixels of the texture to create. * @param[in] data The data to populate the texture with, or NULL to leave it unpopulated. * - * @returns HONEY_OK on success, and appropriate error on failure. + * @returns Nothing. */ void honey_texture_new_depth(honey_texture* texture, int width, int height, @@ -101,14 +101,21 @@ enum honey_texture_result honey_texture_load(honey_texture* texture, void honey_texture_use(honey_texture texture, int texture_unit); /** @brief Create a framebuffer object. + * + * You must specify at least one of draw and depth; otherwise, the framebuffer will + * be incomplete and fail. * * @param[out] destination Pointer to store the resulting OpenGL handle in. + * @param[in] draw Pointer to a texture to draw to. + * @param[in] depth Pointer to a depth texture. * @param[in] width The width in pixels of the FBO. * @param[in] height The height in pixels of the FBO. * - * @returns HONEY_OK on success; appropriate error otherwise. + * @returns Nothing. */ -honey_result honey_texture_framebuffer_object_new(unsigned int* destination, - int width, int height); +void honey_texture_framebuffer_object_new(unsigned int* destination, + honey_texture* draw, + honey_texture* depth, + int width, int height); #endif -- cgit v1.2.1