From 216115a3a57fa6b281478abf691f8b09d2b95645 Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 7 Dec 2024 01:39:09 +0000 Subject: [PATCH] library: surface settint + setalpha api --- src/library/doc/doc.texi | 27 +++++++++++++++++++++ src/library/gl.c | 42 ++++++++++++++++++++++++++++++++- src/library/gl.h | 13 ++++++++++ src/library/plugin/plugin.h | 8 +++++++ src/library/plugin/plugin_api.c | 18 ++++++++++++++ 5 files changed, 107 insertions(+), 1 deletion(-) diff --git a/src/library/doc/doc.texi b/src/library/doc/doc.texi index 59a5de2..7c4b438 100644 --- a/src/library/doc/doc.texi +++ b/src/library/doc/doc.texi @@ -1064,6 +1064,33 @@ mysurface:drawtowindow(mywindow, 0, 0, 100, 100, 0, 0, 1920, 1080) @end verbatim @end example +@node surface-settint +@subsection settint + +Sets the "tint" this surface will be drawn with when drawing it to the +screen or to another surface. These values are in the range [0.0 - 1.0] +and are multiplied with the red, green and blue channels of the image, +so values less than 1.0 will darken the image. The defaults are all 1.0. + +@example lua +@verbatim +mysurface:settint(red, green, blue) +@end verbatim +@end example + +@node surface-setalpha +@subsection setalpha + +Sets the alpha transparency this surface will be drawn with when drawing +it to the screen or to another surface. The value is in the range [0.0 - +1.0] where 0.0 is invisible and 1.0 is fully opaque. The default is 1.0. + +@example lua +@verbatim +mysurface:setalpha(0.5) +@end verbatim +@end example + @node objects-buffer @section Buffer diff --git a/src/library/gl.c b/src/library/gl.c index 385c9c1..317821b 100644 --- a/src/library/gl.c +++ b/src/library/gl.c @@ -31,11 +31,13 @@ static GLint program_direct_screen_sampler; static GLint program_direct_screen_d_xywh; static GLint program_direct_screen_s_xywh; static GLint program_direct_screen_src_wh_dest_wh; +static GLint program_direct_screen_rgba; static GLuint program_direct_surface; static GLint program_direct_surface_sampler; static GLint program_direct_surface_d_xywh; static GLint program_direct_surface_s_xywh; static GLint program_direct_surface_src_wh_dest_wh; +static GLint program_direct_surface_rgba; static GLuint program_region; static GLint program_region_xywh; static GLint program_region_dest_wh; @@ -70,8 +72,9 @@ static const GLchar program_direct_fs[] = GLSLHEADER "uniform sampler2D tex;" "uniform ivec4 s_xywh;" "uniform ivec4 src_wh_dest_wh;" +"uniform vec4 rgba;" "void main() {" - "col = texture(tex, ((vPos * s_xywh.pq) + s_xywh.st) / src_wh_dest_wh.st);" + "col = texture(tex, ((vPos * s_xywh.pq) + s_xywh.st) / src_wh_dest_wh.st) * clamp(rgba, 0.0, 1.0);" "}"; // "region" program draws an outline of alternating black and white pixels on a rectangular region of the screen @@ -129,6 +132,8 @@ static void _bolt_gl_plugin_surface_clear(void* userdata, double r, double g, do static void _bolt_gl_plugin_surface_subimage(void* userdata, int x, int y, int w, int h, const void* pixels, uint8_t is_bgra); static void _bolt_gl_plugin_surface_drawtoscreen(void* userdata, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh); static void _bolt_gl_plugin_surface_drawtosurface(void* userdata, void* target, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh); +static void _bolt_gl_plugin_surface_set_tint(void* userdata, double r, double g, double b); +static void _bolt_gl_plugin_surface_set_alpha(void* userdata, double alpha); static void _bolt_gl_plugin_draw_region_outline(void* userdata, int16_t x, int16_t y, uint16_t width, uint16_t height); static void _bolt_gl_plugin_read_screen_pixels(uint32_t width, uint32_t height, void* data); static void _bolt_gl_plugin_game_view_rect(int* x, int* y, int* w, int* h); @@ -168,6 +173,7 @@ struct PluginSurfaceUserdata { unsigned int height; GLuint framebuffer; GLuint renderbuffer; + GLfloat rgba[4]; }; struct PluginShaderUserdata { @@ -622,9 +628,22 @@ static void _bolt_gl_load(void* (*GetProcAddress)(const char*)) { INIT_GL_FUNC(MultiDrawElements) INIT_GL_FUNC(ShaderSource) INIT_GL_FUNC(TexStorage2D) + INIT_GL_FUNC(Uniform1f) + INIT_GL_FUNC(Uniform2f) + INIT_GL_FUNC(Uniform3f) + INIT_GL_FUNC(Uniform4f) + INIT_GL_FUNC(Uniform1fv) + INIT_GL_FUNC(Uniform2fv) + INIT_GL_FUNC(Uniform3fv) + INIT_GL_FUNC(Uniform4fv) INIT_GL_FUNC(Uniform1i) INIT_GL_FUNC(Uniform2i) + INIT_GL_FUNC(Uniform3i) INIT_GL_FUNC(Uniform4i) + INIT_GL_FUNC(Uniform1iv) + INIT_GL_FUNC(Uniform2iv) + INIT_GL_FUNC(Uniform3iv) + INIT_GL_FUNC(Uniform4iv) INIT_GL_FUNC(UniformMatrix4fv) INIT_GL_FUNC(UnmapBuffer) INIT_GL_FUNC(UseProgram) @@ -664,6 +683,7 @@ static void _bolt_gl_init() { program_direct_screen_d_xywh = gl.GetUniformLocation(program_direct_screen, "d_xywh"); program_direct_screen_s_xywh = gl.GetUniformLocation(program_direct_screen, "s_xywh"); program_direct_screen_src_wh_dest_wh = gl.GetUniformLocation(program_direct_screen, "src_wh_dest_wh"); + program_direct_screen_rgba = gl.GetUniformLocation(program_direct_screen, "rgba"); program_direct_surface = gl.CreateProgram(); gl.AttachShader(program_direct_surface, direct_surface_vs); @@ -673,6 +693,7 @@ static void _bolt_gl_init() { program_direct_surface_d_xywh = gl.GetUniformLocation(program_direct_surface, "d_xywh"); program_direct_surface_s_xywh = gl.GetUniformLocation(program_direct_surface, "s_xywh"); program_direct_surface_src_wh_dest_wh = gl.GetUniformLocation(program_direct_surface, "src_wh_dest_wh"); + program_direct_surface_rgba = gl.GetUniformLocation(program_direct_surface, "rgba"); gl.DetachShader(program_direct_screen, direct_screen_vs); gl.DetachShader(program_direct_screen, direct_fs); @@ -2118,6 +2139,9 @@ static void _bolt_gl_plugin_surface_init(struct SurfaceFunctions* functions, uns struct GLContext* c = _bolt_context(); userdata->width = width; userdata->height = height; + for (size_t i = 0; i < 4; i += 1) { + userdata->rgba[i] = 1.0; + } _bolt_gl_surface_init_buffers(userdata); if (data) { lgl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data); @@ -2130,6 +2154,8 @@ static void _bolt_gl_plugin_surface_init(struct SurfaceFunctions* functions, uns functions->subimage = _bolt_gl_plugin_surface_subimage; functions->draw_to_screen = _bolt_gl_plugin_surface_drawtoscreen; functions->draw_to_surface = _bolt_gl_plugin_surface_drawtosurface; + functions->set_tint = _bolt_gl_plugin_surface_set_tint; + functions->set_alpha = _bolt_gl_plugin_surface_set_alpha; const struct GLTexture2D* original_tex = c->texture_units[c->active_texture]; lgl->BindTexture(GL_TEXTURE_2D, original_tex ? original_tex->id : 0); @@ -2186,6 +2212,7 @@ static void _bolt_gl_plugin_surface_drawtoscreen(void* _userdata, int sx, int sy gl.Uniform4i(program_direct_screen_d_xywh, dx, dy, dw, dh); gl.Uniform4i(program_direct_screen_s_xywh, sx, sy, sw, sh); gl.Uniform4i(program_direct_screen_src_wh_dest_wh, userdata->width, userdata->height, gl_width, gl_height); + gl.Uniform4fv(program_direct_screen_rgba, 1, userdata->rgba); lgl->Viewport(0, 0, gl_width, gl_height); lgl->Disable(GL_DEPTH_TEST); lgl->Disable(GL_SCISSOR_TEST); @@ -2220,6 +2247,7 @@ static void _bolt_gl_plugin_surface_drawtosurface(void* _userdata, void* _target gl.Uniform4i(program_direct_surface_d_xywh, dx, dy, dw, dh); gl.Uniform4i(program_direct_surface_s_xywh, sx, sy, sw, sh); gl.Uniform4i(program_direct_surface_src_wh_dest_wh, userdata->width, userdata->height, target->width, target->height); + gl.Uniform4fv(program_direct_screen_rgba, 1, userdata->rgba); lgl->Viewport(0, 0, target->width, target->height); lgl->Disable(GL_DEPTH_TEST); lgl->Disable(GL_SCISSOR_TEST); @@ -2237,6 +2265,18 @@ static void _bolt_gl_plugin_surface_drawtosurface(void* _userdata, void* _target gl.UseProgram(c->bound_program ? c->bound_program->id : 0); } +static void _bolt_gl_plugin_surface_set_tint(void* userdata, double r, double g, double b) { + struct PluginSurfaceUserdata* surface = userdata; + surface->rgba[0] = (GLfloat)r; + surface->rgba[1] = (GLfloat)g; + surface->rgba[2] = (GLfloat)b; +} + +static void _bolt_gl_plugin_surface_set_alpha(void* userdata, double alpha) { + struct PluginSurfaceUserdata* surface = userdata; + surface->rgba[3] = (GLfloat)alpha; +} + static void _bolt_gl_plugin_draw_region_outline(void* userdata, int16_t x, int16_t y, uint16_t width, uint16_t height) { struct PluginSurfaceUserdata* target = userdata; struct GLContext* c = _bolt_context(); diff --git a/src/library/gl.h b/src/library/gl.h index 1a933aa..1cb79b3 100644 --- a/src/library/gl.h +++ b/src/library/gl.h @@ -81,9 +81,22 @@ struct GLProcFunctions { void (*MultiDrawElements)(GLenum, const GLsizei*, GLenum, const void* const*, GLsizei); void (*ShaderSource)(GLuint, GLsizei, const GLchar**, const GLint*); void (*TexStorage2D)(GLenum, GLsizei, GLenum, GLsizei, GLsizei); + void (*Uniform1f)(GLint, GLfloat); + void (*Uniform2f)(GLint, GLfloat, GLfloat); + void (*Uniform3f)(GLint, GLfloat, GLfloat, GLfloat); + void (*Uniform4f)(GLint, GLfloat, GLfloat, GLfloat, GLfloat); + void (*Uniform1fv)(GLint, GLsizei, const GLfloat*); + void (*Uniform2fv)(GLint, GLsizei, const GLfloat*); + void (*Uniform3fv)(GLint, GLsizei, const GLfloat*); + void (*Uniform4fv)(GLint, GLsizei, const GLfloat*); void (*Uniform1i)(GLint, GLint); void (*Uniform2i)(GLint, GLint, GLint); + void (*Uniform3i)(GLint, GLint, GLint, GLint); void (*Uniform4i)(GLint, GLint, GLint, GLint, GLint); + void (*Uniform1iv)(GLint, GLsizei, const GLint*); + void (*Uniform2iv)(GLint, GLsizei, const GLint*); + void (*Uniform3iv)(GLint, GLsizei, const GLint*); + void (*Uniform4iv)(GLint, GLsizei, const GLint*); void (*UniformMatrix4fv)(GLint, GLsizei, GLboolean, const GLfloat*); GLboolean (*UnmapBuffer)(GLenum); void (*UseProgram)(GLuint); diff --git a/src/library/plugin/plugin.h b/src/library/plugin/plugin.h index 76eb59c..a56447b 100644 --- a/src/library/plugin/plugin.h +++ b/src/library/plugin/plugin.h @@ -158,6 +158,14 @@ struct SurfaceFunctions { /// Draws a rectangle from the surface, indicated by sx,sy,sw,sh, to a rectangle on the target surface, /// indicated by dx,dy,dw,dh. All values are in pixels. void (*draw_to_surface)(void* userdata, void* target, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh); + + /// Sets the tint this surface will be drawn with when calling draw_to_screen or draw_to_surface. + /// Values are in the range [0.0 - 1.0]. Defaults are 1.0. + void (*set_tint)(void* userdata, double r, double g, double b); + + /// Sets the transparency this surface will be drawn with when calling draw_to_screen or draw_to_surface. + /// Value is in the range [0.0 - 1.0] with 0.0 being invisible and 1.0 being fully opaque. Default is 1.0. + void (*set_alpha)(void* userdata, double alpha); }; /// Struct containing "vtable" callback information for shaders diff --git a/src/library/plugin/plugin_api.c b/src/library/plugin/plugin_api.c index 2fcf1ad..6bea86f 100644 --- a/src/library/plugin/plugin_api.c +++ b/src/library/plugin/plugin_api.c @@ -1076,6 +1076,22 @@ static int api_surface_drawtowindow(lua_State* state) { return 0; } +static int api_surface_settint(lua_State* state) { + const struct SurfaceFunctions* functions = require_self_userdata(state, "settint"); + const lua_Number r = luaL_checknumber(state, 2); + const lua_Number g = luaL_checknumber(state, 3); + const lua_Number b = luaL_checknumber(state, 4); + functions->set_tint(functions->userdata, r, g, b); + return 0; +} + +static int api_surface_setalpha(lua_State* state) { + const struct SurfaceFunctions* functions = require_self_userdata(state, "setalpha"); + const lua_Number alpha = luaL_checknumber(state, 2); + functions->set_alpha(functions->userdata, alpha); + return 0; +} + static int api_window_close(lua_State* state) { struct EmbeddedWindow* window = require_self_userdata(state, "state"); window->is_deleted = true; @@ -1841,6 +1857,8 @@ static struct ApiFuncTemplate surface_functions[] = { BOLTFUNC(drawtoscreen, surface), BOLTFUNC(drawtosurface, surface), BOLTFUNC(drawtowindow, surface), + BOLTFUNC(settint, surface), + BOLTFUNC(setalpha, surface), }; static struct ApiFuncTemplate window_functions[] = {