diff --git a/pd.lua b/pd.lua index 94195ac..d644b97 100644 --- a/pd.lua +++ b/pd.lua @@ -184,14 +184,16 @@ function pd.Clock:destruct() end function pd.Clock:dispatch() - local m = self._target[self._method] - if type(m) == "function" then - return m(self._target) - else - self._target:error( - "no method for `" .. self._method .. - "' at clock of Lua object `" .. self._name .. "'" - ) + if pd._objects[self._target] then + local m = self._target[self._method] + if type(m) == "function" then + return m(self._target) + else + self._target:error( + "no method for `" .. self._method .. + "' at clock of Lua object `" .. self._name .. "'" + ) + end end end diff --git a/pdlua.h b/pdlua.h index 4d9862d..2f24a43 100644 --- a/pdlua.h +++ b/pdlua.h @@ -17,7 +17,6 @@ #include "m_pd.h" -#if !PLUGDATA typedef enum {SCALE, TRANSLATE} transform_type; typedef struct _gfx_transform @@ -25,20 +24,25 @@ typedef struct _gfx_transform transform_type type; float x, y; } gfx_transform; -#endif typedef struct _pdlua_gfx { // Size variables int width, height; + void *object; #if !PLUGDATA 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 + gfx_transform* transforms; + int num_transforms; + char current_color[8]; // Keep track of current color // Variables to keep track of mouse button state and drag position int mouse_drag_x, mouse_drag_y, mouse_down; int first_draw; + #else void(*plugdata_draw_callback)(void*, t_symbol*, int, t_atom*); // Callback to perform drawing in plugdata #endif diff --git a/pdlua_gfx.h b/pdlua_gfx.h index 799b75b..4868a29 100644 --- a/pdlua_gfx.h +++ b/pdlua_gfx.h @@ -97,7 +97,6 @@ static int scale(lua_State* L); static int reset_transform(lua_State* L); static int free_path(lua_State* L); -static int free_graphics_context(lua_State* L); // pdlua_gfx_clear, pdlua_gfx_repaint and pdlua_gfx_mouse_* correspond to the various callbacks the user can assign @@ -111,14 +110,14 @@ void pdlua_gfx_repaint(t_pdlua *o, int firsttime) { lua_getglobal(__L(), "pd"); lua_getfield (__L(), -1, "_repaint"); lua_pushlightuserdata(__L(), o); - - + + if (lua_pcall(__L(), 1, 0, 0)) { pd_error(o, "lua: error in repaint:\n%s", lua_tostring(__L(), -1)); lua_pop(__L(), 1); /* pop the error string */ } - + lua_pop(__L(), 1); /* pop the global "pd" */ #if !PLUGDATA o->gfx.first_draw = 0; @@ -127,20 +126,20 @@ void pdlua_gfx_repaint(t_pdlua *o, int firsttime) { // Pass mouse events to lua script void pdlua_gfx_mouse_event(t_pdlua *o, int x, int y, int type) { - + lua_getglobal(__L(), "pd"); lua_getfield (__L(), -1, "_mouseevent"); lua_pushlightuserdata(__L(), o); lua_pushinteger(__L(), x); lua_pushinteger(__L(), y); lua_pushinteger(__L(), type); - + if (lua_pcall(__L(), 4, 0, 0)) { pd_error(o, "lua: error in mouseevent:\n%s", lua_tostring(__L(), -1)); lua_pop(__L(), 1); /* pop the error string */ } - + lua_pop(__L(), 1); /* pop the global "pd" */ } @@ -165,36 +164,18 @@ void pdlua_gfx_mouse_drag(t_pdlua *o, int x, int y) { // for plugdata, it only contains a unique ID to the juce::Path that this is mapped to typedef struct _path_state { -#if PLUGDATA - t_gpointer* path_id; -#else // Variables for managing vector paths - int* path_segments; + float* path_segments; int num_path_segments; int num_path_segments_allocated; - int path_start_x, path_start_y; -#endif + float path_start_x, path_start_y; } t_path_state; -// Represents the graphics context object "g" that is passed to the user by the paint function -// This holds the object it is associated with, and for pd-vanilla also some of the current graphics state -typedef struct _graphics_context -{ - t_pdlua *object; -#if !PLUGDATA - char* object_tag; - char current_item_tag[64]; // Tcl/tk tag that is only attached to the current drawing in progress - gfx_transform* transforms; - int num_transforms; - char current_color[8]; // Keep track of current color -#endif -} t_graphics_context; - // Pops the graphics context off the argument list and returns it -static t_graphics_context *pop_graphics_context(lua_State* L) +static t_pdlua_gfx *pop_graphics_context(lua_State* L) { - t_graphics_context* ctx = (t_graphics_context*)luaL_checkudata(L, 1, "GraphicsContext"); + t_pdlua_gfx* ctx = (t_pdlua_gfx*)luaL_checkudata(L, 1, "GraphicsContext"); lua_remove(L, 1); return ctx; } @@ -234,7 +215,6 @@ static const luaL_Reg gfx_methods[] = { {"translate", translate}, {"scale", scale}, {"reset_transform", reset_transform}, - {"__gc", free_graphics_context}, {NULL, NULL} // Sentinel to end the list }; @@ -242,7 +222,7 @@ int pdlua_gfx_setup(lua_State* L) { // for Path(x, y) constructor lua_pushcfunction(L, start_path); lua_setglobal(L, "Path"); - + luaL_newmetatable(L, "Path"); lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); @@ -252,11 +232,11 @@ int pdlua_gfx_setup(lua_State* L) { lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); luaL_setfuncs(L, gfx_methods, 0); - + // Register functions with Lua luaL_newlib(L, gfx_lib); lua_setglobal(L, "_gfx_internal"); - + return 1; // Number of values pushed onto the stack } @@ -265,7 +245,7 @@ static int get_size(lua_State* L) if (!lua_islightuserdata(L, 1)) { return 0; } - + t_pdlua *obj = (t_pdlua*)lua_touserdata(L, 1); lua_pushnumber(L, (lua_Number)obj->gfx.width); lua_pushnumber(L, (lua_Number)obj->gfx.height); @@ -298,6 +278,7 @@ static void pdlua_gfx_clear(t_pdlua *obj, int removed) { static int gfx_initialize(t_pdlua *obj) { + obj->gfx.object = obj; pdlua_gfx_repaint(obj, 0); // Initial repaint return 0; } @@ -307,7 +288,7 @@ static int set_size(lua_State* L) if (!lua_islightuserdata(L, 1)) { return 0; } - + t_pdlua *obj = (t_pdlua*)lua_touserdata(L, 1); obj->gfx.width = luaL_checknumber(L, 2); obj->gfx.height = luaL_checknumber(L, 3); @@ -324,46 +305,37 @@ static int start_paint(lua_State* L) { return 1; } t_pdlua *obj = (t_pdlua*)lua_touserdata(L, 1); - - // Set graphics context as return value - t_graphics_context *ctx = (t_graphics_context *)lua_newuserdata(L, sizeof(t_graphics_context)); - ctx->object = obj; - + + 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); return 1; } static int end_paint(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - t_pdlua *obj = ctx->object; + t_pdlua_gfx *gfx = pop_graphics_context(L); + t_pdlua *obj = gfx->object; plugdata_draw(obj, gensym("lua_end_paint"), 0, NULL); return 0; } -static int free_graphics_context(lua_State* L) -{ - // Nothing to do here - return 0; -} - static int set_color(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - t_pdlua *obj = ctx->object; + t_pdlua_gfx *gfx = pop_graphics_context(L); + t_pdlua *obj = gfx->object; 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); return 0; } - + t_atom args[4]; SETFLOAT(args, luaL_checknumber(L, 1)); // r SETFLOAT(args + 1, luaL_checknumber(L, 2)); // g SETFLOAT(args + 2, luaL_checknumber(L, 3)); // b - + if (lua_gettop(L) > 4) { // object and table are already on stack, hence 5 // alpha (optional, default to 1.0) SETFLOAT(args + 3, luaL_checknumber(L, 4)); @@ -376,72 +348,72 @@ static int set_color(lua_State* L) { } static int fill_ellipse(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); + t_pdlua_gfx *gfx = pop_graphics_context(L); t_atom args[4]; SETFLOAT(args, luaL_checknumber(L, 1)); // x 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(ctx->object, gensym("lua_fill_ellipse"), 4, args); + plugdata_draw(gfx->object, gensym("lua_fill_ellipse"), 4, args); return 0; } static int stroke_ellipse(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); + t_pdlua_gfx *gfx = pop_graphics_context(L); t_atom args[5]; SETFLOAT(args, luaL_checknumber(L, 1)); // x SETFLOAT(args + 1, luaL_checknumber(L, 2)); // y 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(ctx->object, gensym("lua_stroke_ellipse"), 5, args); + plugdata_draw(gfx->object, gensym("lua_stroke_ellipse"), 5, args); return 0; } static int fill_all(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - t_pdlua *obj = ctx->object; + t_pdlua_gfx *gfx = pop_graphics_context(L); + t_pdlua *obj = gfx->object; plugdata_draw(obj, gensym("lua_fill_all"), 0, NULL); return 0; } static int fill_rect(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); + t_pdlua_gfx *gfx = pop_graphics_context(L); t_atom args[4]; SETFLOAT(args, luaL_checknumber(L, 1)); // x 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(ctx->object, gensym("lua_fill_rect"), 4, args); + plugdata_draw(gfx->object, gensym("lua_fill_rect"), 4, args); return 0; } static int stroke_rect(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); + t_pdlua_gfx *gfx = pop_graphics_context(L); t_atom args[5]; SETFLOAT(args, luaL_checknumber(L, 1)); // x SETFLOAT(args + 1, luaL_checknumber(L, 2)); // y 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(ctx->object, gensym("lua_stroke_rect"), 5, args); + plugdata_draw(gfx->object, gensym("lua_stroke_rect"), 5, args); return 0; } static int fill_rounded_rect(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); + t_pdlua_gfx *gfx = pop_graphics_context(L); t_atom args[5]; SETFLOAT(args, luaL_checknumber(L, 1)); // x SETFLOAT(args + 1, luaL_checknumber(L, 2)); // y 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(ctx->object, gensym("lua_fill_rounded_rect"), 5, args); + plugdata_draw(gfx->object, gensym("lua_fill_rounded_rect"), 5, args); return 0; } static int stroke_rounded_rect(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); + t_pdlua_gfx *gfx = pop_graphics_context(L); t_atom args[6]; SETFLOAT(args, luaL_checknumber(L, 1)); // x SETFLOAT(args + 1, luaL_checknumber(L, 2)); // y @@ -449,25 +421,25 @@ 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(ctx->object, gensym("lua_stroke_rounded_rect"), 6, args); + plugdata_draw(gfx->object, gensym("lua_stroke_rounded_rect"), 6, args); return 0; } static int draw_line(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); + t_pdlua_gfx *gfx = pop_graphics_context(L); t_atom args[5]; SETFLOAT(args, luaL_checknumber(L, 1)); // x SETFLOAT(args + 1, luaL_checknumber(L, 2)); // y 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(ctx->object, gensym("lua_draw_line"), 5, args); - + plugdata_draw(gfx->object, gensym("lua_draw_line"), 5, args); + return 0; } static int draw_text(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); + t_pdlua_gfx *gfx = pop_graphics_context(L); const char* text = luaL_checkstring(L, 1); t_atom args[5]; SETSYMBOL(args, gensym(text)); @@ -475,112 +447,60 @@ 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(ctx->object, gensym("lua_draw_text"), 5, args); + plugdata_draw(gfx->object, gensym("lua_draw_text"), 5, args); return 0; } -static int start_path(lua_State* L) { - t_path_state *path = (t_path_state *)lua_newuserdata(L, sizeof(t_path_state)); - luaL_setmetatable(L, "Path"); - - path->path_id = (t_gpointer*)path; - - t_atom args[3]; - SETPOINTER(args, path->path_id); // path id - SETFLOAT(args + 1, luaL_checknumber(L, 1)); // x - SETFLOAT(args + 2, luaL_checknumber(L, 2)); // y - plugdata_draw_path(gensym("lua_start_path"), 3, args); - return 1; -} +static int stroke_path(lua_State* L) { + t_pdlua_gfx *gfx = pop_graphics_context(L); + t_pdlua *obj = gfx->object; -static int line_to(lua_State* L) { - t_path_state* path = (t_path_state*)luaL_checkudata(L, 1, "Path"); - - t_atom args[3]; - SETPOINTER(args, path->path_id); // path id - SETFLOAT(args + 1, luaL_checknumber(L, 2)); // x - SETFLOAT(args + 2, luaL_checknumber(L, 3)); // y - plugdata_draw_path(gensym("lua_line_to"), 3, args); - return 0; -} + t_canvas *cnv = glist_getcanvas(obj->canvas); -static int quad_to(lua_State* L) { t_path_state* path = (t_path_state*)luaL_checkudata(L, 1, "Path"); - - t_atom args[5]; // Assuming quad_to takes 3 arguments - SETPOINTER(args, path->path_id); // path id - SETFLOAT(args + 1, luaL_checknumber(L, 1)); // x1 - SETFLOAT(args + 2, luaL_checknumber(L, 2)); // y1 - SETFLOAT(args + 3, luaL_checknumber(L, 3)); // x2 - SETFLOAT(args + 4, luaL_checknumber(L, 4)); // y2 - - // Forward the message to the appropriate function - plugdata_draw_path(gensym("lua_quad_to"), 5, args); - return 0; -} + int stroke_width = luaL_checknumber(L, 2) * glist_getzoom(cnv); -static int cubic_to(lua_State* L) { - t_path_state* path = (t_path_state*)luaL_checkudata(L, 1, "Path"); - - t_atom args[7]; // Assuming cubic_to takes 4 arguments - - SETPOINTER(args, path->path_id); // path id - SETFLOAT(args + 1, luaL_checknumber(L, 2)); // x1 - SETFLOAT(args + 2, luaL_checknumber(L, 3)); // y1 - SETFLOAT(args + 3, luaL_checknumber(L, 4)); // x2 - SETFLOAT(args + 4, luaL_checknumber(L, 5)); // y2 - SETFLOAT(args + 5, luaL_checknumber(L, 6)); // x3 - SETFLOAT(args + 6, luaL_checknumber(L, 7)); // y3 - - // Forward the message to the appropriate function - plugdata_draw_path(gensym("lua_cubic_to"), 7, args); - return 0; -} + t_atom* coordinates = malloc((2 * path->num_path_segments + 2) * sizeof(t_atom)); + SETFLOAT(coordinates, stroke_width); -static int close_path(lua_State* L) { - t_path_state* path = (t_path_state*)luaL_checkudata(L, 1, "Path"); - - t_atom args; - SETPOINTER(&args, path->path_id); // path id - - plugdata_draw_path(gensym("lua_close_path"), 1, &args); - return 0; -} + for (int i = 0; i < path->num_path_segments; i++) { + float x = path->path_segments[i * 2], y = path->path_segments[i * 2 + 1]; + SETFLOAT(coordinates + (i * 2) + 1, x); + SETFLOAT(coordinates + (i * 2) + 2, y); + } -static int free_path(lua_State* L) { - t_path_state* path = (t_path_state*)luaL_checkudata(L, 1, "Path"); - - t_atom args; - SETPOINTER(&args, path->path_id); // path id - plugdata_draw_path(gensym("lua_free_path"), 1, &args); - return 0; -} + plugdata_draw(gfx->object, gensym("lua_stroke_path"), path->num_path_segments * 2 + 1, coordinates); + free(coordinates); -static int stroke_path(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - t_path_state* path = (t_path_state*)luaL_checkudata(L, 1, "Path"); - - t_atom args[2]; - SETPOINTER(args, path->path_id); // path id - SETFLOAT(args + 1, luaL_checknumber(L, 2)); // line thickness - plugdata_draw(ctx->object, gensym("lua_stroke_path"), 2, args); return 0; } static int fill_path(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); + t_pdlua_gfx *gfx = pop_graphics_context(L); + t_pdlua *obj = gfx->object; + + t_canvas *cnv = glist_getcanvas(obj->canvas); + t_path_state* path = (t_path_state*)luaL_checkudata(L, 1, "Path"); + + t_atom* coordinates = malloc(2 * path->num_path_segments * sizeof(t_atom)); - t_atom args; - SETPOINTER(&args, path->path_id); // path id - - plugdata_draw(ctx->object, gensym("lua_fill_path"), 1, &args); + for (int i = 0; i < path->num_path_segments; i++) { + float x = path->path_segments[i * 2], y = path->path_segments[i * 2 + 1]; + SETFLOAT(coordinates + (i * 2), x); + SETFLOAT(coordinates + (i * 2) + 1, y); + } + + plugdata_draw(gfx->object, gensym("lua_fill_path"), path->num_path_segments * 2, coordinates); + free(coordinates); + return 0; } + static int translate(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - t_pdlua *obj = ctx->object; + t_pdlua_gfx *gfx = pop_graphics_context(L); + t_pdlua *obj = gfx->object; t_atom args[2]; SETFLOAT(args, luaL_checknumber(L, 1)); // tx SETFLOAT(args + 1, luaL_checknumber(L, 2)); // ty @@ -589,8 +509,8 @@ static int translate(lua_State* L) { } static int scale(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - t_pdlua *obj = ctx->object; + t_pdlua_gfx *gfx = pop_graphics_context(L); + t_pdlua *obj = gfx->object; t_atom args[2]; SETFLOAT(args, luaL_checknumber(L, 1)); // sx SETFLOAT(args + 1, luaL_checknumber(L, 2)); // sy @@ -599,8 +519,8 @@ static int scale(lua_State* L) { } static int reset_transform(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - t_pdlua *obj = ctx->object; + t_pdlua_gfx *gfx = pop_graphics_context(L); + t_pdlua *obj = gfx->object; plugdata_draw(obj, gensym("lua_reset_transform"), 0, NULL); return 0; } @@ -614,7 +534,7 @@ static unsigned long long custom_rand() { const unsigned long long m = 4294967296; // 2^32 seed = (a * seed + c) % m; if(seed == 0) seed = 1; // We cannot return 0 since we use modulo on this. Having the rhs operator of % be zero leads to div-by-zero error on Windows - + return seed; } @@ -622,58 +542,66 @@ static unsigned long long custom_rand() { static void generate_random_id(char *str, size_t len) { const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; size_t charset_len = strlen(charset); - + str[0] = '.'; str[1] = 'x'; - + for (size_t i = 2; i < len - 1; ++i) { int key = custom_rand() % charset_len; str[i] = charset[key]; } - + str[len - 1] = '\0'; } -static int free_path(lua_State* L) -{ - t_path_state* path = (t_path_state*)luaL_checkudata(L, 1, "Path"); - freebytes(path->path_segments, path->num_path_segments_allocated * sizeof(int)); - return 0; +static void transform_size(t_pdlua_gfx *gfx, int* w, int* h) { + for(int i = gfx->num_transforms - 1; i >= 0; i--) + { + if(gfx->transforms[i].type == SCALE) + { + *w *= gfx->transforms[i].x; + *h *= gfx->transforms[i].y; + } + } } -static void transform_size(t_graphics_context *ctx, int* w, int* h) { - for(int i = ctx->num_transforms - 1; i >= 0; i--) +static void transform_point(t_pdlua_gfx *gfx, int* x, int* y) { + for(int i = gfx->num_transforms - 1; i >= 0; i--) { - if(ctx->transforms[i].type == SCALE) + if(gfx->transforms[i].type == SCALE) { - *w *= ctx->transforms[i].x; - *h *= ctx->transforms[i].y; + *x *= gfx->transforms[i].x; + *y *= gfx->transforms[i].y; + } + else // translate + { + *x += gfx->transforms[i].x; + *y += gfx->transforms[i].y; } } } -static void transform_point(t_graphics_context *ctx, int* x, int* y) { - for(int i = ctx->num_transforms - 1; i >= 0; i--) +static void transform_point_float(t_pdlua_gfx *gfx, float* x, float* y) { + for(int i = gfx->num_transforms - 1; i >= 0; i--) { - if(ctx->transforms[i].type == SCALE) + if(gfx->transforms[i].type == SCALE) { - *x *= ctx->transforms[i].x; - *y *= ctx->transforms[i].y; + *x *= gfx->transforms[i].x; + *y *= gfx->transforms[i].y; } else // translate { - *x += ctx->transforms[i].x; - *y += ctx->transforms[i].y; + *x += gfx->transforms[i].x; + *y += gfx->transforms[i].y; } } } - static void pdlua_gfx_clear(t_pdlua *obj, int removed) { t_pdlua_gfx *gfx = &obj->gfx; t_canvas *cnv = glist_getcanvas(obj->canvas); pdgui_vmess(0, "crs", cnv, "delete", gfx->object_tag); - + if(removed && gfx->order_tag[0] != '\0') { pdgui_vmess(0, "crs", cnv, "delete", gfx->order_tag); @@ -683,20 +611,20 @@ static void pdlua_gfx_clear(t_pdlua *obj, int removed) { glist_eraseiofor(glist_getcanvas(cnv), &obj->pd, gfx->object_tag); } -static void get_bounds_args(lua_State* L, t_pdlua *obj, t_graphics_context *ctx, int* x1, int* y1, int* x2, int* y2) { +static void get_bounds_args(lua_State* L, t_pdlua *obj, int* x1, int* y1, int* x2, int* y2) { t_canvas *cnv = glist_getcanvas(obj->canvas); - + int x = luaL_checknumber(L, 1); int y = luaL_checknumber(L, 2); int w = luaL_checknumber(L, 3); int h = luaL_checknumber(L, 4); - - transform_point(ctx, &x, &y); - transform_size(ctx, &w, &h); - + + transform_point(&obj->gfx, &x, &y); + transform_size(&obj->gfx, &w, &h); + x += text_xpix((t_object*)obj, obj->canvas) / glist_getzoom(cnv); y += text_ypix((t_object*)obj, obj->canvas) / glist_getzoom(cnv); - + *x1 = x * glist_getzoom(cnv); *y1 = y * glist_getzoom(cnv); *x2 = (x + w) * glist_getzoom(cnv); @@ -707,28 +635,31 @@ static void gfx_displace(t_pdlua *x, t_glist *glist, int dx, int dy) { sys_vgui(".x%lx.c move .x%lx %d %d\n", glist_getcanvas(x->canvas), (long)x, dx, dy); canvas_fixlinesfor(glist, (t_text*)x); - + int scale = glist_getzoom(glist_getcanvas(x->canvas)); - + int xpos = text_xpix((t_object*)x, x->canvas); int ypos = text_ypix((t_object*)x, x->canvas); glist_drawiofor(x->canvas, (t_object*)x, 0, x->gfx.object_tag, xpos, ypos, xpos + (x->gfx.width * scale), ypos + (x->gfx.height * scale)); } -static const char* register_drawing(t_graphics_context *ctx) +static const char* register_drawing(t_pdlua_gfx *gfx) { - generate_random_id(ctx->current_item_tag, 64); - return ctx->current_item_tag; + generate_random_id(gfx->current_item_tag, 64); + return gfx->current_item_tag; } static int gfx_initialize(t_pdlua *obj) { t_pdlua_gfx *gfx = &obj->gfx; - + snprintf(gfx->object_tag, 128, ".x%lx", (long)obj); gfx->object_tag[127] = '\0'; gfx->order_tag[0] = '\0'; - + gfx->object = obj; + gfx->transforms = NULL; + gfx->num_transforms = 0; + pdlua_gfx_repaint(obj, 0); return 0; } @@ -738,12 +669,14 @@ static int set_size(lua_State* L) if (!lua_islightuserdata(L, 1)) { return 0; } - + t_pdlua *obj = (t_pdlua*)lua_touserdata(L, 1); obj->gfx.width = luaL_checknumber(L, 2); obj->gfx.height = luaL_checknumber(L, 3); pdlua_gfx_repaint(obj, 0); - canvas_fixlinesfor(obj->canvas, (t_text*)obj); + if(glist_isvisible(obj->canvas) && gobj_shouldvis(&obj->pd.te_g, obj->canvas)) { + canvas_fixlinesfor(obj->canvas, (t_text*)obj); + } return 0; } @@ -752,7 +685,7 @@ static int start_paint(lua_State* L) { lua_pushnil(L); return 1; } - + t_pdlua* obj = (t_pdlua*)lua_touserdata(L, 1); t_pdlua_gfx *gfx = &obj->gfx; if(gfx->object_tag[0] == '\0') @@ -768,17 +701,16 @@ 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) { - t_graphics_context *ctx = (t_graphics_context *)lua_newuserdata(L, sizeof(t_graphics_context)); + if(gfx->transforms) freebytes(gfx->transforms, gfx->num_transforms * sizeof(gfx_transform)); + gfx->num_transforms = 0; + gfx->transforms = NULL; + + lua_pushlightuserdata(L, gfx); luaL_setmetatable(L, "GraphicsContext"); - - ctx->object = obj; - ctx->object_tag = &gfx->object_tag[0]; - ctx->num_transforms = 0; - ctx->transforms = NULL; - + // clear anything that was painted before if(strlen(gfx->object_tag)) pdlua_gfx_clear(obj, 0); - + if(gfx->first_draw) { // Whenever the objects gets painted for the first time with a "vis" message, @@ -786,12 +718,12 @@ static int start_paint(lua_State* L) { // We can then use this line to set the correct z-index for the drawings, using the tcl/tk "lower" command t_canvas *cnv = glist_getcanvas(obj->canvas); generate_random_id(gfx->order_tag, 64); - + const char* tags[] = { gfx->order_tag }; - pdgui_vmess(0, "crr iiii ri rS", cnv, "create", "line", 0, 0, 1, 1, + pdgui_vmess(0, "crr iiii ri rS", cnv, "create", "line", 0, 0, 0, 0, "-width", 1, "-tags", 1, tags); } - + return 1; } @@ -800,37 +732,29 @@ static int start_paint(lua_State* L) { } static int end_paint(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - t_pdlua *obj = ctx->object; + t_pdlua_gfx *gfx = pop_graphics_context(L); + t_pdlua *obj = (t_pdlua*)gfx->object; t_canvas *cnv = glist_getcanvas(obj->canvas); - + int scale = glist_getzoom(glist_getcanvas(obj->canvas)); - + // Draw iolets on top int xpos = text_xpix((t_object*)obj, obj->canvas); int ypos = text_ypix((t_object*)obj, obj->canvas); - - t_pdlua_gfx *gfx = &obj->gfx; - glist_drawiofor(glist_getcanvas(obj->canvas), (t_object*)obj, 1, ctx->object_tag, xpos, ypos, xpos + (obj->gfx.width * scale), ypos + (obj->gfx.height * scale)); - + + glist_drawiofor(glist_getcanvas(obj->canvas), (t_object*)obj, 1, gfx->object_tag, xpos, ypos, xpos + (gfx->width * scale), ypos + (gfx->height * scale)); + 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", ctx->object_tag, gfx->order_tag); + pdgui_vmess(0, "crss", cnv, "lower", gfx->object_tag, gfx->order_tag); } - - return 0; -} -static int free_graphics_context(lua_State* L) -{ - t_graphics_context* ctx = (t_graphics_context*)luaL_checkudata(L, 1, "GraphicsContext"); - if(ctx && ctx->transforms) freebytes(ctx->transforms, ctx->num_transforms * sizeof(gfx_transform)); return 0; } static int set_color(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - + t_pdlua_gfx *gfx = pop_graphics_context(L); + int r, g, b; if (lua_gettop(L) == 1) { // Single argument: parse as color ID instead of RGB int color_id = luaL_checknumber(L, 1); @@ -853,184 +777,181 @@ static int set_color(lua_State* L) { } // AFAIK, alpha is not supported in tcl/tk + snprintf(gfx->current_color, 8, "#%02X%02X%02X", r, g, b); + gfx->current_color[7] = '\0'; - snprintf(ctx->current_color, 8, "#%02X%02X%02X", r, g, b); - ctx->current_color[7] = '\0'; - return 0; } static int fill_ellipse(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - t_pdlua *obj = ctx->object; - + t_pdlua_gfx *gfx = pop_graphics_context(L); + t_pdlua *obj = gfx->object; + t_canvas *cnv = glist_getcanvas(obj->canvas); - + int x1, y1, x2, y2; - get_bounds_args(L, obj, ctx, &x1, &y1, &x2, &y2); - - const char* tags[] = { ctx->object_tag, register_drawing(ctx) }; - - pdgui_vmess(0, "crr iiii rs ri rS", cnv, "create", "oval", x1, y1, x2, y2, "-fill", ctx->current_color, "-width", 0, "-tags", 2, tags); - + get_bounds_args(L, obj, &x1, &y1, &x2, &y2); + + const char* tags[] = { gfx->object_tag, register_drawing(gfx) }; + + pdgui_vmess(0, "crr iiii rs ri rS", cnv, "create", "oval", x1, y1, x2, y2, "-fill", gfx->current_color, "-width", 0, "-tags", 2, tags); + return 0; } static int stroke_ellipse(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - t_pdlua *obj = ctx->object; - + t_pdlua_gfx *gfx = pop_graphics_context(L); + t_pdlua *obj = gfx->object; + t_canvas *cnv = glist_getcanvas(obj->canvas); int x1, y1, x2, y2; - get_bounds_args(L, obj, ctx, &x1, &y1, &x2, &y2); - + get_bounds_args(L, obj, &x1, &y1, &x2, &y2); + int line_width = luaL_checknumber(L, 5) * glist_getzoom(cnv); - - const char* tags[] = { ctx->object_tag, register_drawing(ctx) }; - - pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "oval", x1, y1, x2, y2, "-width", line_width, "-outline", ctx->current_color, "-tags", 2, tags); - + + const char* tags[] = { gfx->object_tag, register_drawing(gfx) }; + + 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); + return 0; } static int fill_all(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - t_pdlua *obj = ctx->object; - t_pdlua_gfx *gfx = &obj->gfx; - + t_pdlua_gfx *gfx = pop_graphics_context(L); + t_pdlua *obj = gfx->object; + t_canvas *cnv = glist_getcanvas(obj->canvas); - + int x1 = text_xpix((t_object*)obj, obj->canvas); int y1 = text_ypix((t_object*)obj, obj->canvas); int x2 = x1 + gfx->width * glist_getzoom(cnv); int y2 = y1 + gfx->height * glist_getzoom(cnv); - - const char* tags[] = { ctx->object_tag, register_drawing(ctx) }; - - pdgui_vmess(0, "crr iiii rs rS", cnv, "create", "rectangle", x1, y1, x2, y2, "-fill", ctx->current_color, "-tags", 2, tags); - + + const char* tags[] = { gfx->object_tag, register_drawing(gfx) }; + + pdgui_vmess(0, "crr iiii rs rS", cnv, "create", "rectangle", x1, y1, x2, y2, "-fill", gfx->current_color, "-tags", 2, tags); + return 0; } static int fill_rect(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - t_pdlua *obj = ctx->object; - + t_pdlua_gfx *gfx = pop_graphics_context(L); + t_pdlua *obj = gfx->object; + t_canvas *cnv = glist_getcanvas(obj->canvas); - + int x1, y1, x2, y2; - get_bounds_args(L, obj, ctx, &x1, &y1, &x2, &y2); - - const char* tags[] = { ctx->object_tag, register_drawing(ctx) }; - - pdgui_vmess(0, "crr iiii rs ri rS", cnv, "create", "rectangle", x1, y1, x2, y2, "-fill", ctx->current_color, "-width", 0, "-tags", 2, tags); - + get_bounds_args(L, obj, &x1, &y1, &x2, &y2); + + const char* tags[] = { gfx->object_tag, register_drawing(gfx) }; + + pdgui_vmess(0, "crr iiii rs ri rS", cnv, "create", "rectangle", x1, y1, x2, y2, "-fill", gfx->current_color, "-width", 0, "-tags", 2, tags); + return 0; } static int stroke_rect(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - t_pdlua *obj = ctx->object; - + t_pdlua_gfx *gfx = pop_graphics_context(L); + t_pdlua *obj = gfx->object; + t_canvas *cnv = glist_getcanvas(obj->canvas); - + int x1, y1, x2, y2; - get_bounds_args(L, obj, ctx, &x1, &y1, &x2, &y2); + get_bounds_args(L, obj, &x1, &y1, &x2, &y2); int line_width = luaL_checknumber(L, 5) * glist_getzoom(cnv); - - const char* tags[] = { ctx->object_tag, register_drawing(ctx) }; - pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "rectangle", x1, y1, x2, y2, "-width", line_width, "-outline", ctx->current_color, "-tags", 2, tags); - + const char* tags[] = { gfx->object_tag, register_drawing(gfx) }; + + 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); + return 0; } static int fill_rounded_rect(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - t_pdlua *obj = ctx->object; - + t_pdlua_gfx *gfx = pop_graphics_context(L); + t_pdlua *obj = gfx->object; + t_canvas *cnv = glist_getcanvas(obj->canvas); - + int x1, y1, x2, y2; - get_bounds_args(L, obj, ctx, &x1, &y1, &x2, &y2); + get_bounds_args(L, obj, &x1, &y1, &x2, &y2); int radius = luaL_checknumber(L, 5); // Radius for rounded corners int radius_x = radius * glist_getzoom(cnv); int radius_y = radius * glist_getzoom(cnv); - transform_size(ctx, &radius_x, &radius_y); - - const char* tags[] = { ctx->object_tag, register_drawing(ctx) }; + transform_size(gfx, &radius_x, &radius_y); + + const char* tags[] = { gfx->object_tag, register_drawing(gfx) }; // 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", ctx->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", ctx->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", ctx->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", ctx->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", ctx->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", ctx->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", 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); return 0; } static int stroke_rounded_rect(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - t_pdlua *obj = ctx->object; - + t_pdlua_gfx *gfx = pop_graphics_context(L); + t_pdlua *obj = gfx->object; + t_canvas *cnv = glist_getcanvas(obj->canvas); - + int x1, y1, x2, y2; - get_bounds_args(L, obj, ctx, &x1, &y1, &x2, &y2); - + get_bounds_args(L, obj, &x1, &y1, &x2, &y2); + int radius = luaL_checknumber(L, 5); // Radius for rounded corners int radius_x = radius * glist_getzoom(cnv); int radius_y = radius * glist_getzoom(cnv); - transform_size(ctx, &radius_x, &radius_y); + transform_size(gfx, &radius_x, &radius_y); int line_width = luaL_checknumber(L, 6) * glist_getzoom(cnv); - - const char* tags[] = { ctx->object_tag, register_drawing(ctx) }; - + + const char* tags[] = { gfx->object_tag, register_drawing(gfx) }; + // 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", ctx->current_color, "-style", "arc", "-tags", 2, tags); + "-start", 0, "-extent", 90, "-width", line_width, "-start", 90, "-outline", gfx->current_color, "-style", "arc", "-tags", 2, 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", ctx->current_color, "-style", "arc", "-tags", 2, tags); + "-start", 270, "-extent", 90, "-width", line_width, "-start", 0, "-outline", gfx->current_color, "-style", "arc", "-tags", 2, 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", ctx->current_color, "-style", "arc", "-tags", 2, tags); + "-start", 180, "-extent", 90, "-width", line_width, "-start", 180, "-outline", gfx->current_color, "-style", "arc", "-tags", 2, 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", ctx->current_color, "-style", "arc", "-tags", 2, tags); - + "-start", 90, "-extent", 90, "-width", line_width, "-start", 270, "-outline", gfx->current_color, "-style", "arc", "-tags", 2, 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", ctx->current_color, "-tags", 2, tags); + "-width", line_width, "-fill", gfx->current_color, "-tags", 2, tags); pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "line", x1 + radius_y, y2, x2 - radius_y, y2, - "-width", line_width, "-fill", ctx->current_color, "-tags", 2, tags); + "-width", line_width, "-fill", gfx->current_color, "-tags", 2, tags); pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "line", x1 , y1 + radius_y, x1, y2 - radius_y, - "-width", line_width, "-fill", ctx->current_color, "-tags", 2, tags); + "-width", line_width, "-fill", gfx->current_color, "-tags", 2, tags); pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "line", x2 , y1 + radius_y, x2, y2 - radius_y, - "-width", line_width, "-fill", ctx->current_color, "-tags", 2, tags); - + "-width", line_width, "-fill", gfx->current_color, "-tags", 2, tags); + return 0; } static int draw_line(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - t_pdlua *obj = ctx->object; - + t_pdlua_gfx *gfx = pop_graphics_context(L); + t_pdlua *obj = gfx->object; t_canvas *cnv = glist_getcanvas(obj->canvas); - + int x1 = luaL_checknumber(L, 1); int y1 = luaL_checknumber(L, 2); int x2 = luaL_checknumber(L, 3); int y2 = luaL_checknumber(L, 4); int line_width = luaL_checknumber(L, 5); - - transform_point(ctx, &x1, &y1); - transform_point(ctx, &x2, &y2); - + + transform_point(gfx, &x1, &y1); + transform_point(gfx, &x2, &y2); + int canvas_zoom = glist_getzoom(cnv); x1 += text_xpix((t_object*)obj, obj->canvas) / canvas_zoom; @@ -1043,41 +964,41 @@ static int draw_line(lua_State* L) { x2 *= canvas_zoom; y2 *= canvas_zoom; line_width *= canvas_zoom; - - const char* tags[] = { ctx->object_tag, register_drawing(ctx) }; - + + const char* tags[] = { gfx->object_tag, register_drawing(gfx) }; + pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "line", x1, y1, x2, y2, - "-width", line_width, "-fill", ctx->current_color, "-tags", 2, tags); + "-width", line_width, "-fill", gfx->current_color, "-tags", 2, tags); return 0; } static int draw_text(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - t_pdlua *obj = ctx->object; - + t_pdlua_gfx *gfx = pop_graphics_context(L); + t_pdlua *obj = gfx->object; + t_canvas *cnv = glist_getcanvas(obj->canvas); - + const char* text = luaL_checkstring(L, 1); // Assuming text is a string int x = luaL_checknumber(L, 2); int y = luaL_checknumber(L, 3); int w = luaL_checknumber(L, 4); int font_height = luaL_checknumber(L, 5); font_height = sys_hostfontsize(font_height, glist_getzoom(cnv)); - - transform_point(ctx, &x, &y); - transform_size(ctx, &w, &font_height); - + + transform_point(gfx, &x, &y); + transform_size(gfx, &w, &font_height); + int canvas_zoom = glist_getzoom(cnv); x += text_xpix((t_object*)obj, obj->canvas) / canvas_zoom; y += text_ypix((t_object*)obj, obj->canvas) / canvas_zoom; - + x *= canvas_zoom; y *= canvas_zoom; w *= canvas_zoom; - - const char* tags[] = { ctx->object_tag, register_drawing(ctx) }; - + + const char* tags[] = { gfx->object_tag, register_drawing(gfx) }; + pdgui_vmess(0, "crr ii rs ri rs rS", cnv, "create", "text", 0, 0, "-anchor", "nw", "-width", w, "-text", text, "-tags", 2, tags); @@ -1088,28 +1009,136 @@ static int draw_text(lua_State* L) { pdgui_vmess(0, "crs rA rs rs", cnv, "itemconfigure", tags[1], "-font", 3, fontatoms, - "-fill", ctx->current_color, + "-fill", gfx->current_color, "-justify", "left"); - + pdgui_vmess(0, "crs ii", cnv, "coords", tags[1], x, y); + + return 0; +} + +static int stroke_path(lua_State* L) { + t_pdlua_gfx *gfx = pop_graphics_context(L); + t_pdlua *obj = gfx->object; + + t_canvas *cnv = glist_getcanvas(obj->canvas); + + t_path_state* path = (t_path_state*)luaL_checkudata(L, 1, "Path"); + if(path->num_path_segments < 3) + { + return 0; + } + + int stroke_width = luaL_checknumber(L, 2) * glist_getzoom(cnv); + int obj_x = text_xpix((t_object*)obj, obj->canvas); + 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) }; + + 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); + sys_vgui(".x%lx.c coords %s", cnv, tags[1]); + for (int i = 0; i < path->num_path_segments; i++) { + float x = path->path_segments[i * 2], y = path->path_segments[i * 2 + 1]; + transform_point_float(gfx, &x, &y); + sys_vgui(" %f %f", (x * canvas_zoom) + obj_x, (y * canvas_zoom) + obj_y); + } + sys_vgui("\n"); + + return 0; +} + +static int fill_path(lua_State* L) { + t_pdlua_gfx *gfx = pop_graphics_context(L); + t_pdlua *obj = gfx->object; + + t_canvas *cnv = glist_getcanvas(obj->canvas); + + t_path_state* path = (t_path_state*)luaL_checkudata(L, 1, "Path"); + if(path->num_path_segments < 3) + { + return 0; + } + + // Apply transformations to all coordinates + int obj_x = text_xpix((t_object*)obj, obj->canvas); + 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) }; + + pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "polygon", 0, 0, 0, 0, "-width", 0, "-fill", gfx->current_color, "-tags", 2, tags); + + sys_vgui(".x%lx.c coords %s", cnv, tags[1]); + for (int i = 0; i < path->num_path_segments; i++) { + float x = path->path_segments[i * 2], y = path->path_segments[i * 2 + 1]; + transform_point_float(gfx, &x, &y); + sys_vgui(" %f %f", (x * canvas_zoom) + obj_x, (y * canvas_zoom) + obj_y); + } + sys_vgui("\n"); + + return 0; +} + + +static int translate(lua_State* L) { + t_pdlua_gfx *gfx = pop_graphics_context(L); + + if(gfx->num_transforms == 0) + { + gfx->transforms = getbytes(sizeof(gfx_transform)); + + } + else + { + gfx->transforms = resizebytes(gfx->transforms, gfx->num_transforms * sizeof(gfx_transform), (gfx->num_transforms + 1) * sizeof(gfx_transform)); + + } + + gfx->transforms[gfx->num_transforms].type = TRANSLATE; + gfx->transforms[gfx->num_transforms].x = luaL_checknumber(L, 1); + gfx->transforms[gfx->num_transforms].y = luaL_checknumber(L, 2); + + gfx->num_transforms++; + return 0; +} + +static int scale(lua_State* L) { + t_pdlua_gfx *gfx = pop_graphics_context(L); + + gfx->transforms = resizebytes(gfx->transforms, gfx->num_transforms * sizeof(gfx_transform), (gfx->num_transforms + 1) * sizeof(gfx_transform)); + + gfx->transforms[gfx->num_transforms].type = SCALE; + gfx->transforms[gfx->num_transforms].x = luaL_checknumber(L, 1); + gfx->transforms[gfx->num_transforms].y = luaL_checknumber(L, 2); + + gfx->num_transforms++; return 0; } -static void add_path_segment(t_path_state* path, int x, int y) +static int reset_transform(lua_State* L) { + t_pdlua_gfx *gfx = pop_graphics_context(L); + freebytes(gfx->transforms, gfx->num_transforms * sizeof(gfx_transform)); + gfx->transforms = NULL; + gfx->num_transforms = 0; + return 0; +} +#endif +static void add_path_segment(t_path_state* path, float x, float y) { int path_segment_space = (path->num_path_segments + 1) * 2; int old_size = path->num_path_segments_allocated; int new_size = MAX(path_segment_space, path->num_path_segments_allocated); if(!path->num_path_segments_allocated) { - path->path_segments = (int*)getbytes(new_size * sizeof(int)); + path->path_segments = (float*)getbytes(new_size * sizeof(float)); } else { - path->path_segments = (int*)resizebytes(path->path_segments, old_size * sizeof(int), new_size * sizeof(int)); + path->path_segments = (float*)resizebytes(path->path_segments, old_size * sizeof(float), new_size * sizeof(float)); } path->num_path_segments_allocated = new_size; - + path->path_segments[path->num_path_segments * 2] = x; path->path_segments[path->num_path_segments * 2 + 1] = y; path->num_path_segments++; @@ -1123,7 +1152,7 @@ static int start_path(lua_State* L) { path->num_path_segments_allocated = 0; path->path_start_x = luaL_checknumber(L, 1); path->path_start_y = luaL_checknumber(L, 2); - + add_path_segment(path, path->path_start_x, path->path_start_y); return 1; } @@ -1131,72 +1160,72 @@ static int start_path(lua_State* L) { // Function to add a line to the current path static int line_to(lua_State* L) { t_path_state* path = (t_path_state*)luaL_checkudata(L, 1, "Path"); - int x = luaL_checknumber(L, 2); - int y = luaL_checknumber(L, 3); + float x = luaL_checknumber(L, 2); + float y = luaL_checknumber(L, 3); add_path_segment(path, x, y); return 0; } static int quad_to(lua_State* L) { t_path_state* path = (t_path_state*)luaL_checkudata(L, 1, "Path"); - int x2 = luaL_checknumber(L, 2); - int y2 = luaL_checknumber(L, 3); - int x3 = luaL_checknumber(L, 4); - int y3 = luaL_checknumber(L, 5); - - int x1 = path->num_path_segments > 0 ? path->path_segments[(path->num_path_segments - 1) * 2] : x2; - int y1 = path->num_path_segments > 0 ? path->path_segments[(path->num_path_segments - 1) * 2 + 1] : y2; - + float x2 = luaL_checknumber(L, 2); + float y2 = luaL_checknumber(L, 3); + float x3 = luaL_checknumber(L, 4); + float y3 = luaL_checknumber(L, 5); + + float x1 = path->num_path_segments > 0 ? path->path_segments[(path->num_path_segments - 1) * 2] : x2; + float y1 = path->num_path_segments > 0 ? path->path_segments[(path->num_path_segments - 1) * 2 + 1] : y2; + // heuristic for deciding the number of lines in our bezier curve float dx = x3 - x1; float dy = y3 - y1; float distance = sqrtf(dx * dx + dy * dy); float resolution = MAX(10.0f, distance); - + // Get the last point float t = 0.0; while (t <= 1.0) { t += 1.0 / resolution; - + // Calculate quadratic bezier curve as points (source: https://en.wikipedia.org/wiki/B%C3%A9zier_curve) - int x = (1.0f - t) * (1.0f - t) * x1 + 2.0f * (1.0f - t) * t * x2 + t * t * x3; - int y = (1.0f - t) * (1.0f - t) * y1 + 2.0f * (1.0f - t) * t * y2 + t * t * y3; + float x = (1.0f - t) * (1.0f - t) * x1 + 2.0f * (1.0f - t) * t * x2 + t * t * x3; + float y = (1.0f - t) * (1.0f - t) * y1 + 2.0f * (1.0f - t) * t * y2 + t * t * y3; add_path_segment(path, x, y); } - + return 0; } static int cubic_to(lua_State* L) { t_path_state* path = (t_path_state*)luaL_checkudata(L, 1, "Path"); - int x2 = luaL_checknumber(L, 2); - int y2 = luaL_checknumber(L, 3); - int x3 = luaL_checknumber(L, 4); - int y3 = luaL_checknumber(L, 5); - int x4 = luaL_checknumber(L, 6); - int y4 = luaL_checknumber(L, 7); - - int x1 = path->num_path_segments > 0 ? path->path_segments[(path->num_path_segments - 1) * 2] : x2; - int y1 = path->num_path_segments > 0 ? path->path_segments[(path->num_path_segments - 1) * 2 + 1] : y2; - + float x2 = luaL_checknumber(L, 2); + float y2 = luaL_checknumber(L, 3); + float x3 = luaL_checknumber(L, 4); + float y3 = luaL_checknumber(L, 5); + float x4 = luaL_checknumber(L, 6); + float y4 = luaL_checknumber(L, 7); + + float x1 = path->num_path_segments > 0 ? path->path_segments[(path->num_path_segments - 1) * 2] : x2; + float y1 = path->num_path_segments > 0 ? path->path_segments[(path->num_path_segments - 1) * 2 + 1] : y2; + // heuristic for deciding the number of lines in our bezier curve float dx = x3 - x1; float dy = y3 - y1; float distance = sqrtf(dx * dx + dy * dy); float resolution = MAX(10.0f, distance); - + // Get the last point float t = 0.0; while (t <= 1.0) { t += 1.0 / resolution; // Calculate cubic bezier curve as points (source: https://en.wikipedia.org/wiki/B%C3%A9zier_curve) - int x = (1 - t)*(1 - t)*(1 - t) * x1 + 3 * (1 - t)*(1 - t) * t * x2 + 3 * (1 - t) * t*t * x3 + t*t*t * x4; - int y = (1 - t)*(1 - t)*(1 - t) * y1 + 3 * (1 - t)*(1 - t) * t * y2 + 3 * (1 - t) * t*t * y3 + t*t*t * y4; - + float x = (1 - t)*(1 - t)*(1 - t) * x1 + 3 * (1 - t)*(1 - t) * t * x2 + 3 * (1 - t) * t*t * x3 + t*t*t * x4; + float y = (1 - t)*(1 - t)*(1 - t) * y1 + 3 * (1 - t)*(1 - t) * t * y2 + 3 * (1 - t) * t*t * y3 + t*t*t * y4; + add_path_segment(path, x, y); } - + return 0; } @@ -1207,159 +1236,9 @@ static int close_path(lua_State* L) { return 0; } -static int stroke_path(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - t_pdlua *obj = ctx->object; - - t_canvas *cnv = glist_getcanvas(obj->canvas); - - t_path_state* path = (t_path_state*)luaL_checkudata(L, 1, "Path"); - int stroke_width = luaL_checknumber(L, 2) * glist_getzoom(cnv); - - // Apply transformations to all coordinates - // Apply transformations to all coordinates - int obj_x = text_xpix((t_object*)obj, obj->canvas); - int obj_y = text_ypix((t_object*)obj, obj->canvas); - for (int i = 0; i < path->num_path_segments; i++) { - int x = path->path_segments[i * 2], y = path->path_segments[i * 2 + 1]; - - transform_point(ctx, &x, &y); - - int canvas_zoom = glist_getzoom(cnv); - path->path_segments[i * 2] = (x * canvas_zoom) + obj_x; - path->path_segments[i * 2 + 1] = (y * canvas_zoom) + obj_y; - } - - int totalSize = 0; - // Determine the total size needed - for (int i = 0; i < path->num_path_segments; i++) { - int x = path->path_segments[i * 2], y = path->path_segments[i * 2 + 1]; - // Calculate size for x and y - totalSize += snprintf(NULL, 0, "%i %i ", x, y); - } - char *coordinates = (char*)getbytes(totalSize + 1); // +1 for null terminator - - int offset = 0; - for (int i = 0; i < path->num_path_segments; i++) { - int x = path->path_segments[i * 2], y = path->path_segments[i * 2 + 1]; - int charsWritten = snprintf(coordinates + offset, totalSize - offset, "%i %i ", x, y); - if (charsWritten >= 0) { - offset += charsWritten; - } else { - break; - } - } - // Replace the trailing space with string terminator - if (offset > 0) { - coordinates[offset - 1] = '\0'; - } - - const char* tags[] = { ctx->object_tag, register_drawing(ctx) }; - - pdgui_vmess(0, "crr iiii ri rs rS", cnv, "create", "line", 0, 0, 0, 0, "-width", stroke_width, "-fill", ctx->current_color, "-tags", 2, tags); - - pdgui_vmess(0, "crs r", cnv, "coords", tags[1], coordinates); - - freebytes(coordinates, totalSize+1); - - return 0; -} - -static int fill_path(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - t_pdlua *obj = ctx->object; - - t_canvas *cnv = glist_getcanvas(obj->canvas); - +static int free_path(lua_State* L) +{ t_path_state* path = (t_path_state*)luaL_checkudata(L, 1, "Path"); - - // Apply transformations to all coordinates - int obj_x = text_xpix((t_object*)obj, obj->canvas); - int obj_y = text_ypix((t_object*)obj, obj->canvas); - for (int i = 0; i < path->num_path_segments; i++) { - int x = path->path_segments[i * 2], y = path->path_segments[i * 2 + 1]; - - transform_point(ctx, &x, &y); - - path->path_segments[i * 2] = x * glist_getzoom(cnv) + obj_x; - path->path_segments[i * 2 + 1] = y * glist_getzoom(cnv) + obj_y; - } - - int totalSize = 0; - // Determine the total size needed - for (int i = 0; i < path->num_path_segments; i++) { - int x = path->path_segments[i * 2], y = path->path_segments[i * 2 + 1]; - // Calculate size for x and y - totalSize += snprintf(NULL, 0, "%i %i ", x, y); - } - char *coordinates = (char*)getbytes(totalSize + 1); // +1 for null terminator - - int offset = 0; - for (int i = 0; i < path->num_path_segments; i++) { - int x = path->path_segments[i * 2], y = path->path_segments[i * 2 + 1]; - int charsWritten = snprintf(coordinates + offset, totalSize - offset, "%i %i ", x, y); - if (charsWritten >= 0) { - offset += charsWritten; - } else { - break; - } - } - - // Remove the trailing space - if (offset > 0) { - coordinates[offset - 1] = '\0'; - } - - const char* tags[] = { ctx->object_tag, register_drawing(ctx) }; - - pdgui_vmess(0, "crr r ri rs rS", cnv, "create", "polygon", coordinates, "-width", 0, "-fill", ctx->current_color, "-tags", 2, tags); - - freebytes(coordinates, totalSize+1); - - return 0; -} - - -static int translate(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - - if(ctx->num_transforms == 0) - { - ctx->transforms = getbytes(sizeof(gfx_transform)); - - } - else - { - ctx->transforms = resizebytes(ctx->transforms, ctx->num_transforms * sizeof(gfx_transform), (ctx->num_transforms + 1) * sizeof(gfx_transform)); - - } - - ctx->transforms[ctx->num_transforms].type = TRANSLATE; - ctx->transforms[ctx->num_transforms].x = luaL_checknumber(L, 1); - ctx->transforms[ctx->num_transforms].y = luaL_checknumber(L, 2); - - ctx->num_transforms++; - return 0; -} - -static int scale(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - - ctx->transforms = resizebytes(ctx->transforms, ctx->num_transforms * sizeof(gfx_transform), (ctx->num_transforms + 1) * sizeof(gfx_transform)); - - ctx->transforms[ctx->num_transforms].type = SCALE; - ctx->transforms[ctx->num_transforms].x = luaL_checknumber(L, 1); - ctx->transforms[ctx->num_transforms].y = luaL_checknumber(L, 2); - - ctx->num_transforms++; - return 0; -} - -static int reset_transform(lua_State* L) { - t_graphics_context *ctx = pop_graphics_context(L); - freebytes(ctx->transforms, ctx->num_transforms * sizeof(gfx_transform)); - ctx->transforms = NULL; - ctx->num_transforms = 0; + freebytes(path->path_segments, path->num_path_segments_allocated * sizeof(int)); return 0; } -#endif