From a2cd2f596ac03f4ffc393e4e5e7f7057e2ab61cf Mon Sep 17 00:00:00 2001 From: Charlotte Meyer Date: Sun, 26 Jan 2020 19:18:52 +0000 Subject: [PATCH] Add renderer --- include/desktop/view.h | 2 + include/luak/kiwmi_renderer.h | 16 +++++ kiwmi/desktop/output.c | 2 + kiwmi/desktop/view.c | 2 + kiwmi/luak/kiwmi_renderer.c | 126 ++++++++++++++++++++++++++++++++++ kiwmi/luak/kiwmi_view.c | 109 +++++++++++++++++++++++++++++ kiwmi/luak/luak.c | 3 + kiwmi/meson.build | 1 + 8 files changed, 261 insertions(+) create mode 100644 include/luak/kiwmi_renderer.h create mode 100644 kiwmi/luak/kiwmi_renderer.c diff --git a/include/desktop/view.h b/include/desktop/view.h index 64a5b13..ad4acbb 100644 --- a/include/desktop/view.h +++ b/include/desktop/view.h @@ -59,6 +59,8 @@ struct kiwmi_view { struct wl_signal unmap; struct wl_signal request_move; struct wl_signal request_resize; + struct wl_signal post_render; + struct wl_signal pre_render; } events; struct kiwmi_xdg_decoration *decoration; diff --git a/include/luak/kiwmi_renderer.h b/include/luak/kiwmi_renderer.h new file mode 100644 index 0000000..0f722cf --- /dev/null +++ b/include/luak/kiwmi_renderer.h @@ -0,0 +1,16 @@ +/* Copyright (c), Charlotte Meyer + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef KIWMI_LUAK_KIWMI_RENDERER_H +#define KIWMI_LUAK_KIWMI_RENDERER_H + +#include + +int luaK_kiwmi_renderer_new(lua_State *L); +int luaK_kiwmi_renderer_register(lua_State *L); + +#endif /* KIWMI_LUAK_KIWMI_RENDERER_H */ diff --git a/kiwmi/desktop/output.c b/kiwmi/desktop/output.c index 00187c8..4f6814c 100644 --- a/kiwmi/desktop/output.c +++ b/kiwmi/desktop/output.c @@ -154,7 +154,9 @@ output_frame_notify(struct wl_listener *listener, void *data) rdata.data = view; + wl_signal_emit(&view->events.pre_render, &rdata); view_for_each_surface(view, render_surface, &rdata); + wl_signal_emit(&view->events.post_render, &rdata); } render_layer(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &rdata); diff --git a/kiwmi/desktop/view.c b/kiwmi/desktop/view.c index b4d741b..c7bd019 100644 --- a/kiwmi/desktop/view.c +++ b/kiwmi/desktop/view.c @@ -237,6 +237,8 @@ view_create( wl_signal_init(&view->events.unmap); wl_signal_init(&view->events.request_move); wl_signal_init(&view->events.request_resize); + wl_signal_init(&view->events.post_render); + wl_signal_init(&view->events.pre_render); return view; } diff --git a/kiwmi/luak/kiwmi_renderer.c b/kiwmi/luak/kiwmi_renderer.c new file mode 100644 index 0000000..01c453b --- /dev/null +++ b/kiwmi/luak/kiwmi_renderer.c @@ -0,0 +1,126 @@ +/* Copyright (c), Charlotte Meyer + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "luak/kiwmi_renderer.h" + +#include +#include + +#include +#include +#include +#include + +#include "desktop/output.h" +#include "luak/luak.h" + +struct kiwmi_renderer { + struct wlr_renderer *wlr_renderer; + struct kiwmi_output *output; +}; + +static bool +parse_color(const char *hex, float color[static 4]) +{ + if (hex[0] == '#') { + ++hex; + } + + int len = strlen(hex); + if (len != 6 && len != 8) { + return false; + } + + uint32_t rgba = (uint32_t)strtoul(hex, NULL, 16); + if (len == 6) { + rgba = (rgba << 8) | 0xff; + } + + for (size_t i = 0; i < 4; ++i) { + color[3 - i] = (rgba & 0xff) / 255.0; + rgba >>= 8; + } + + // premultiply alpha + color[0] *= color[3]; + color[1] *= color[3]; + color[2] *= color[3]; + + return true; +} + +static int +l_kiwmi_renderer_draw_rect(lua_State *L) +{ + struct kiwmi_renderer *renderer = + (struct kiwmi_renderer *)luaL_checkudata(L, 1, "kiwmi_renderer"); + luaL_checktype(L, 2, LUA_TSTRING); // color + luaL_checktype(L, 3, LUA_TNUMBER); // x + luaL_checktype(L, 4, LUA_TNUMBER); // y + luaL_checktype(L, 5, LUA_TNUMBER); // width + luaL_checktype(L, 6, LUA_TNUMBER); // height + + struct wlr_renderer *wlr_renderer = renderer->wlr_renderer; + struct kiwmi_output *output = renderer->output; + struct wlr_output *wlr_output = output->wlr_output; + + float color[4]; + if (!parse_color(lua_tostring(L, 2), color)) { + return luaL_argerror(L, 2, "not a valid color"); + } + + struct wlr_box box = { + .x = lua_tonumber(L, 3), + .y = lua_tonumber(L, 4), + .width = lua_tonumber(L, 5), + .height = lua_tonumber(L, 6), + }; + + wlr_render_rect(wlr_renderer, &box, color, wlr_output->transform_matrix); + + return 0; +} + +static const luaL_Reg kiwmi_renderer_methods[] = { + {"draw_rect", l_kiwmi_renderer_draw_rect}, + {NULL, NULL}, +}; + +int +luaK_kiwmi_renderer_new(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); // wlr_renderer + luaL_checktype(L, 2, LUA_TLIGHTUSERDATA); // wlr_output + + struct wlr_renderer *wlr_renderer = lua_touserdata(L, 1); + struct kiwmi_output *output = lua_touserdata(L, 2); + + struct kiwmi_renderer *renderer_ud = + lua_newuserdata(L, sizeof(*renderer_ud)); + luaL_getmetatable(L, "kiwmi_renderer"); + lua_setmetatable(L, -2); + + renderer_ud->wlr_renderer = wlr_renderer; + renderer_ud->output = output; + + return 1; +} + +int +luaK_kiwmi_renderer_register(lua_State *L) +{ + luaL_newmetatable(L, "kiwmi_renderer"); + + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_setfuncs(L, kiwmi_renderer_methods, 0); + + lua_pushcfunction(L, luaK_usertype_ref_equal); + lua_setfield(L, -2, "__eq"); + + return 0; +} diff --git a/kiwmi/luak/kiwmi_view.c b/kiwmi/luak/kiwmi_view.c index bcc5e28..12cf1e7 100644 --- a/kiwmi/luak/kiwmi_view.c +++ b/kiwmi/luak/kiwmi_view.c @@ -15,10 +15,13 @@ #include #include +#include "desktop/output.h" #include "desktop/view.h" #include "desktop/xdg_shell.h" #include "input/seat.h" #include "luak/kiwmi_lua_callback.h" +#include "luak/kiwmi_output.h" +#include "luak/kiwmi_renderer.h" #include "server.h" static int @@ -351,6 +354,62 @@ kiwmi_view_on_destroy_notify(struct wl_listener *listener, void *data) } } +static void +kiwmi_view_on_render_notify(struct wl_listener *listener, void *data) +{ + struct kiwmi_lua_callback *lc = wl_container_of(listener, lc, listener); + struct kiwmi_server *server = lc->server; + lua_State *L = server->lua->L; + struct kiwmi_render_data *rdata = data; + + struct kiwmi_view *view = rdata->data; + struct wlr_renderer *renderer = rdata->renderer; + struct kiwmi_output *output = rdata->output->data; + + lua_rawgeti(L, LUA_REGISTRYINDEX, lc->callback_ref); + + lua_newtable(L); + + lua_pushcfunction(L, luaK_kiwmi_view_new); + lua_pushlightuserdata(L, view); + + if (lua_pcall(L, 1, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + lua_pop(L, 1); + return; + } + + lua_setfield(L, -2, "view"); + + lua_pushcfunction(L, luaK_kiwmi_output_new); + lua_pushlightuserdata(L, output); + + if (lua_pcall(L, 1, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + lua_pop(L, 1); + return; + } + + lua_setfield(L, -2, "output"); + + lua_pushcfunction(L, luaK_kiwmi_renderer_new); + lua_pushlightuserdata(L, renderer); + lua_pushlightuserdata(L, output); + + if (lua_pcall(L, 2, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + lua_pop(L, 1); + return; + } + + lua_setfield(L, -2, "renderer"); + + if (lua_pcall(L, 1, 0, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + lua_pop(L, 1); + } +} + static void kiwmi_view_on_request_move_notify(struct wl_listener *listener, void *data) { @@ -456,6 +515,54 @@ l_kiwmi_view_on_destroy(lua_State *L) return 1; } +static int +l_kiwmi_view_on_post_render(lua_State *L) +{ + struct kiwmi_view *view = + *(struct kiwmi_view **)luaL_checkudata(L, 1, "kiwmi_view"); + luaL_checktype(L, 2, LUA_TFUNCTION); + + struct kiwmi_desktop *desktop = view->desktop; + struct kiwmi_server *server = wl_container_of(desktop, server, desktop); + + lua_pushcfunction(L, luaK_kiwmi_lua_callback_new); + lua_pushlightuserdata(L, server); + lua_pushvalue(L, 2); + lua_pushlightuserdata(L, kiwmi_view_on_render_notify); + lua_pushlightuserdata(L, &view->events.post_render); + + if (lua_pcall(L, 4, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + return 0; + } + + return 1; +} + +static int +l_kiwmi_view_on_pre_render(lua_State *L) +{ + struct kiwmi_view *view = + *(struct kiwmi_view **)luaL_checkudata(L, 1, "kiwmi_view"); + luaL_checktype(L, 2, LUA_TFUNCTION); + + struct kiwmi_desktop *desktop = view->desktop; + struct kiwmi_server *server = wl_container_of(desktop, server, desktop); + + lua_pushcfunction(L, luaK_kiwmi_lua_callback_new); + lua_pushlightuserdata(L, server); + lua_pushvalue(L, 2); + lua_pushlightuserdata(L, kiwmi_view_on_render_notify); + lua_pushlightuserdata(L, &view->events.pre_render); + + if (lua_pcall(L, 4, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + return 0; + } + + return 1; +} + static int l_kiwmi_view_on_request_move(lua_State *L) { @@ -506,6 +613,8 @@ l_kiwmi_view_on_request_resize(lua_State *L) static const luaL_Reg kiwmi_view_events[] = { {"destroy", l_kiwmi_view_on_destroy}, + {"post_render", l_kiwmi_view_on_post_render}, + {"pre_render", l_kiwmi_view_on_pre_render}, {"request_move", l_kiwmi_view_on_request_move}, {"request_resize", l_kiwmi_view_on_request_resize}, {NULL, NULL}, diff --git a/kiwmi/luak/luak.c b/kiwmi/luak/luak.c index 2f94fb7..ffb350c 100644 --- a/kiwmi/luak/luak.c +++ b/kiwmi/luak/luak.c @@ -18,6 +18,7 @@ #include "luak/kiwmi_keyboard.h" #include "luak/kiwmi_lua_callback.h" #include "luak/kiwmi_output.h" +#include "luak/kiwmi_renderer.h" #include "luak/kiwmi_server.h" #include "luak/kiwmi_view.h" @@ -89,6 +90,8 @@ luaK_create(struct kiwmi_server *server) error |= lua_pcall(L, 0, 0, 0); lua_pushcfunction(L, luaK_kiwmi_output_register); error |= lua_pcall(L, 0, 0, 0); + lua_pushcfunction(L, luaK_kiwmi_renderer_register); + error |= lua_pcall(L, 0, 0, 0); lua_pushcfunction(L, luaK_kiwmi_server_register); error |= lua_pcall(L, 0, 0, 0); lua_pushcfunction(L, luaK_kiwmi_view_register); diff --git a/kiwmi/meson.build b/kiwmi/meson.build index 498873b..6c79fb0 100644 --- a/kiwmi/meson.build +++ b/kiwmi/meson.build @@ -15,6 +15,7 @@ kiwmi_sources = files( 'luak/kiwmi_keyboard.c', 'luak/kiwmi_lua_callback.c', 'luak/kiwmi_output.c', + 'luak/kiwmi_renderer.c', 'luak/kiwmi_server.c', 'luak/kiwmi_view.c', 'luak/luak.c',