From a75075555033c0eb1bfeb3ea9522064d75817c5b Mon Sep 17 00:00:00 2001 From: Timothy Schoen Date: Mon, 2 Sep 2024 14:23:58 +0200 Subject: [PATCH 01/21] Compatibility fix for pd 0.55-1 --- pdlua.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pdlua.c b/pdlua.c index 082c129..685c9ef 100644 --- a/pdlua.c +++ b/pdlua.c @@ -172,6 +172,9 @@ void initialise_lua_state() # define PDLUA_DEBUG3 PDLUA_DEBUG #endif +EXTERN int sys_trytoopenone(const char *dir, const char *name, const char* ext, + char *dirresult, char **nameresult, unsigned int size, int bin); + // In plugdata we're linked statically and thus c_externdir is empty. // So we pass a data directory to the setup function instead and store it here. // ag: Renamed to pdlua_datadir since we also need this in vanilla when From 046ac53f1f157ec129ab71c76efce1f6a342974d Mon Sep 17 00:00:00 2001 From: Timothy Schoen Date: Mon, 9 Sep 2024 02:03:16 +0200 Subject: [PATCH 02/21] Improve multi-layer drawing --- Makefile | 2 +- pd.lua | 43 ++++++++++++++++--- pdlua.c | 2 +- pdlua.h | 3 ++ pdlua_gfx.h | 120 ++++++++++++++++++++++++++++++++-------------------- 5 files changed, 116 insertions(+), 54 deletions(-) diff --git a/Makefile b/Makefile index 739aeb1..4d35806 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ luaflags += -DLUA_USE_WINDOWS endef endif -cflags = ${luaflags} -DPDLUA_VERSION="$(pdlua_version)" +cflags = ${luaflags} -DPDLUA_VERSION="$(pdlua_version)" -fsanitize=address -g pdlua.class.sources := pdlua.c $(luasrc) pdlua.class.ldlibs := $(lualibs) diff --git a/pd.lua b/pd.lua index da9166c..4e3c581 100644 --- a/pd.lua +++ b/pd.lua @@ -97,7 +97,7 @@ end pd._repaint = function (object) local obj = pd._objects[object] if nil ~= obj and type(obj.repaint) == "function" then - obj:repaint(); + obj:repaint(0); end end @@ -410,14 +410,43 @@ function pd.Class:set_args(args) pd._set_args(self._object, args) end -function pd.Class:repaint() - if type(self.paint) == "function" then - local g = _gfx_internal.start_paint(self._object); - if g ~= nil then - self:paint(g); - _gfx_internal.end_paint(g); + +function pd.Class:repaint(layer) + if layer == nil or layer <= 1 then + if type(self.paint) == "function" then + local g = _gfx_internal.start_paint(self._object, 1); + if type(self.paint) == "function" and g ~= nil then + self:paint(g); + _gfx_internal.end_paint(g, 1); + end end end + if layer == nil or layer == 0 then + local i = 2 + while true do + local paint_layer_method = "paint_layer_" .. tostring(i) + if type(self[paint_layer_method]) == "function" then + local g = _gfx_internal.start_paint(self._object, i) + if g ~= nil then + self[paint_layer_method](self, g) + _gfx_internal.end_paint(g, i) + i = i + 1 + end + else + break -- Exit the loop when no more paint_layer_X methods are found + end + end + end + if layer ~= nil and layer >= 2 then + local paint_layer_method = "paint_layer_" .. tostring(layer) + if type(self[paint_layer_method]) == "function" then + local g = _gfx_internal.start_paint(self._object, layer) + if g ~= nil then + self[paint_layer_method](self, g) + _gfx_internal.end_paint(g, layer) + end + end + end end function pd.Class:get_size() diff --git a/pdlua.c b/pdlua.c index 685c9ef..376975e 100644 --- a/pdlua.c +++ b/pdlua.c @@ -690,7 +690,7 @@ void pdlua_vis(t_gobj *z, t_glist *glist, int vis){ pdlua_gfx_repaint(x, 1); } else { - pdlua_gfx_clear(x, 1); + pdlua_gfx_clear(x, 0, 1); } } diff --git a/pdlua.h b/pdlua.h index 2f24a43..f144d40 100644 --- a/pdlua.h +++ b/pdlua.h @@ -35,6 +35,9 @@ typedef struct _pdlua_gfx char object_tag[128]; // Tcl/tk tag that is attached to all drawings char order_tag[64]; // Tag for invisible line, used to preserve correct object ordering char current_item_tag[64]; // Tcl/tk tag that is only attached to the current drawing in progress + char** layer_tags; + int num_layers; + char* current_layer_tag; gfx_transform* transforms; int num_transforms; char current_color[8]; // Keep track of current color diff --git a/pdlua_gfx.h b/pdlua_gfx.h index 71db726..7353a63 100644 --- a/pdlua_gfx.h +++ b/pdlua_gfx.h @@ -80,7 +80,7 @@ static int free_path(lua_State* L); // pdlua_gfx_clear, pdlua_gfx_repaint and pdlua_gfx_mouse_* correspond to the various callbacks the user can assign -static void pdlua_gfx_clear(t_pdlua *obj, int removed); // only for pd-vanilla, to delete all tcl/tk items +static void pdlua_gfx_clear(t_pdlua *obj, int layer, int removed); // only for pd-vanilla, to delete all tcl/tk items // Trigger repaint callback in lua script void pdlua_gfx_repaint(t_pdlua *o, int firsttime) { @@ -253,7 +253,7 @@ static inline void plugdata_draw_path(t_symbol* sym, int argc, t_atom* argv) } } -static void pdlua_gfx_clear(t_pdlua *obj, int removed) { +static void pdlua_gfx_clear(t_pdlua *obj, int layer, int removed) { } static int gfx_initialize(t_pdlua *obj) @@ -285,19 +285,27 @@ static int start_paint(lua_State* L) { return 1; } t_pdlua *obj = (t_pdlua*)lua_touserdata(L, 1); - + int layer = luaL_checknumber(L, 2); + t_atom layer_atom; + SETFLOAT(&layer_atom, layer); + lua_pushlightuserdata(L, &obj->gfx); luaL_setmetatable(L, "GraphicsContext"); plugdata_draw_callback = obj->gfx.plugdata_draw_callback; - plugdata_draw(obj, gensym("lua_start_paint"), 0, NULL); + plugdata_draw(obj, gensym("lua_start_paint"), 1, &layer_atom); return 1; } static int end_paint(lua_State* L) { t_pdlua_gfx *gfx = pop_graphics_context(L); t_pdlua *obj = gfx->object; - plugdata_draw(obj, gensym("lua_end_paint"), 0, NULL); + + int layer = luaL_checknumber(L, 1); + t_atom layer_atom; + SETFLOAT(&layer_atom, layer); + + plugdata_draw(obj, gensym("lua_end_paint"), 1, &layer_atom); return 0; } @@ -686,11 +694,11 @@ void glist_eraseiofor(t_glist *glist, t_object *ob, char *tag) } #endif -static void pdlua_gfx_clear(t_pdlua *obj, int removed) { +static void pdlua_gfx_clear(t_pdlua *obj, int layer, int removed) { t_pdlua_gfx *gfx = &obj->gfx; t_canvas *cnv = glist_getcanvas(obj->canvas); #ifndef PURR_DATA - pdgui_vmess(0, "crs", cnv, "delete", gfx->object_tag); + pdgui_vmess(0, "crs", cnv, "delete", layer == 0 ? gfx->object_tag : gfx->layer_tags[layer]); if(removed && gfx->order_tag[0] != '\0') { @@ -768,7 +776,9 @@ static int gfx_initialize(t_pdlua *obj) gfx->object = obj; gfx->transforms = NULL; gfx->num_transforms = 0; - + gfx->num_layers = 1; + gfx->layer_tags = malloc(sizeof(char*)); + pdlua_gfx_repaint(obj, 0); return 0; } @@ -796,12 +806,22 @@ static int start_paint(lua_State* L) { } t_pdlua* obj = (t_pdlua*)lua_touserdata(L, 1); + t_pdlua_gfx *gfx = &obj->gfx; if(gfx->object_tag[0] == '\0') { lua_pushnil(L); return 1; } + + int layer = luaL_checknumber(L, 2); + if(layer >= gfx->num_layers) + { + gfx->layer_tags = resizebytes(gfx->layer_tags, sizeof(char*) * gfx->num_layers, sizeof(char*) * ++gfx->num_layers); + gfx->layer_tags[layer] = malloc(64); + snprintf(gfx->layer_tags[layer], 64, ".l%i%lx", layer, (long)obj); + } + gfx->current_layer_tag = gfx->layer_tags[layer]; #ifdef PURR_DATA if (gfx->object_tag[0] == '*') { @@ -835,7 +855,7 @@ static int start_paint(lua_State* L) { #ifndef PURR_DATA // clear anything that was painted before - if(strlen(gfx->object_tag)) pdlua_gfx_clear(obj, 0); + if(strlen(gfx->object_tag)) pdlua_gfx_clear(obj, layer, 0); if(gfx->first_draw) { @@ -858,7 +878,7 @@ static int start_paint(lua_State* L) { gui_vmess("gui_luagfx_new", "xsiiiii", cnv, gfx->object_tag, xpos, ypos, glist_istoplevel(obj->canvas)); } else if (strlen(gfx->object_tag)) - pdlua_gfx_clear(obj, 0); + pdlua_gfx_clear(obj, layer, 0); #endif return 1; @@ -874,17 +894,27 @@ static int end_paint(lua_State* L) { t_canvas *cnv = glist_getcanvas(obj->canvas); int scale = glist_getzoom(glist_getcanvas(obj->canvas)); - + int layer = luaL_checknumber(L, 1); + // Draw iolets on top int xpos = text_xpix((t_object*)obj, obj->canvas); int ypos = text_ypix((t_object*)obj, obj->canvas); glist_drawiofor(obj->canvas, (t_object*)obj, 1, gfx->object_tag, xpos, ypos, xpos + (gfx->width * scale), ypos + (gfx->height * scale)); - + #ifndef PURR_DATA if(!gfx->first_draw && gfx->order_tag[0] != '\0') { + // Move everything to below the order marker, to make sure redrawn stuff isn't always on top pdgui_vmess(0, "crss", cnv, "lower", gfx->object_tag, gfx->order_tag); + + if(layer == 1) + { + if(layer < gfx->num_layers) pdgui_vmess(0, "crss", cnv, "lower", gfx->current_layer_tag, gfx->layer_tags[layer + 1]); + } + else if(layer != 0) { + pdgui_vmess(0, "crss", cnv, "raise", gfx->current_layer_tag, gfx->layer_tags[layer - 1]); + } } #endif @@ -931,10 +961,10 @@ static int fill_ellipse(lua_State* L) { int x1, y1, x2, y2; get_bounds_args(L, obj, &x1, &y1, &x2, &y2); - const char* tags[] = { gfx->object_tag, register_drawing(gfx) }; + const char* tags[] = { gfx->object_tag, register_drawing(gfx), gfx->current_layer_tag }; #ifndef PURR_DATA - pdgui_vmess(0, "crr iiii rs ri rS", cnv, "create", "oval", x1, y1, x2, y2, "-fill", gfx->current_color, "-width", 0, "-tags", 2, tags); + pdgui_vmess(0, "crr iiii rs ri rS", cnv, "create", "oval", x1, y1, x2, y2, "-fill", gfx->current_color, "-width", 0, "-tags", 3, tags); #else // PURR_DATA // in Purr Data, the coordinates of the graphical objects are all relative // to the gobj container @@ -959,14 +989,14 @@ static int stroke_ellipse(lua_State* L) { int line_width = luaL_checknumber(L, 5) * glist_getzoom(cnv); - const char* tags[] = { gfx->object_tag, register_drawing(gfx) }; + const char* tags[] = { gfx->object_tag, register_drawing(gfx), gfx->current_layer_tag }; #ifndef PURR_DATA - pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "oval", x1, y1, x2, y2, "-width", line_width, "-outline", gfx->current_color, "-tags", 2, tags); + pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "oval", x1, y1, x2, y2, "-width", line_width, "-outline", gfx->current_color, "-tags", 3, tags); #else // PURR_DATA int x0 = text_xpix((t_object*)obj, obj->canvas); int y0 = text_ypix((t_object*)obj, obj->canvas); - gui_vmess("gui_luagfx_stroke_ellipse", "xsssiiiii", cnv, tags[0], tags[1], + gui_vmess("gui_luagfx_stroke_ellipse", "xssssiiiii", cnv, tags[0], tags[1], gfx->current_color, line_width, x1-x0, y1-y0, x2-x0, y2-y0); #endif @@ -985,10 +1015,10 @@ static int fill_all(lua_State* L) { int x2 = x1 + gfx->width * glist_getzoom(cnv); int y2 = y1 + gfx->height * glist_getzoom(cnv); - const char* tags[] = { gfx->object_tag, register_drawing(gfx) }; + const char* tags[] = { gfx->object_tag, register_drawing(gfx), gfx->current_layer_tag }; #ifndef PURR_DATA - pdgui_vmess(0, "crr iiii rs rS", cnv, "create", "rectangle", x1, y1, x2, y2, "-fill", gfx->current_color, "-tags", 2, tags); + pdgui_vmess(0, "crr iiii rs rS", cnv, "create", "rectangle", x1, y1, x2, y2, "-fill", gfx->current_color, "-tags", 3, tags); #else // PURR_DATA gui_vmess("gui_luagfx_fill_all", "xsssiiii", cnv, tags[0], tags[1], gfx->current_color, @@ -1007,10 +1037,10 @@ static int fill_rect(lua_State* L) { int x1, y1, x2, y2; get_bounds_args(L, obj, &x1, &y1, &x2, &y2); - const char* tags[] = { gfx->object_tag, register_drawing(gfx) }; + const char* tags[] = { gfx->object_tag, register_drawing(gfx), gfx->current_layer_tag }; #ifndef PURR_DATA - pdgui_vmess(0, "crr iiii rs ri rS", cnv, "create", "rectangle", x1, y1, x2, y2, "-fill", gfx->current_color, "-width", 0, "-tags", 2, tags); + pdgui_vmess(0, "crr iiii rs ri rS", cnv, "create", "rectangle", x1, y1, x2, y2, "-fill", gfx->current_color, "-width", 0, "-tags", 3, tags); #else // PURR_DATA int x0 = text_xpix((t_object*)obj, obj->canvas); int y0 = text_ypix((t_object*)obj, obj->canvas); @@ -1033,10 +1063,10 @@ static int stroke_rect(lua_State* L) { int line_width = luaL_checknumber(L, 5) * glist_getzoom(cnv); - const char* tags[] = { gfx->object_tag, register_drawing(gfx) }; + const char* tags[] = { gfx->object_tag, register_drawing(gfx), gfx->current_layer_tag }; #ifndef PURR_DATA - pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "rectangle", x1, y1, x2, y2, "-width", line_width, "-outline", gfx->current_color, "-tags", 2, tags); + pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "rectangle", x1, y1, x2, y2, "-width", line_width, "-outline", gfx->current_color, "-tags", 3, tags); #else // PURR_DATA int x0 = text_xpix((t_object*)obj, obj->canvas); int y0 = text_ypix((t_object*)obj, obj->canvas); @@ -1063,16 +1093,16 @@ static int fill_rounded_rect(lua_State* L) { transform_size(gfx, &radius_x, &radius_y); - const char* tags[] = { gfx->object_tag, register_drawing(gfx) }; + const char* tags[] = { gfx->object_tag, register_drawing(gfx), gfx->current_layer_tag }; #ifndef PURR_DATA // Tcl/tk can't fill rounded rectangles, so we draw 2 smaller rectangles with 4 ovals over the corners - pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "oval", x1, y1, x1 + radius_x * 2, y1 + radius_y * 2, "-width", 0, "-fill", gfx->current_color, "-tags", 2, tags); - pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "oval", x2 - radius_x * 2 , y1, x2, y1 + radius_y * 2, "-width", 0, "-fill", gfx->current_color, "-tags", 2, tags); - pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "oval", x1, y2 - radius_y * 2, x1 + radius_x * 2, y2, "-width", 0, "-fill", gfx->current_color, "-tags", 2, tags); - pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "oval", x2 - radius_x * 2, y2 - radius_y * 2, x2, y2, "-width", 0, "-fill", gfx->current_color, "-tags", 2, tags); - pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "rectangle", x1 + radius_x, y1, x2 - radius_x, y2, "-width", 0, "-fill", gfx->current_color, "-tag", 2, tags); - pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "rectangle", x1, y1 + radius_y, x2, y2 - radius_y, "-width", 0, "-fill", gfx->current_color, "-tags", 2, tags); + pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "oval", x1, y1, x1 + radius_x * 2, y1 + radius_y * 2, "-width", 0, "-fill", gfx->current_color, "-tags", 3, tags); + pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "oval", x2 - radius_x * 2 , y1, x2, y1 + radius_y * 2, "-width", 0, "-fill", gfx->current_color, "-tags", 3, tags); + pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "oval", x1, y2 - radius_y * 2, x1 + radius_x * 2, y2, "-width", 0, "-fill", gfx->current_color, "-tags", 3, tags); + pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "oval", x2 - radius_x * 2, y2 - radius_y * 2, x2, y2, "-width", 0, "-fill", gfx->current_color, "-tags", 3, tags); + pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "rectangle", x1 + radius_x, y1, x2 - radius_x, y2, "-width", 0, "-fill", gfx->current_color, "-tag", 3, tags); + pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "rectangle", x1, y1 + radius_y, x2, y2 - radius_y, "-width", 0, "-fill", gfx->current_color, "-tags", 3, tags); #else // PURR_DATA int x0 = text_xpix((t_object*)obj, obj->canvas); int y0 = text_ypix((t_object*)obj, obj->canvas); @@ -1100,28 +1130,28 @@ static int stroke_rounded_rect(lua_State* L) { transform_size(gfx, &radius_x, &radius_y); int line_width = luaL_checknumber(L, 6) * glist_getzoom(cnv); - const char* tags[] = { gfx->object_tag, register_drawing(gfx) }; + const char* tags[] = { gfx->object_tag, register_drawing(gfx), gfx->current_layer_tag }; #ifndef PURR_DATA // Tcl/tk can't stroke rounded rectangles either, so we draw 2 lines connecting with 4 arcs at the corners pdgui_vmess(0, "crr iiii ri ri ri ri rs rs rS", cnv, "create", "arc", x1, y1 + radius_y*2, x1 + radius_x*2, y1, - "-start", 0, "-extent", 90, "-width", line_width, "-start", 90, "-outline", gfx->current_color, "-style", "arc", "-tags", 2, tags); + "-start", 0, "-extent", 90, "-width", line_width, "-start", 90, "-outline", gfx->current_color, "-style", "arc", "-tags", 3, tags); pdgui_vmess(0, "crr iiii ri ri ri ri rs rs rS", cnv, "create", "arc", x2 - radius_x*2, y1, x2, y1 + radius_y*2, - "-start", 270, "-extent", 90, "-width", line_width, "-start", 0, "-outline", gfx->current_color, "-style", "arc", "-tags", 2, tags); + "-start", 270, "-extent", 90, "-width", line_width, "-start", 0, "-outline", gfx->current_color, "-style", "arc", "-tags", 3, tags); pdgui_vmess(0, "crr iiii ri ri ri ri rs rs rS", cnv, "create", "arc", x1, y2 - radius_y*2, x1 + radius_x*2, y2, - "-start", 180, "-extent", 90, "-width", line_width, "-start", 180, "-outline", gfx->current_color, "-style", "arc", "-tags", 2, tags); + "-start", 180, "-extent", 90, "-width", line_width, "-start", 180, "-outline", gfx->current_color, "-style", "arc", "-tags", 3, tags); pdgui_vmess(0, "crr iiii ri ri ri ri rs rs rS", cnv, "create", "arc", x2 - radius_x*2, y2, x2, y2 - radius_y*2, - "-start", 90, "-extent", 90, "-width", line_width, "-start", 270, "-outline", gfx->current_color, "-style", "arc", "-tags", 2, tags); + "-start", 90, "-extent", 90, "-width", line_width, "-start", 270, "-outline", gfx->current_color, "-style", "arc", "-tags", 3, tags); // Connect with lines pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "line", x1 + radius_x, y1, x2 - radius_x, y1, - "-width", line_width, "-fill", gfx->current_color, "-tags", 2, tags); + "-width", line_width, "-fill", gfx->current_color, "-tags", 3, tags); pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "line", x1 + radius_y, y2, x2 - radius_y, y2, - "-width", line_width, "-fill", gfx->current_color, "-tags", 2, tags); + "-width", line_width, "-fill", gfx->current_color, "-tags", 3, tags); pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "line", x1 , y1 + radius_y, x1, y2 - radius_y, - "-width", line_width, "-fill", gfx->current_color, "-tags", 2, tags); + "-width", line_width, "-fill", gfx->current_color, "-tags", 3, tags); pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "line", x2 , y1 + radius_y, x2, y2 - radius_y, - "-width", line_width, "-fill", gfx->current_color, "-tags", 2, tags); + "-width", line_width, "-fill", gfx->current_color, "-tags", 3, tags); #else // PURR_DATA int x0 = text_xpix((t_object*)obj, obj->canvas); int y0 = text_ypix((t_object*)obj, obj->canvas); @@ -1162,7 +1192,7 @@ static int draw_line(lua_State* L) { y2 *= canvas_zoom; line_width *= canvas_zoom; - const char* tags[] = { gfx->object_tag, register_drawing(gfx) }; + const char* tags[] = { gfx->object_tag, register_drawing(gfx), gfx->current_layer_tag }; #ifndef PURR_DATA pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "line", x1, y1, x2, y2, @@ -1202,11 +1232,11 @@ static int draw_text(lua_State* L) { y *= canvas_zoom; w *= canvas_zoom; - const char* tags[] = { gfx->object_tag, register_drawing(gfx) }; + const char* tags[] = { gfx->object_tag, register_drawing(gfx), gfx->current_layer_tag }; #ifndef PURR_DATA pdgui_vmess(0, "crr ii rs ri rs rS", cnv, "create", "text", - 0, 0, "-anchor", "nw", "-width", w, "-text", text, "-tags", 2, tags); + 0, 0, "-anchor", "nw", "-width", w, "-text", text, "-tags", 3, tags); t_atom fontatoms[3]; SETSYMBOL(fontatoms+0, gensym(sys_font)); @@ -1246,7 +1276,7 @@ static int stroke_path(lua_State* L) { int obj_y = text_ypix((t_object*)obj, obj->canvas); int canvas_zoom = glist_getzoom(cnv); - const char* tags[] = { gfx->object_tag, register_drawing(gfx) }; + const char* tags[] = { gfx->object_tag, register_drawing(gfx), gfx->current_layer_tag }; #ifndef PURR_DATA pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "line", 0, 0, 0, 0, "-width", stroke_width, "-fill", gfx->current_color, "-tags", 2, tags); @@ -1292,10 +1322,10 @@ static int fill_path(lua_State* L) { int obj_y = text_ypix((t_object*)obj, obj->canvas); int canvas_zoom = glist_getzoom(cnv); - const char* tags[] = { gfx->object_tag, register_drawing(gfx) }; + const char* tags[] = { gfx->object_tag, register_drawing(gfx), gfx->current_layer_tag }; #ifndef PURR_DATA - pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "polygon", 0, 0, 0, 0, "-width", 0, "-fill", gfx->current_color, "-tags", 2, tags); + pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "polygon", 0, 0, 0, 0, "-width", 0, "-fill", gfx->current_color, "-tags", 3, tags); sys_vgui(".x%lx.c coords %s", cnv, tags[1]); for (int i = 0; i < path->num_path_segments; i++) { From e3a5acd0231773b420630872a4f61713fb5b839e Mon Sep 17 00:00:00 2001 From: Timothy Schoen Date: Thu, 26 Sep 2024 14:52:52 +0200 Subject: [PATCH 03/21] Improve plugdata system for multi-layer drawing --- pdlua.h | 3 ++- pdlua_gfx.h | 55 ++++++++++++++++++++++++----------------------------- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/pdlua.h b/pdlua.h index f144d40..e5c579b 100644 --- a/pdlua.h +++ b/pdlua.h @@ -47,7 +47,8 @@ typedef struct _pdlua_gfx int first_draw; #else - void(*plugdata_draw_callback)(void*, t_symbol*, int, t_atom*); // Callback to perform drawing in plugdata + int current_layer; + void(*plugdata_draw_callback)(void*, int, t_symbol*, int, t_atom*); // Callback to perform drawing in plugdata #endif } t_pdlua_gfx; diff --git a/pdlua_gfx.h b/pdlua_gfx.h index 7353a63..43c00fd 100644 --- a/pdlua_gfx.h +++ b/pdlua_gfx.h @@ -236,20 +236,20 @@ static int get_size(lua_State* L) // we make this global because paths are disconnected from object, but still need to send messages to plugdata // it really doesn't matter since all these function callbacks point to the same function anyway -static void(*plugdata_draw_callback)(void*, t_symbol*, int, t_atom*) = NULL; +static void(*plugdata_draw_callback)(void*, int, t_symbol*, int, t_atom*) = NULL; // Wrapper around draw callback to plugdata -static inline void plugdata_draw(t_pdlua *obj, t_symbol* sym, int argc, t_atom* argv) +static inline void plugdata_draw(t_pdlua *obj, int layer, t_symbol* sym, int argc, t_atom* argv) { if(plugdata_draw_callback) { - plugdata_draw_callback(obj, sym, argc, argv); + plugdata_draw_callback(obj, layer, sym, argc, argv); } } static inline void plugdata_draw_path(t_symbol* sym, int argc, t_atom* argv) { if(plugdata_draw_callback) { - plugdata_draw_callback(NULL, sym, argc, argv); + plugdata_draw_callback(NULL, -1, sym, argc, argv); } } @@ -275,7 +275,7 @@ static int set_size(lua_State* L) t_atom args[2]; SETFLOAT(args, obj->gfx.width); // w SETFLOAT(args + 1, obj->gfx.height); // h - plugdata_draw(obj, gensym("lua_resized"), 2, args); + plugdata_draw(obj, -1, gensym("lua_resized"), 2, args); return 0; } @@ -286,26 +286,21 @@ static int start_paint(lua_State* L) { } t_pdlua *obj = (t_pdlua*)lua_touserdata(L, 1); int layer = luaL_checknumber(L, 2); - t_atom layer_atom; - SETFLOAT(&layer_atom, layer); lua_pushlightuserdata(L, &obj->gfx); luaL_setmetatable(L, "GraphicsContext"); plugdata_draw_callback = obj->gfx.plugdata_draw_callback; - plugdata_draw(obj, gensym("lua_start_paint"), 1, &layer_atom); + obj->gfx.current_layer = layer; + plugdata_draw(obj, obj->gfx.current_layer, gensym("lua_start_paint"), 0, NULL); return 1; } static int end_paint(lua_State* L) { t_pdlua_gfx *gfx = pop_graphics_context(L); t_pdlua *obj = gfx->object; - - int layer = luaL_checknumber(L, 1); - t_atom layer_atom; - SETFLOAT(&layer_atom, layer); - - plugdata_draw(obj, gensym("lua_end_paint"), 1, &layer_atom); + plugdata_draw(obj, gfx->current_layer, gensym("lua_end_paint"), 0, NULL); + gfx->current_layer = -1; return 0; } @@ -315,7 +310,7 @@ static int set_color(lua_State* L) { if (lua_gettop(L) == 1) { // Single argument: parse as color ID instead of RGB t_atom arg; SETFLOAT(&arg, luaL_checknumber(L, 1)); // color ID - plugdata_draw(obj, gensym("lua_set_color"), 1, &arg); + plugdata_draw(obj, gfx->current_layer, gensym("lua_set_color"), 1, &arg); return 0; } @@ -331,7 +326,7 @@ static int set_color(lua_State* L) { else { SETFLOAT(args + 3, 1.0f); } - plugdata_draw(obj, gensym("lua_set_color"), 4, args); + plugdata_draw(obj, gfx->current_layer, gensym("lua_set_color"), 4, args); return 0; } @@ -342,7 +337,7 @@ static int fill_ellipse(lua_State* L) { SETFLOAT(args + 1, luaL_checknumber(L, 2)); // y SETFLOAT(args + 2, luaL_checknumber(L, 3)); // w SETFLOAT(args + 3, luaL_checknumber(L, 4)); // h - plugdata_draw(gfx->object, gensym("lua_fill_ellipse"), 4, args); + plugdata_draw(gfx->object, gfx->current_layer, gensym("lua_fill_ellipse"), 4, args); return 0; } @@ -354,14 +349,14 @@ static int stroke_ellipse(lua_State* L) { SETFLOAT(args + 2, luaL_checknumber(L, 3)); // w SETFLOAT(args + 3, luaL_checknumber(L, 4)); // h SETFLOAT(args + 4, luaL_checknumber(L, 5)); // width - plugdata_draw(gfx->object, gensym("lua_stroke_ellipse"), 5, args); + plugdata_draw(gfx->object, gfx->current_layer, gensym("lua_stroke_ellipse"), 5, args); return 0; } static int fill_all(lua_State* L) { t_pdlua_gfx *gfx = pop_graphics_context(L); t_pdlua *obj = gfx->object; - plugdata_draw(obj, gensym("lua_fill_all"), 0, NULL); + plugdata_draw(obj, gfx->current_layer, gensym("lua_fill_all"), 0, NULL); return 0; } @@ -372,7 +367,7 @@ static int fill_rect(lua_State* L) { SETFLOAT(args + 1, luaL_checknumber(L, 2)); // y SETFLOAT(args + 2, luaL_checknumber(L, 3)); // w SETFLOAT(args + 3, luaL_checknumber(L, 4)); // h - plugdata_draw(gfx->object, gensym("lua_fill_rect"), 4, args); + plugdata_draw(gfx->object, gfx->current_layer, gensym("lua_fill_rect"), 4, args); return 0; } @@ -384,7 +379,7 @@ static int stroke_rect(lua_State* L) { SETFLOAT(args + 2, luaL_checknumber(L, 3)); // w SETFLOAT(args + 3, luaL_checknumber(L, 4)); // h SETFLOAT(args + 4, luaL_checknumber(L, 5)); // corner_radius - plugdata_draw(gfx->object, gensym("lua_stroke_rect"), 5, args); + plugdata_draw(gfx->object, gfx->current_layer, gensym("lua_stroke_rect"), 5, args); return 0; } @@ -396,7 +391,7 @@ static int fill_rounded_rect(lua_State* L) { SETFLOAT(args + 2, luaL_checknumber(L, 3)); // w SETFLOAT(args + 3, luaL_checknumber(L, 4)); // h SETFLOAT(args + 4, luaL_checknumber(L, 5)); // corner radius - plugdata_draw(gfx->object, gensym("lua_fill_rounded_rect"), 5, args); + plugdata_draw(gfx->object, gfx->current_layer, gensym("lua_fill_rounded_rect"), 5, args); return 0; } @@ -409,7 +404,7 @@ static int stroke_rounded_rect(lua_State* L) { SETFLOAT(args + 3, luaL_checknumber(L, 4)); // h SETFLOAT(args + 4, luaL_checknumber(L, 5)); // corner_radius SETFLOAT(args + 5, luaL_checknumber(L, 6)); // width - plugdata_draw(gfx->object, gensym("lua_stroke_rounded_rect"), 6, args); + plugdata_draw(gfx->object, gfx->current_layer, gensym("lua_stroke_rounded_rect"), 6, args); return 0; } @@ -421,7 +416,7 @@ static int draw_line(lua_State* L) { SETFLOAT(args + 2, luaL_checknumber(L, 3)); // w SETFLOAT(args + 3, luaL_checknumber(L, 4)); // h SETFLOAT(args + 4, luaL_checknumber(L, 5)); // line width - plugdata_draw(gfx->object, gensym("lua_draw_line"), 5, args); + plugdata_draw(gfx->object, gfx->current_layer, gensym("lua_draw_line"), 5, args); return 0; } @@ -435,7 +430,7 @@ static int draw_text(lua_State* L) { SETFLOAT(args + 2, luaL_checknumber(L, 3)); // y SETFLOAT(args + 3, luaL_checknumber(L, 4)); // w SETFLOAT(args + 4, luaL_checknumber(L, 5)); // h - plugdata_draw(gfx->object, gensym("lua_draw_text"), 5, args); + plugdata_draw(gfx->object, gfx->current_layer, gensym("lua_draw_text"), 5, args); return 0; } @@ -457,7 +452,7 @@ static int stroke_path(lua_State* L) { SETFLOAT(coordinates + (i * 2) + 2, y); } - plugdata_draw(gfx->object, gensym("lua_stroke_path"), path->num_path_segments * 2 + 1, coordinates); + plugdata_draw(gfx->object, gfx->current_layer, gensym("lua_stroke_path"), path->num_path_segments * 2 + 1, coordinates); free(coordinates); return 0; @@ -479,7 +474,7 @@ static int fill_path(lua_State* L) { SETFLOAT(coordinates + (i * 2) + 1, y); } - plugdata_draw(gfx->object, gensym("lua_fill_path"), path->num_path_segments * 2, coordinates); + plugdata_draw(gfx->object, gfx->current_layer, gensym("lua_fill_path"), path->num_path_segments * 2, coordinates); free(coordinates); return 0; @@ -492,7 +487,7 @@ static int translate(lua_State* L) { t_atom args[2]; SETFLOAT(args, luaL_checknumber(L, 1)); // tx SETFLOAT(args + 1, luaL_checknumber(L, 2)); // ty - plugdata_draw(obj, gensym("lua_translate"), 2, args); + plugdata_draw(obj, gfx->current_layer, gensym("lua_translate"), 2, args); return 0; } @@ -502,14 +497,14 @@ static int scale(lua_State* L) { t_atom args[2]; SETFLOAT(args, luaL_checknumber(L, 1)); // sx SETFLOAT(args + 1, luaL_checknumber(L, 2)); // sy - plugdata_draw(obj, gensym("lua_scale"), 2, args); + plugdata_draw(obj, gfx->current_layer, gensym("lua_scale"), 2, args); return 0; } static int reset_transform(lua_State* L) { t_pdlua_gfx *gfx = pop_graphics_context(L); t_pdlua *obj = gfx->object; - plugdata_draw(obj, gensym("lua_reset_transform"), 0, NULL); + plugdata_draw(obj, gfx->current_layer, gensym("lua_reset_transform"), 0, NULL); return 0; } #else From 868250d1964591cba826669e408285d52e14cf28 Mon Sep 17 00:00:00 2001 From: Timothy Schoen Date: Fri, 27 Sep 2024 01:54:10 +0200 Subject: [PATCH 04/21] Fix bug in pd-vanilla implementation --- Makefile | 2 +- pdlua_gfx.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 4d35806..739aeb1 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ luaflags += -DLUA_USE_WINDOWS endef endif -cflags = ${luaflags} -DPDLUA_VERSION="$(pdlua_version)" -fsanitize=address -g +cflags = ${luaflags} -DPDLUA_VERSION="$(pdlua_version)" pdlua.class.sources := pdlua.c $(luasrc) pdlua.class.ldlibs := $(lualibs) diff --git a/pdlua_gfx.h b/pdlua_gfx.h index 43c00fd..9d7a1c0 100644 --- a/pdlua_gfx.h +++ b/pdlua_gfx.h @@ -812,7 +812,9 @@ static int start_paint(lua_State* L) { int layer = luaL_checknumber(L, 2); if(layer >= gfx->num_layers) { - gfx->layer_tags = resizebytes(gfx->layer_tags, sizeof(char*) * gfx->num_layers, sizeof(char*) * ++gfx->num_layers); + int new_num_layers = layer + 1; + gfx->layer_tags = resizebytes(gfx->layer_tags, sizeof(char*) * gfx->num_layers, sizeof(char*) * new_num_layers); + gfx->num_layers = new_num_layers; gfx->layer_tags[layer] = malloc(64); snprintf(gfx->layer_tags[layer], 64, ".l%i%lx", layer, (long)obj); } From ea2210c06cd0ff5dad2fed5bd4014177309078bd Mon Sep 17 00:00:00 2001 From: Timothy Schoen Date: Fri, 27 Sep 2024 03:41:57 +0200 Subject: [PATCH 05/21] Don't use reserved C++ keyword in header --- pdlua.c | 4 ++-- pdlua.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pdlua.c b/pdlua.c index df2d07b..d1ece3e 100644 --- a/pdlua.c +++ b/pdlua.c @@ -990,7 +990,7 @@ static void pdlua_menu_open(t_pdlua *o) PDLUA_DEBUG3("pdlua_menu_open: L is %p, name is %s stack top is %d", __L(), name, lua_gettop(__L())); if (name && *name) // `pdluax` without argument gives empty script name { - class = o->class; + class = o->pdlua_class; if (!class) { lua_pop(__L(), 2); /* pop name, global "pd"*/ return; @@ -1385,7 +1385,7 @@ static int pdlua_object_new(lua_State *L) o->sigoutlets = 0; o->sig_warned = 0; o->canvas = canvas_getcurrent(); - o->class = c; + o->pdlua_class = c; o->class_gfx = c_gfx; o->gfx.width = 80; diff --git a/pdlua.h b/pdlua.h index d403856..eeade36 100644 --- a/pdlua.h +++ b/pdlua.h @@ -67,7 +67,7 @@ typedef struct pdlua t_canvas *canvas; // The canvas that the object was created on. int has_gui; // True if graphics are enabled. t_pdlua_gfx gfx; // Holds state for graphics. - t_class *class; // Holds our class pointer. + t_class *pdlua_class; // Holds our class pointer. t_class *class_gfx; // Holds our gfx class pointer. } t_pdlua; From f8e94a390c15f532b08f29cf12874abe410f1904 Mon Sep 17 00:00:00 2001 From: Timothy Schoen Date: Sun, 29 Sep 2024 17:21:51 +0200 Subject: [PATCH 06/21] Fix broken layer indexing --- pdlua_gfx.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pdlua_gfx.h b/pdlua_gfx.h index 60ff4e1..597ea59 100644 --- a/pdlua_gfx.h +++ b/pdlua_gfx.h @@ -291,6 +291,7 @@ static int start_paint(lua_State* L) { plugdata_draw_callback = obj->gfx.plugdata_draw_callback; obj->gfx.current_layer = layer; + obj->gfx.object = obj; plugdata_draw(obj, obj->gfx.current_layer, gensym("lua_start_paint"), 0, NULL); return 1; } @@ -770,7 +771,7 @@ static int gfx_initialize(t_pdlua *obj) gfx->object = obj; gfx->transforms = NULL; gfx->num_transforms = 0; - gfx->num_layers = 1; + gfx->num_layers = 0; gfx->layer_tags = malloc(sizeof(char*)); pdlua_gfx_repaint(obj, 0); @@ -808,7 +809,7 @@ static int start_paint(lua_State* L) { return 1; } - int layer = luaL_checknumber(L, 2); + int layer = luaL_checknumber(L, 2) - 1; if(layer >= gfx->num_layers) { int new_num_layers = layer + 1; @@ -890,7 +891,7 @@ static int end_paint(lua_State* L) { t_canvas *cnv = glist_getcanvas(obj->canvas); int scale = glist_getzoom(glist_getcanvas(obj->canvas)); - int layer = luaL_checknumber(L, 1); + int layer = luaL_checknumber(L, 1) - 1; // Draw iolets on top int xpos = text_xpix((t_object*)obj, obj->canvas); @@ -904,7 +905,7 @@ static int end_paint(lua_State* L) { // Move everything to below the order marker, to make sure redrawn stuff isn't always on top pdgui_vmess(0, "crss", cnv, "lower", gfx->object_tag, gfx->order_tag); - if(layer == 1) + if(layer == 0 && gfx->num_layers > 1) { if(layer < gfx->num_layers) pdgui_vmess(0, "crss", cnv, "lower", gfx->current_layer_tag, gfx->layer_tags[layer + 1]); } From 702163cf63b3940f7160490d0ed36307cd25f6a5 Mon Sep 17 00:00:00 2001 From: Timothy Schoen Date: Mon, 30 Sep 2024 03:29:45 +0200 Subject: [PATCH 07/21] Fix error message due to incorrect layer clearing --- pdlua.c | 2 +- pdlua_gfx.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pdlua.c b/pdlua.c index d1ece3e..a1b6409 100644 --- a/pdlua.c +++ b/pdlua.c @@ -750,7 +750,7 @@ void pdlua_vis(t_gobj *z, t_glist *glist, int vis){ pdlua_gfx_repaint(x, 1); } else { - pdlua_gfx_clear(x, 0, 1); + pdlua_gfx_clear(x, -1, 1); } } diff --git a/pdlua_gfx.h b/pdlua_gfx.h index 597ea59..4e8492a 100644 --- a/pdlua_gfx.h +++ b/pdlua_gfx.h @@ -693,7 +693,7 @@ static void pdlua_gfx_clear(t_pdlua *obj, int layer, int removed) { t_pdlua_gfx *gfx = &obj->gfx; t_canvas *cnv = glist_getcanvas(obj->canvas); #ifndef PURR_DATA - pdgui_vmess(0, "crs", cnv, "delete", layer == 0 ? gfx->object_tag : gfx->layer_tags[layer]); + pdgui_vmess(0, "crs", cnv, "delete", layer == -1 ? gfx->object_tag : gfx->layer_tags[layer]); if(removed && gfx->order_tag[0] != '\0') { From 01332c52bb89de29c5c992bf6940b928b703cdf5 Mon Sep 17 00:00:00 2001 From: Timothy Schoen Date: Mon, 30 Sep 2024 19:25:17 +0200 Subject: [PATCH 08/21] Fix hang when opening pdlua patch and drawing instantly --- pd.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pd.lua b/pd.lua index a577cd1..bc12c40 100644 --- a/pd.lua +++ b/pd.lua @@ -481,7 +481,10 @@ function pd.Class:repaint(layer) self[paint_layer_method](self, g) _gfx_internal.end_paint(g, i) i = i + 1 + else + break; end + else break -- Exit the loop when no more paint_layer_X methods are found end From 52d831ef410527d0b52ab86abbbfa8cecc136543 Mon Sep 17 00:00:00 2001 From: Timothy Schoen Date: Mon, 30 Sep 2024 19:46:51 +0200 Subject: [PATCH 09/21] Only repaint layers after initial repaint has happened --- pdlua_gfx.h | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/pdlua_gfx.h b/pdlua_gfx.h index 4e8492a..8f316e6 100644 --- a/pdlua_gfx.h +++ b/pdlua_gfx.h @@ -693,7 +693,10 @@ static void pdlua_gfx_clear(t_pdlua *obj, int layer, int removed) { t_pdlua_gfx *gfx = &obj->gfx; t_canvas *cnv = glist_getcanvas(obj->canvas); #ifndef PURR_DATA - pdgui_vmess(0, "crs", cnv, "delete", layer == -1 ? gfx->object_tag : gfx->layer_tags[layer]); + + if(layer < gfx->num_layers) { + pdgui_vmess(0, "crs", cnv, "delete", layer == -1 ? gfx->object_tag : gfx->layer_tags[layer]); + } if(removed && gfx->order_tag[0] != '\0') { @@ -808,17 +811,6 @@ static int start_paint(lua_State* L) { lua_pushnil(L); return 1; } - - int layer = luaL_checknumber(L, 2) - 1; - if(layer >= gfx->num_layers) - { - int new_num_layers = layer + 1; - gfx->layer_tags = resizebytes(gfx->layer_tags, sizeof(char*) * gfx->num_layers, sizeof(char*) * new_num_layers); - gfx->num_layers = new_num_layers; - gfx->layer_tags[layer] = malloc(64); - snprintf(gfx->layer_tags[layer], 64, ".l%i%lx", layer, (long)obj); - } - gfx->current_layer_tag = gfx->layer_tags[layer]; #ifdef PURR_DATA if (gfx->object_tag[0] == '*') { @@ -843,6 +835,17 @@ static int start_paint(lua_State* L) { int can_draw = (glist_isvisible(obj->canvas) && gobj_shouldvis(&obj->pd.te_g, obj->canvas)) || obj->gfx.first_draw; if(can_draw) { + int layer = luaL_checknumber(L, 2) - 1; + if(layer >= gfx->num_layers) + { + int new_num_layers = layer + 1; + gfx->layer_tags = resizebytes(gfx->layer_tags, sizeof(char*) * gfx->num_layers, sizeof(char*) * new_num_layers); + gfx->num_layers = new_num_layers; + gfx->layer_tags[layer] = malloc(64); + snprintf(gfx->layer_tags[layer], 64, ".l%i%lx", layer, (long)obj); + } + gfx->current_layer_tag = gfx->layer_tags[layer]; + if(gfx->transforms) freebytes(gfx->transforms, gfx->num_transforms * sizeof(gfx_transform)); gfx->num_transforms = 0; gfx->transforms = NULL; From db889e360ce9b7a0c4d8704e98e9fdfe374658f5 Mon Sep 17 00:00:00 2001 From: Ben Wesch Date: Mon, 30 Sep 2024 07:53:42 +0200 Subject: [PATCH 10/21] class_gfx -> pdlua_class_gfx --- pdlua.c | 8 ++++---- pdlua.h | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/pdlua.c b/pdlua.c index a1b6409..f73090d 100644 --- a/pdlua.c +++ b/pdlua.c @@ -1386,7 +1386,7 @@ static int pdlua_object_new(lua_State *L) o->sig_warned = 0; o->canvas = canvas_getcurrent(); o->pdlua_class = c; - o->class_gfx = c_gfx; + o->pdlua_class_gfx = c_gfx; o->gfx.width = 80; o->gfx.height = 80; @@ -1416,7 +1416,7 @@ static int pdlua_object_creategui(lua_State *L) t_pdlua *o = lua_touserdata(L, 1); t_text *x = (t_text*)o; int reinit = lua_tonumber(L, 2); - if (!o->class_gfx) return 0; // we're not supposed to be here... + if (!o->pdlua_class_gfx) return 0; // we're not supposed to be here... // We may need to redraw the object in case it's been reloaded, to get the // iolets and patch cords fixed. int redraw = reinit && o->pd.te_binbuf && gobj_shouldvis(&o->pd.te_g, o->canvas) && glist_isvisible(o->canvas); @@ -1427,9 +1427,9 @@ static int pdlua_object_creategui(lua_State *L) // We need to switch classes mid-flight here. This is a bit of a hack, but // we want to retain the standard text widgetbehavior for regular // (non-gui) objects. As soon as we create the gui here, we switch over to - // o->class_gfx, which is an exact clone of o->class, except that it has + // o->pdlua_class_gfx, which is an exact clone of o->pdlua_class, except that it has // our custom widgetbehavior for gui objects. - x->te_pd = o->class_gfx; + x->te_pd = o->pdlua_class_gfx; gfx_initialize(o); if (redraw) { // force object and its iolets to be redrawn diff --git a/pdlua.h b/pdlua.h index eeade36..06c01df 100644 --- a/pdlua.h +++ b/pdlua.h @@ -55,20 +55,20 @@ typedef struct _pdlua_gfx /** Pd object data. */ typedef struct pdlua { - t_object pd; // We are a Pd object. - int inlets; // Number of inlets. - struct pdlua_proxyinlet *proxy_in; // The inlets themselves. + t_object pd; // We are a Pd object. + int inlets; // Number of inlets. + struct pdlua_proxyinlet *proxy_in; // The inlets themselves. t_inlet **in; - int outlets; // Number of outlets. - t_outlet **out; // The outlets themselves. - int siginlets; // Number of signal inlets. - int sigoutlets; // Number of signal outlets. - int sig_warned; // Flag for perform signal errors. - t_canvas *canvas; // The canvas that the object was created on. - int has_gui; // True if graphics are enabled. - t_pdlua_gfx gfx; // Holds state for graphics. + int outlets; // Number of outlets. + t_outlet **out; // The outlets themselves. + int siginlets; // Number of signal inlets. + int sigoutlets; // Number of signal outlets. + int sig_warned; // Flag for perform signal errors. + t_canvas *canvas; // The canvas that the object was created on. + int has_gui; // True if graphics are enabled. + t_pdlua_gfx gfx; // Holds state for graphics. t_class *pdlua_class; // Holds our class pointer. - t_class *class_gfx; // Holds our gfx class pointer. + t_class *pdlua_class_gfx; // Holds our gfx class pointer. } t_pdlua; lua_State* __L(); From a04eab1639f391cdd6ee6b80be86bef94eac0010 Mon Sep 17 00:00:00 2001 From: Ben Wesch Date: Mon, 30 Sep 2024 20:07:30 +0200 Subject: [PATCH 11/21] hello-gui with separate layers --- pdlua/hello-gui.pd_lua | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/pdlua/hello-gui.pd_lua b/pdlua/hello-gui.pd_lua index e760341..affd987 100644 --- a/pdlua/hello-gui.pd_lua +++ b/pdlua/hello-gui.pd_lua @@ -60,7 +60,7 @@ function hello:mouse_drag(x, y) self.draggable_rect_y = self.rect_down_pos[1] + (y - self.mouse_down_pos[1]) self.draggable_rect_x = math.clamp(self.draggable_rect_x, 0, 620 - self.draggable_rect_size) self.draggable_rect_y = math.clamp(self.draggable_rect_y, 0, 230 - self.draggable_rect_size) - self:repaint() + self:repaint(3) end end @@ -144,12 +144,6 @@ function hello:paint(g) g:fill_path(curve2) g:reset_transform() - -- Draggable rectangle - g:set_color(66, 207, 201, 1) - g:fill_rounded_rect(self.draggable_rect_x, self.draggable_rect_y, self.draggable_rect_size, self.draggable_rect_size, 5) - g:set_color(0, 0, 0, 1) - g:draw_text("Drag\n me!", self.draggable_rect_x + 8, self.draggable_rect_y + 10, self.draggable_rect_size, 12) - -- Titles g:set_color(252, 118, 81, 1) g:draw_text("Ellipse", 25, 190, 120, 12) @@ -159,17 +153,27 @@ function hello:paint(g) g:draw_text("Bezier Paths", 360, 190, 120, 12) g:draw_text("Animation", 460, 190, 120, 12) g:draw_text(" Mouse\nInteraction", 540, 190, 120, 12) +end +function hello:paint_layer_2(g) g:set_color(250, 84, 108, 1) g:fill_ellipse(self.circle_x, self.circle_y, self.circle_radius, self.circle_radius) end +function hello:paint_layer_3(g) + -- Draggable rectangle + g:set_color(66, 207, 201, 1) + g:fill_rounded_rect(self.draggable_rect_x, self.draggable_rect_y, self.draggable_rect_size, self.draggable_rect_size, 5) + g:set_color(0, 0, 0, 1) + g:draw_text("Drag\n me!", self.draggable_rect_x + 8, self.draggable_rect_y + 10, self.draggable_rect_size, 12) +end + function hello:tick() self.circle_y = self.circle_y + self.animation_speed if self.circle_y > 160 + self.circle_radius then self.circle_y = -self.circle_radius end - self:repaint() + self:repaint(2) self.clock:delay(self.delay_time) end From b201390199e6cfd0f9e7e7fbc052aef5f4a014a6 Mon Sep 17 00:00:00 2001 From: Ben Wesch Date: Mon, 30 Sep 2024 22:20:21 +0200 Subject: [PATCH 12/21] update graphics.txt and help --- doc/graphics.txt | 9 ++++++--- pdlua-help.pd | 44 ++++++++++++++++++++++++++------------------ 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/doc/graphics.txt b/doc/graphics.txt index 20928ef..bd8a401 100644 --- a/doc/graphics.txt +++ b/doc/graphics.txt @@ -36,8 +36,11 @@ pd:Class:mouse_move(x, y) -- Mouse move cal pd:Class:mouse_drag(x, y) -- Mouse drag callback, called when the mouse is moved while also being down -- Functions you can call -pd:Class:repaint() -- Request a repaint, after this the "paint" callback will occur -pd:Class:paint(g) -- Paint callback, returns a graphics_context object (commonly called g) that you can call these drawing functions on: +pd:Class:repaint(layer) -- Request a repaint for specified layer (or all layers if no parameter is set + or if layer is 0). after this, the "paint" or "paint_layer_n" callback will occur + +pd:Class:paint(g) / pd:Class:paint_layer_n(g) -- Paint callback, returns a graphics_context object (commonly called g) for main + layer or layer n (n > 1) that you can call these drawing functions on: g:set_size(w, h) -- Sets the size of the object width, height = g:get_size(w, h) -- Gets the size of the object @@ -74,7 +77,7 @@ g:fill_path(p) -- Fills the curr -- Additional functions expandedsymbol = pd:Class:canvas_realizedollar(s) -- Expand dollar symbols in patch canvas context pd:Class:set_args(args) -- Set the object arguments to be saved in the patch file -pd:Class:get_args() -- Get the object arguments to be saved in the patch file +args = pd:Class:get_args() -- Get the object arguments Basic example diff --git a/pdlua-help.pd b/pdlua-help.pd index d6b3a6c..6557144 100644 --- a/pdlua-help.pd +++ b/pdlua-help.pd @@ -90,15 +90,9 @@ #X text 90 2044 self:dofile("filename"); #X text 90 2088 self:error("message"); #X text 90 2188 pd.post("a string"); -#X obj 514 1698 bng 20 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; -#X floatatom 632 1814 3 0 0 0 - - - 0; #X text 66 1821 See doc/examples/lreceive.pd_lua for details.; #X text 81 1738 See doc/examples/lsend.pd_lua for details.; #X text 66 1937 See doc/examples/ldelay.pd_lua for details.; -#X obj 514 1730 lsend splat-1; -#X obj 549 1705 lsend splat-2; -#X obj 509 1784 lreceive splat- 1 2 3; -#X obj 534 1930 ldelay 1000; #X text 65 1054 Each inlet should have at least one method that will be called when an item it can handle arrives at that input.; #X obj 91 1139 cnv 15 300 50 empty empty empty 20 12 0 14 #ffffff #404040 0; #X text 98 1143 function foo:in_1_float(f); @@ -137,13 +131,6 @@ #X text 97 1388 -- code; #X text 99 1401 end; #X text 98 1375 function foo:in_n_symbol(i \, s); -#X obj 509 1814 route bang float; -#X obj 509 1841 bng 20 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; -#X floatatom 555 1844 5 0 0 0 - - - 0; -#X msg 549 1672 100; -#X msg 587 1672 1000; -#X obj 534 1900 bng 20 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; -#X obj 534 1955 bng 20 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; #X obj 46 2226 cnv 17 450 20 empty empty empty 20 12 0 14 #cccccc #404040 0; #X text 71 2229 (modified from doc/examples/pdlua/lua.txt by mrpeach 2011/10/06), f 64; #N canvas 0 22 450 278 (subpatch) 0; @@ -161,10 +148,30 @@ #X text 69 16 Find basic instructions/examples below on how to write externals in Lua. For further details \, see 'pd-lua-intro.pdf' in the 'pdlua/tutorial' folder. You can also find this tutorial online at: https://agraef.github.io/pd-lua/tutorial/pd-lua-intro.html, f 66; #X obj 515 1624 declare -path pdlua/examples; #X text 549 1602 Examples from:; -#X connect 107 0 108 0; -#X connect 110 0 65 0; +#X obj 514 1698 bng 20 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; +#X floatatom 632 1814 3 0 0 0 - - - 0; +#X obj 514 1730 lsend splat-1; +#X obj 549 1705 lsend splat-2; +#X obj 509 1784 lreceive splat- 1 2 3; +#X obj 534 1930 ldelay 1000; +#X obj 509 1814 route bang float; +#X obj 509 1841 bng 20 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; +#X floatatom 555 1844 5 0 0 0 - - - 0; +#X msg 549 1672 100; +#X obj 534 1900 bng 20 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; +#X msg 587 1672 1000; +#X obj 534 1955 bng 20 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; +#X connect 107 0 109 0; +#X connect 111 0 113 0; +#X connect 111 1 108 0; +#X connect 112 0 119 0; +#X connect 113 0 114 0; +#X connect 113 1 115 0; +#X connect 116 0 110 0; +#X connect 117 0 112 0; +#X connect 118 0 110 0; #X restore 446 359 pd quickstart; -#N canvas 106 35 1079 707 graphics 0; +#N canvas 264 71 852 728 graphics 0; #X obj 8 77 hello-gui; #X text 8 376 function yourclass:initialize(sel \, atoms); #X text 24 409 return true; @@ -185,8 +192,9 @@ #X text 25 543 g:fill_all(); #X text 8 323 Graphics mode is enabled automatically by defining the paint method \, see below. You can also set the size in the constructor (or in any other function) \, like this:; #X text 23 394 self:set_size(100 \, 100); -#X text 8 816 pd:Class:mouse_down(x \, y) \; pd:Class:mouse_up(x \, y) \; pd:Class:mouse_move(x \, y) \; pd:Class:mouse_drag(x \, y) \; \; pd:Class:set_size(w \, h) \; width \, height = pd:Class:get_size() \; \; pd:Class:repaint() \; pd:Class:paint(g) \; \; g:set_color(r \, g \, b \, a=1.0) \; \; g:fill_ellipse(x \, y \, w \, h) \; g:stroke_ellipse(x \, y \, w \, h \, line_width) \; g:fill_rect(x \, y \, w \, h) \; g:stroke_rect(x \, y \, w \, h \, line_width) \; g:fill_rounded_rect(x \, y \, w \, h \, corner_radius) \; g:stroke_rounded_rect(x \, y \, w \, h \, corner_radius \, line_width) \; \; g:draw_line(x1 \, y1 \, x2 \, y2) \; g:draw_text(text \, x \, y \, w \, fontsize) \; \; g:fill_all() \; \; g:translate(tx \, ty) \; g:scale(sx \, sy) \; g:reset_transform() \; \; p = Path(x \, y) \; p:line_to(x \, y) \; p:quad_to(x1 \, y1 \, x2 \, y2) \; p:cubic_to(x1 \, y1 \, x2 \, y2 \, x3 \, y) \; p:close_path() \; \; g:stroke_path(p \, line_width) \; g:fill_path(p) \;, f 58; -#X text 373 818 -- Mouse down callback \, called when the mouse is clicked \; -- Mouse up callback \, called when the mouse button is released \; -- Mouse move callback \, called when the mouse is moved while not being down \; -- Mouse drag callback \, called when the mouse is moved while also being down \; \; -- Set object size \; -- Get object size \; \; -- Request a repaint \, after this the "paint" callback will occur \; -- Paint callback The argument "g" is the graphics context that you can call these drawing functions on: \; -- Sets the color for the next drawing operation. Colors are in range 0-255 \, optional alpha is in range 0-1 \; \; -- Draws a filled ellipse at the specified position and size. \; -- Draws the outline of an ellipse at the specified position and size. \; -- Draws a filled rectangle at the specified position and size. \; -- Draws the outline of a rectangle at the specified position and size. \; -- Draws a filled rounded rectangle at the specified position and size. \; -- Draws the outline of a rounded rectangle at the specified position and size. \; \; \; -- Draws a line between two points. \; -- Draws text at the specified position and size. \; \; -- Fills the entire drawing area with the current color. Also will draw an object outline in the style of the host (ie. pure-data or plugdata) \; \; -- Translates the coordinate system by the specified amounts. \; -- Scales the coordinate system by the specified factors. This will always happen after the translation \; -- Resets current scale and translation \; \; -- Initiates a new path at the specified point. \; -- Adds a line segment to the current path. \; -- Adds a quadratic Bezier curve to the current path. \; -- Adds a cubic Bezier curve to the current path. \; -- Closes the current path. \; \; -- Draws the outline of the current path with the specified line width. \; -- Fills the current path. \;, f 115; +#X text 801 1407  ; +#X text 8 816 -- Callback functions you can define \; pd:Class:mouse_down(x \, y) \; pd:Class:mouse_up(x \, y) \; pd:Class:mouse_move(x \, y) \; pd:Class:mouse_drag(x \, y) \; \; \; -- Functions you can call \; pd:Class:repaint(layer) \; \; \; pd:Class:paint(g) / pd:Class:paint_layer_n(g) \; \; \; g:set_size(w \, h) \; width \, height = g:get_size(w \, h) \; \; g:set_color(r \, g \, b \, a=1.0) \; \; g:fill_ellipse(x \, y \, w \, h) \; g:stroke_ellipse(x \, y \, w \, h \, line_width) \; \; g:fill_rect(x \, y \, w \, h) \; g:stroke_rect(x \, y \, w \, h \, line_width) \; \; g:fill_rounded_rect(x \, y \, w \, h \, corner_radius) \; g:stroke_rounded_rect(x \, y \, w \, h \, corner_radius \, line_width) \; \; g:draw_line(x1 \, y1 \, x2 \, y2) \; g:draw_text(text \, x \, y \, w \, fontsize) \; \; g:fill_all() \; \; g:translate(tx \, ty) \; g:scale(sx \, sy) \; \; g:reset_transform() \; \; p = Path(x \, y) \; p:line_to(x \, y) \; p:quad_to(x1 \, y1 \, x2 \, y2) \; p:cubic_to(x1 \, y1 \, x2 \, y2 \, x3 \, y) \; p:close_path() \; \; g:stroke_path(p \, line_width) \; g:fill_path(p) \; \; \; -- Additional functions \; expandedsymbol = pd:Class:canvas_realizedollar(s) \; pd:Class:set_args(args) \; args = pd:Class:get_args() \;, f 51; +#X text 320 816 \; -- Mouse down callback \, called when the mouse is clicked \; -- Mouse up callback \, called when the mouse button is released \; -- Mouse move callback \, called when the mouse is moved while not being down \; -- Mouse drag callback \, called when the mouse is moved while also being down \; \; \; \; -- Request a repaint for specified layer (or all layers if no parameter is set or if layer is 0). after this \, the "paint" or "paint_layer_n" callback will occur \; \; -- Paint callback \, returns a graphics_context object (commonly called g) for main layer or layer n (n > 1) that you can call these drawing functions on: \; \; -- Sets the size of the object \; -- Gets the size of the object \; \; -- Sets the color for the next drawing operation \; \; -- Draws a filled ellipse at the specified position and size \; -- Draws the outline of an ellipse at the specified position and size \; \; -- Draws a filled rectangle at the specified position and size \; -- Draws the outline of a rectangle at the specified position and size \; \; -- Draws a filled rounded rectangle at the specified position and size \; -- Draws the outline of a rounded rectangle at the specified position and size \; \; \; -- Draws a line between two points \; -- Draws text at the specified position and size \; \; -- Fills the entire drawing area with the current color. Also will draw an object outline in the style of the host (ie. pure-data or plugdata) \; -- Translates the coordinate system by the specified amounts \; -- Scales the coordinate system by the specified factors. This will always happen after the translation \; -- Resets current scale and translation \; \; -- Initiates a new path at the specified point \; -- Adds a line segment to the path \; -- Adds a quadratic Bezier curve to the path \; -- Adds a cubic Bezier curve to the path \; -- Closes the path \; \; -- Draws the outline of the path with the specified line width \; -- Fills the current path \; \; \; \; -- Expand dollar symbols in patch canvas context \; -- Set the object arguments to be saved in the patch file \; -- Get the object arguments \;, f 81; #X restore 446 409 pd graphics; #X text 324 384 Details on how to create GUI objects ------->, f 18; #X obj 342 247 hello; From 6627d559a7d98732e09600f119b27732a5b479a9 Mon Sep 17 00:00:00 2001 From: alcomposer Date: Tue, 1 Oct 2024 15:38:54 +0930 Subject: [PATCH 13/21] Fix compile for msvc --- pdlua.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pdlua.c b/pdlua.c index a1b6409..ccfd132 100644 --- a/pdlua.c +++ b/pdlua.c @@ -32,15 +32,18 @@ #include // for open #include // for open #ifdef _MSC_VER -#include -#include // for open -#define read _read -#define close _close -#define ssize_t int -#define snprintf _snprintf + #include + #include // for open + #ifndef PATH_MAX + #define PATH_MAX 1024 /* same with Mac OS X's syslimits.h */ + #endif + #define read _read + #define close _close + #define ssize_t int + #define snprintf _snprintf #else -#include // for open -#include + #include // for open + #include #endif /* we use Lua */ #include @@ -180,9 +183,6 @@ void initialise_lua_state() # define PDLUA_DEBUG3 PDLUA_DEBUG #endif -EXTERN int sys_trytoopenone(const char *dir, const char *name, const char* ext, - char *dirresult, char **nameresult, unsigned int size, int bin); - // In plugdata we're linked statically and thus c_externdir is empty. // So we pass a data directory to the setup function instead and store it here. // ag: Renamed to pdlua_datadir since we also need this in vanilla when From 4180dd3a606b5576908a548ce34e1182d86181ad Mon Sep 17 00:00:00 2001 From: Timothy Schoen Date: Wed, 2 Oct 2024 18:02:13 +0200 Subject: [PATCH 14/21] Fix tags issue --- pdlua_gfx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdlua_gfx.h b/pdlua_gfx.h index 8f316e6..ce5e2ca 100644 --- a/pdlua_gfx.h +++ b/pdlua_gfx.h @@ -1206,7 +1206,7 @@ static int draw_line(lua_State* L) { #ifndef PURR_DATA pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "line", x1, y1, x2, y2, - "-width", line_width, "-fill", gfx->current_color, "-tags", 2, tags); + "-width", line_width, "-fill", gfx->current_color, "-tags", 3, tags); #else // PURR_DATA int x0 = text_xpix((t_object*)obj, obj->canvas); int y0 = text_ypix((t_object*)obj, obj->canvas); @@ -1289,7 +1289,7 @@ static int stroke_path(lua_State* L) { const char* tags[] = { gfx->object_tag, register_drawing(gfx), gfx->current_layer_tag }; #ifndef PURR_DATA - pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "line", 0, 0, 0, 0, "-width", stroke_width, "-fill", gfx->current_color, "-tags", 2, tags); + pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "line", 0, 0, 0, 0, "-width", stroke_width, "-fill", gfx->current_color, "-tags", 3, tags); sys_vgui(".x%lx.c coords %s", cnv, tags[1]); for (int i = 0; i < path->num_path_segments; i++) { From de7e6fdda1c6c44ff0509d857a4a49496c2dad1e Mon Sep 17 00:00:00 2001 From: Timothy Schoen Date: Thu, 3 Oct 2024 14:04:59 +0200 Subject: [PATCH 15/21] Fix plugdata compatibility --- pdlua.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pdlua.c b/pdlua.c index 4a5cd10..1313266 100644 --- a/pdlua.c +++ b/pdlua.c @@ -1314,9 +1314,8 @@ static int pdlua_class_new(lua_State *L) // Let plugdata know this class is a lua object #if PLUGDATA - // XXXFIXME: @timothyschoen: Not sure whether plugdata needs to know about - // name_gfx, too? plugdata_register_class(name); + plugdata_register_class(name_gfx); #endif if (c) { @@ -2999,8 +2998,8 @@ void pdlua_setup(void) result = lua_pcall(__L(), 0, 0, 0); PDLUA_DEBUG ("pdlua lua_pcall returned %d", result); } - if (0 != result) - //if (lua_load(__L(), pdlua_reader, &reader, "pd.lua") || lua_pcall(__L(), 0, 0, 0)) + + if (lua_load(__L(), pdlua_reader, &reader, "pd.lua", NULL) || lua_pcall(__L(), 0, 0, 0)) { mylua_error(__L(), NULL, NULL); pd_error(NULL, "lua: loader will not be registered!"); From 696d227a20671ff99020c6e266dcac8849a72778 Mon Sep 17 00:00:00 2001 From: Timothy Schoen Date: Fri, 4 Oct 2024 14:14:46 +0200 Subject: [PATCH 16/21] Make sure layers indices can never be skipped in pd.lua --- pd.lua | 61 ++++++++++++++++++++++++++++------------------------------ 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/pd.lua b/pd.lua index bc12c40..c11bf7a 100644 --- a/pd.lua +++ b/pd.lua @@ -462,44 +462,41 @@ function pd.Class:canvas_realizedollar(s) end function pd.Class:repaint(layer) - if layer == nil or layer <= 1 then - if type(self.paint) == "function" then - local g = _gfx_internal.start_paint(self._object, 1); - if type(self.paint) == "function" and g ~= nil then - self:paint(g); - _gfx_internal.end_paint(g, 1); + local paint_funcs = {} + if type(self.paint) == "function" then + table.insert(paint_funcs, self.paint) + -- Check for layer paint functions + local i = 2 + while true do + local paint_layer_method = "paint_layer_" .. tostring(i) + if type(self[paint_layer_method]) == "function" then + table.insert(paint_funcs, self[paint_layer_method]) + i = i + 1; + else + break -- Exit the loop when no more paint_layer_X methods are found + end end - end end - if layer == nil or layer == 0 then - local i = 2 - while true do - local paint_layer_method = "paint_layer_" .. tostring(i) - if type(self[paint_layer_method]) == "function" then - local g = _gfx_internal.start_paint(self._object, i) - if g ~= nil then - self[paint_layer_method](self, g) - _gfx_internal.end_paint(g, i) - i = i + 1 - else - break; - end - + -- repaint all + if layer == nil or layer == 0 then + for i, paint_fn in ipairs(paint_funcs) do + local g = _gfx_internal.start_paint(self._object, i); + if type(paint_fn) == "function" and g ~= nil then + paint_fn(self, g); + _gfx_internal.end_paint(g, i); else - break -- Exit the loop when no more paint_layer_X methods are found + break; end end - end - if layer ~= nil and layer >= 2 then - local paint_layer_method = "paint_layer_" .. tostring(layer) - if type(self[paint_layer_method]) == "function" then - local g = _gfx_internal.start_paint(self._object, layer) - if g ~= nil then - self[paint_layer_method](self, g) - _gfx_internal.end_paint(g, layer) - end + -- repaint only chosen index + elseif layer <= #paint_funcs then + local g = _gfx_internal.start_paint(self._object, layer); + local paint_fn = paint_funcs[layer] + if type(paint_fn) == "function" and g ~= nil then + paint_fn(self, g); + _gfx_internal.end_paint(g, layer); end - end + end end function pd.Class:get_size() From a2d0e4e4bcc2ab8cdffb6da5dc0e2b5ee34ccf29 Mon Sep 17 00:00:00 2001 From: Timothy Schoen Date: Fri, 4 Oct 2024 14:49:45 +0200 Subject: [PATCH 17/21] Remove semicolons at end of lines in pd.lua --- pd.lua | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pd.lua b/pd.lua index c11bf7a..f96a5f2 100644 --- a/pd.lua +++ b/pd.lua @@ -95,7 +95,7 @@ end pd._repaint = function (object) local obj = pd._objects[object] if nil ~= obj and type(obj.repaint) == "function" then - obj:repaint(0); + obj:repaint(0) end end @@ -471,7 +471,7 @@ function pd.Class:repaint(layer) local paint_layer_method = "paint_layer_" .. tostring(i) if type(self[paint_layer_method]) == "function" then table.insert(paint_funcs, self[paint_layer_method]) - i = i + 1; + i = i + 1 else break -- Exit the loop when no more paint_layer_X methods are found end @@ -480,21 +480,21 @@ function pd.Class:repaint(layer) -- repaint all if layer == nil or layer == 0 then for i, paint_fn in ipairs(paint_funcs) do - local g = _gfx_internal.start_paint(self._object, i); + local g = _gfx_internal.start_paint(self._object, i) if type(paint_fn) == "function" and g ~= nil then - paint_fn(self, g); - _gfx_internal.end_paint(g, i); + paint_fn(self, g) + _gfx_internal.end_paint(g, i) else - break; + break end end -- repaint only chosen index elseif layer <= #paint_funcs then - local g = _gfx_internal.start_paint(self._object, layer); + local g = _gfx_internal.start_paint(self._object, layer) local paint_fn = paint_funcs[layer] if type(paint_fn) == "function" and g ~= nil then - paint_fn(self, g); - _gfx_internal.end_paint(g, layer); + paint_fn(self, g) + _gfx_internal.end_paint(g, layer) end end end From 0fbd1810b9cf8fc36dbde30b01c931acebc45004 Mon Sep 17 00:00:00 2001 From: Timothy Schoen Date: Fri, 4 Oct 2024 15:01:30 +0200 Subject: [PATCH 18/21] Fix memory leaks --- pdlua.c | 2 ++ pdlua_gfx.h | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/pdlua.c b/pdlua.c index 9eeb71a..c7f5160 100644 --- a/pdlua.c +++ b/pdlua.c @@ -1854,6 +1854,8 @@ static int pdlua_object_free(lua_State *L) if (o) { + pdlua_gfx_free(&o->gfx); + if(o->in) { for (i = 0; i < o->inlets; ++i) inlet_free(o->in[i]); diff --git a/pdlua_gfx.h b/pdlua_gfx.h index ce5e2ca..cfc87a7 100644 --- a/pdlua_gfx.h +++ b/pdlua_gfx.h @@ -83,6 +83,15 @@ static int free_path(lua_State* L); static void pdlua_gfx_clear(t_pdlua *obj, int layer, int removed); // only for pd-vanilla, to delete all tcl/tk items +void pdlua_gfx_free(t_pdlua_gfx *gfx) { + for(int i = 0; i < gfx->num_layers; i++) + { + free(gfx->layer_tags[i]); + } + free(gfx->layer_tags); + if(gfx->transforms) freebytes(gfx->transforms, gfx->num_transforms * sizeof(gfx_transform)); +} + // Trigger repaint callback in lua script void pdlua_gfx_repaint(t_pdlua *o, int firsttime) { #if !PLUGDATA @@ -775,7 +784,7 @@ static int gfx_initialize(t_pdlua *obj) gfx->transforms = NULL; gfx->num_transforms = 0; gfx->num_layers = 0; - gfx->layer_tags = malloc(sizeof(char*)); + gfx->layer_tags = NULL; pdlua_gfx_repaint(obj, 0); return 0; @@ -839,7 +848,11 @@ static int start_paint(lua_State* L) { if(layer >= gfx->num_layers) { int new_num_layers = layer + 1; - gfx->layer_tags = resizebytes(gfx->layer_tags, sizeof(char*) * gfx->num_layers, sizeof(char*) * new_num_layers); + if(gfx->layer_tags) + gfx->layer_tags = resizebytes(gfx->layer_tags, sizeof(char*) * gfx->num_layers, sizeof(char*) * new_num_layers); + else + gfx->layer_tags = malloc(sizeof(char*)); + gfx->num_layers = new_num_layers; gfx->layer_tags[layer] = malloc(64); snprintf(gfx->layer_tags[layer], 64, ".l%i%lx", layer, (long)obj); From 6da6c2e7ae479ec45fd0040311d8130e90a57e47 Mon Sep 17 00:00:00 2001 From: Timothy Schoen Date: Fri, 4 Oct 2024 15:10:51 +0200 Subject: [PATCH 19/21] No need to deallocate for plugdata --- pdlua_gfx.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pdlua_gfx.h b/pdlua_gfx.h index cfc87a7..3f39e2b 100644 --- a/pdlua_gfx.h +++ b/pdlua_gfx.h @@ -84,12 +84,14 @@ static int free_path(lua_State* L); static void pdlua_gfx_clear(t_pdlua *obj, int layer, int removed); // only for pd-vanilla, to delete all tcl/tk items void pdlua_gfx_free(t_pdlua_gfx *gfx) { +#if !PLUGDATA for(int i = 0; i < gfx->num_layers; i++) { free(gfx->layer_tags[i]); } free(gfx->layer_tags); if(gfx->transforms) freebytes(gfx->transforms, gfx->num_transforms * sizeof(gfx_transform)); +#endif } // Trigger repaint callback in lua script From b2079699c8722c51f0e5a17a3266ca02ad680a40 Mon Sep 17 00:00:00 2001 From: Timothy Schoen Date: Sat, 5 Oct 2024 01:28:37 +0200 Subject: [PATCH 20/21] Revert "Make sure layers indices can never be skipped in pd.lua" This reverts commit 696d227a20671ff99020c6e266dcac8849a72778. # Conflicts: # pd.lua --- pd.lua | 61 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/pd.lua b/pd.lua index f96a5f2..7360fe9 100644 --- a/pd.lua +++ b/pd.lua @@ -462,41 +462,44 @@ function pd.Class:canvas_realizedollar(s) end function pd.Class:repaint(layer) - local paint_funcs = {} - if type(self.paint) == "function" then - table.insert(paint_funcs, self.paint) - -- Check for layer paint functions - local i = 2 - while true do - local paint_layer_method = "paint_layer_" .. tostring(i) - if type(self[paint_layer_method]) == "function" then - table.insert(paint_funcs, self[paint_layer_method]) - i = i + 1 - else - break -- Exit the loop when no more paint_layer_X methods are found - end + if layer == nil or layer <= 1 then + if type(self.paint) == "function" then + local g = _gfx_internal.start_paint(self._object, 1); + if type(self.paint) == "function" and g ~= nil then + self:paint(g) + _gfx_internal.end_paint(g, 1) end + end end - -- repaint all - if layer == nil or layer == 0 then - for i, paint_fn in ipairs(paint_funcs) do - local g = _gfx_internal.start_paint(self._object, i) - if type(paint_fn) == "function" and g ~= nil then - paint_fn(self, g) - _gfx_internal.end_paint(g, i) + if layer == nil or layer == 0 then + local i = 2 + while true do + local paint_layer_method = "paint_layer_" .. tostring(i) + if type(self[paint_layer_method]) == "function" then + local g = _gfx_internal.start_paint(self._object, i) + if g ~= nil then + self[paint_layer_method](self, g) + _gfx_internal.end_paint(g, i) + i = i + 1 + else + break + end + else - break + break -- Exit the loop when no more paint_layer_X methods are found end end - -- repaint only chosen index - elseif layer <= #paint_funcs then - local g = _gfx_internal.start_paint(self._object, layer) - local paint_fn = paint_funcs[layer] - if type(paint_fn) == "function" and g ~= nil then - paint_fn(self, g) - _gfx_internal.end_paint(g, layer) + end + if layer ~= nil and layer >= 2 then + local paint_layer_method = "paint_layer_" .. tostring(layer) + if type(self[paint_layer_method]) == "function" then + local g = _gfx_internal.start_paint(self._object, layer) + if g ~= nil then + self[paint_layer_method](self, g) + _gfx_internal.end_paint(g, layer) + end end - end + end end function pd.Class:get_size() From d0dd9a7221827fe79e155a6062009274e7daf0f6 Mon Sep 17 00:00:00 2001 From: Timothy Schoen Date: Sat, 5 Oct 2024 01:29:45 +0200 Subject: [PATCH 21/21] Fix layer skipping issue when live-coding, consistently use getbytes()/freebytes() --- pdlua_gfx.h | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/pdlua_gfx.h b/pdlua_gfx.h index 3f39e2b..08dbf39 100644 --- a/pdlua_gfx.h +++ b/pdlua_gfx.h @@ -87,9 +87,9 @@ void pdlua_gfx_free(t_pdlua_gfx *gfx) { #if !PLUGDATA for(int i = 0; i < gfx->num_layers; i++) { - free(gfx->layer_tags[i]); + freebytes(gfx->layer_tags[i], 64); } - free(gfx->layer_tags); + freebytes(gfx->layer_tags, gfx->num_layers); if(gfx->transforms) freebytes(gfx->transforms, gfx->num_transforms * sizeof(gfx_transform)); #endif } @@ -454,7 +454,8 @@ static int stroke_path(lua_State* L) { t_path_state* path = (t_path_state*)luaL_checkudata(L, 1, "Path"); int stroke_width = luaL_checknumber(L, 2) * glist_getzoom(cnv); - t_atom* coordinates = malloc((2 * path->num_path_segments + 2) * sizeof(t_atom)); + int coordinates_size = (2 * path->num_path_segments + 2) * sizeof(t_atom); + t_atom* coordinates = getbytes(coordinates_size); SETFLOAT(coordinates, stroke_width); for (int i = 0; i < path->num_path_segments; i++) { @@ -464,7 +465,7 @@ static int stroke_path(lua_State* L) { } plugdata_draw(gfx->object, gfx->current_layer, gensym("lua_stroke_path"), path->num_path_segments * 2 + 1, coordinates); - free(coordinates); + freebytes(coordinates, coordinates_size); return 0; } @@ -477,7 +478,8 @@ static int fill_path(lua_State* L) { t_path_state* path = (t_path_state*)luaL_checkudata(L, 1, "Path"); - t_atom* coordinates = malloc(2 * path->num_path_segments * sizeof(t_atom)); + int coordinates_size = (2 * path->num_path_segments + 2) * sizeof(t_atom); + t_atom* coordinates = getbytes(coordinates_size); for (int i = 0; i < path->num_path_segments; i++) { float x = path->path_segments[i * 2], y = path->path_segments[i * 2 + 1]; @@ -486,7 +488,7 @@ static int fill_path(lua_State* L) { } plugdata_draw(gfx->object, gfx->current_layer, gensym("lua_fill_path"), path->num_path_segments * 2, coordinates); - free(coordinates); + freebytes(coordinates, coordinates_size); return 0; } @@ -847,17 +849,23 @@ static int start_paint(lua_State* L) { if(can_draw) { int layer = luaL_checknumber(L, 2) - 1; - if(layer >= gfx->num_layers) + if(layer > gfx->num_layers) // If we get here, we have skipped a layer. This isn't allowed, so we should instead repaint everything + { + pdlua_gfx_repaint(obj, 0); + lua_pushnil(L); + return 1; + } + else if(layer >= gfx->num_layers) { int new_num_layers = layer + 1; if(gfx->layer_tags) gfx->layer_tags = resizebytes(gfx->layer_tags, sizeof(char*) * gfx->num_layers, sizeof(char*) * new_num_layers); else - gfx->layer_tags = malloc(sizeof(char*)); + gfx->layer_tags = getbytes(sizeof(char*)); - gfx->num_layers = new_num_layers; - gfx->layer_tags[layer] = malloc(64); + gfx->layer_tags[layer] = getbytes(64); snprintf(gfx->layer_tags[layer], 64, ".l%i%lx", layer, (long)obj); + gfx->num_layers = new_num_layers; } gfx->current_layer_tag = gfx->layer_tags[layer]; @@ -915,6 +923,7 @@ static int end_paint(lua_State* L) { int xpos = text_xpix((t_object*)obj, obj->canvas); int ypos = text_ypix((t_object*)obj, obj->canvas); + // TODO: I don't think we need to call drawiofor on each layer? glist_drawiofor(obj->canvas, (t_object*)obj, 1, gfx->object_tag, xpos, ypos, xpos + (gfx->width * scale), ypos + (gfx->height * scale)); #ifndef PURR_DATA