Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple paint layers #57

Merged
merged 27 commits into from
Oct 5, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a750755
Compatibility fix for pd 0.55-1
timothyschoen Sep 2, 2024
046ac53
Improve multi-layer drawing
timothyschoen Sep 9, 2024
e3a5acd
Improve plugdata system for multi-layer drawing
timothyschoen Sep 26, 2024
868250d
Fix bug in pd-vanilla implementation
timothyschoen Sep 26, 2024
06deee4
Resolve merge conflict
timothyschoen Sep 26, 2024
ea2210c
Don't use reserved C++ keyword in header
timothyschoen Sep 27, 2024
f8e94a3
Fix broken layer indexing
timothyschoen Sep 29, 2024
702163c
Fix error message due to incorrect layer clearing
timothyschoen Sep 30, 2024
01332c5
Fix hang when opening pdlua patch and drawing instantly
timothyschoen Sep 30, 2024
52d831e
Only repaint layers after initial repaint has happened
timothyschoen Sep 30, 2024
db889e3
class_gfx -> pdlua_class_gfx
ben-wes Sep 30, 2024
a04eab1
hello-gui with separate layers
ben-wes Sep 30, 2024
cecc76e
Merge pull request #4 from ben-wes/gfx/minor-changes
timothyschoen Sep 30, 2024
b201390
update graphics.txt and help
ben-wes Sep 30, 2024
6f39118
Merge pull request #5 from ben-wes/doc/multilayers
timothyschoen Sep 30, 2024
6627d55
Fix compile for msvc
alcomposer Oct 1, 2024
4180dd3
Fix tags issue
timothyschoen Oct 2, 2024
e4ff17d
Merge branch 'master' of https://github.com/timothyschoen/pd-lua
timothyschoen Oct 2, 2024
b29168f
Merge pull request #6 from alcomposer/fix-msvc-compile
timothyschoen Oct 3, 2024
de7e6fd
Fix plugdata compatibility
timothyschoen Oct 3, 2024
2f88492
Merge branch 'master' into master
timothyschoen Oct 3, 2024
696d227
Make sure layers indices can never be skipped in pd.lua
timothyschoen Oct 4, 2024
a2d0e4e
Remove semicolons at end of lines in pd.lua
timothyschoen Oct 4, 2024
0fbd181
Fix memory leaks
timothyschoen Oct 4, 2024
6da6c2e
No need to deallocate for plugdata
timothyschoen Oct 4, 2024
b207969
Revert "Make sure layers indices can never be skipped in pd.lua"
timothyschoen Oct 4, 2024
d0dd9a7
Fix layer skipping issue when live-coding, consistently use getbytes(…
timothyschoen Oct 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions doc/graphics.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
47 changes: 39 additions & 8 deletions pd.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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();
obj:repaint(0)
end
end

Expand Down Expand Up @@ -458,17 +458,48 @@ function pd.Class:set_args(args)
end

function pd.Class:canvas_realizedollar(s)
return pd._canvas_realizedollar(self._object, s)
return pd._canvas_realizedollar(self._object, s)
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
else
break
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
agraef marked this conversation as resolved.
Show resolved Hide resolved
end

function pd.Class:get_size()
Expand Down
44 changes: 26 additions & 18 deletions pdlua-help.pd
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down
39 changes: 22 additions & 17 deletions pdlua.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,18 @@
#include <sys/types.h> // for open
#include <sys/stat.h> // for open
#ifdef _MSC_VER
#include <io.h>
#include <fcntl.h> // for open
#define read _read
#define close _close
#define ssize_t int
#define snprintf _snprintf
#include <io.h>
#include <fcntl.h> // 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 <sys/fcntl.h> // for open
#include <unistd.h>
#include <sys/fcntl.h> // for open
#include <unistd.h>
#endif
/* we use Lua */
#include <lua.h>
Expand Down Expand Up @@ -747,7 +750,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, -1, 1);
}
}

Expand Down Expand Up @@ -987,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;
Expand Down Expand Up @@ -1311,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) {
Expand Down Expand Up @@ -1382,8 +1384,8 @@ static int pdlua_object_new(lua_State *L)
o->sigoutlets = 0;
o->sig_warned = 0;
o->canvas = canvas_getcurrent();
o->class = c;
o->class_gfx = c_gfx;
o->pdlua_class = c;
o->pdlua_class_gfx = c_gfx;

o->gfx.width = 80;
o->gfx.height = 80;
Expand Down Expand Up @@ -1413,7 +1415,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);
Expand All @@ -1424,9 +1426,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
Expand Down Expand Up @@ -1852,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]);
Expand Down Expand Up @@ -2996,6 +3000,7 @@ void pdlua_setup(void)
result = lua_pcall(__L(), 0, 0, 0);
PDLUA_DEBUG ("pdlua lua_pcall returned %d", result);
}

if (0 != result)
{
mylua_error(__L(), NULL, NULL);
Expand Down
32 changes: 18 additions & 14 deletions pdlua.h
Original file line number Diff line number Diff line change
Expand Up @@ -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[10]; // Keep track of current color
Expand All @@ -44,27 +47,28 @@ 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;

/** 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.
t_class *class; // Holds our class pointer.
t_class *class_gfx; // Holds our gfx class pointer.
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 *pdlua_class_gfx; // Holds our gfx class pointer.
} t_pdlua;

lua_State* __L();
Loading