Commit ffed7406 authored by Ivica Bukvic's avatar Ivica Bukvic
Browse files

added work-in-progress expansion for the svg-based scalars by Jonathan Wilkes

parent e4ddd80d
......@@ -1581,7 +1581,7 @@ void *canvas_getblock(t_class *blockclass, t_canvas **canvasp)
/* redraw all "scalars" (do this if a drawing command is changed.)
LATER we'll use the "template" information to select which ones we
redraw. Action = 0 for redraw, 1 for draw only, 2 for erase. */
static void glist_redrawall(t_glist *gl, int action)
static void glist_redrawall(t_template *template, t_glist *gl, int action)
{
//fprintf(stderr,"glist_redrawall\n");
t_gobj *g;
......@@ -1589,7 +1589,8 @@ static void glist_redrawall(t_glist *gl, int action)
for (g = gl->gl_list; g; g = g->g_next)
{
t_class *cl;
if (vis && g->g_pd == scalar_class)
if (vis && g->g_pd == scalar_class &&
template == template_findbyname(((t_scalar *)g)->sc_template))
{
if (action == 1)
{
......@@ -1604,7 +1605,7 @@ static void glist_redrawall(t_glist *gl, int action)
else scalar_redraw((t_scalar *)g, gl);
}
else if (g->g_pd == canvas_class)
glist_redrawall((t_glist *)g, action);
glist_redrawall(template, (t_glist *)g, action);
}
if (glist_isselected(glist_getcanvas(gl), (t_gobj *)gl)) {
sys_vgui("pdtk_select_all_gop_widgets .x%lx %lx %d\n", glist_getcanvas(gl), gl, 1);
......@@ -1617,7 +1618,7 @@ void canvas_redrawallfortemplate(t_template *template, int action)
t_canvas *x;
/* find all root canvases */
for (x = canvas_list; x; x = x->gl_next)
glist_redrawall(x, action);
glist_redrawall(template, x, action);
}
/* find the template defined by a canvas, and redraw all elements
......@@ -1639,7 +1640,7 @@ void canvas_redrawallfortemplatecanvas(t_canvas *x, int action)
if (argv[0].a_type != A_SYMBOL || argv[1].a_type != A_SYMBOL
|| argv[0].a_w.w_symbol != s1)
continue;
tmpl = template_findbyname(argv[1].a_w.w_symbol);
tmpl = template_findbyname(canvas_makebindsym(argv[1].a_w.w_symbol));
canvas_redrawallfortemplate(tmpl, action);
}
canvas_redrawallfortemplate(0, action);
......
......@@ -113,7 +113,7 @@ void glist_delete(t_glist *x, t_gobj *y)
//fprintf(stderr,"glist_delete YES\n");
t_gobj *g;
t_object *ob;
t_template *tmpl;
t_template *tmpl;
t_gotfn chkdsp = zgetfn(&y->g_pd, gensym("dsp"));
t_canvas *canvas = glist_getcanvas(x);
int drawcommand = class_isdrawcommand(y->g_pd);
......@@ -162,10 +162,10 @@ void glist_delete(t_glist *x, t_gobj *y)
belong to our template, before deleting
it; we'll redraw them once it's deleted below. */
if (drawcommand)
{
tmpl = template_findbydrawcommand(y);
canvas_redrawallfortemplate(tmpl, 2);
}
{
tmpl = template_findbydrawcommand(y);
canvas_redrawallfortemplate(tmpl, 2);
}
if (glist_isvisible(canvas))
gobj_vis(y, x, 0);
if (x->gl_editor && (ob = pd_checkobject(&y->g_pd))) {
......@@ -194,7 +194,7 @@ void glist_delete(t_glist *x, t_gobj *y)
pd_free(&y->g_pd);
if (chkdsp) canvas_update_dsp();
if (drawcommand)
canvas_redrawallfortemplate(tmpl, 1);
canvas_redrawallfortemplate(tmpl, 1);
canvas_setdeleting(canvas, wasdeleting);
x->gl_valid = ++glist_valid;
if (late_rtext_free) {
......@@ -1200,16 +1200,16 @@ static void graph_displace_withtag(t_gobj *z, t_glist *glist, int dx, int dy)
{
// first check for legacy objects that don't offer displacefnwtag and fallback on the old way of doing things
t_gobj *g;
/* special case for scalars, which have a group for
the transform matrix */
for (g = x->gl_list; g; g = g->g_next)
{
if (pd_class((t_pd *)g) == scalar_class &&
g->g_pd->c_wb->w_displacefnwtag != NULL)
{
(*(g->g_pd->c_wb->w_displacefnwtag))(g, glist, dx, dy);
}
}
/* special case for scalars, which have a group for
the transform matrix */
for (g = x->gl_list; g; g = g->g_next)
{
if (pd_class((t_pd *)g) == scalar_class &&
g->g_pd->c_wb->w_displacefnwtag != NULL)
{
(*(g->g_pd->c_wb->w_displacefnwtag))(g, glist, dx, dy);
}
}
for (g = x->gl_list; g; g = g->g_next) {
//fprintf(stderr,"shouldvis %d %d\n", gobj_shouldvis(g, glist), gobj_shouldvis(g, x));
if (g && gobj_shouldvis(g, x) && g->g_pd->c_wb->w_displacefnwtag == NULL && pd_class((t_pd *)g) != garray_class) {
......
......@@ -154,6 +154,11 @@ void scalar_getbasexy(t_scalar *x, t_float *basex, t_float *basey)
extern int array_joc;
extern void template_notifyforscalar(t_template *template, t_glist *owner,
t_scalar *sc, t_symbol *s, int argc, t_atom *argv);
static int sc_isentered = 0;
static t_scalar *sc_entered = 0;
static void scalar_getrect(t_gobj *z, t_glist *owner,
int *xp1, int *yp1, int *xp2, int *yp2)
{
......@@ -165,6 +170,27 @@ static void scalar_getrect(t_gobj *z, t_glist *owner,
t_gobj *y;
t_float basex, basey;
/* hack for enter/leave struct notifications */
if (sc_entered == x)
{
if (sc_isentered == 1)
{
/* change value to see if there's a call
to scalar_click the next time around. Of
course it will be too late so we'll be
one pixel off, but it's better than nothing.
*/
sc_isentered = -1;
}
else if (sc_isentered == -1)
{
t_atom at[1];
template_notifyforscalar(template, owner, x, gensym("leave"), 1, at);
sc_entered = 0;
sc_isentered = 0;
}
}
// EXPERIMENTAL: we assume that entire canvas is withing the rectangle--this is for arrays
// with "jump on click" enabled TODO: test for other regressions (there shouuld not be any
// provided the global variable array_joc is properly maintained)
......@@ -210,7 +236,7 @@ static void scalar_getrect(t_gobj *z, t_glist *owner,
*yp2 = y2;
}
static void scalar_drawselectrect(t_scalar *x, t_glist *glist, int state)
void scalar_drawselectrect(t_scalar *x, t_glist *glist, int state)
{
if (state)
{
......@@ -231,7 +257,27 @@ static void scalar_drawselectrect(t_scalar *x, t_glist *glist, int state)
}
}
static void scalar_select(t_gobj *z, t_glist *owner, int state)
/* This is a workaround. Since scalars are contained within a tkpath
group, and since tkpath groups don't have coords, we have to fudge
things with regard to Pd-l2ork's normal *_displace_withtag functionality.
(Additionally, we can't just fall back to the old displace method
because it too assumes the canvas item has an xy coord.)
We draw the selection rect but don't add the scalar to the
"selected" tag. This means when Pd-l2ork issues the canvas "move"
command, our scalar doesn't go anywhere. Instead we get the callback
to scalar_displace_withtag and do another workaround to get the
new position and feed it to the scalar's matrix.
This creates a problem with gop canvases, and yet _another_ partial
workaround. We need the global variable below to let the so that
we can figure out whether the displace call is coming from the scalar
itself or from a parent graph. This means scalars won't currently
respond properly in nested gops. (I think that requires a window
item on the canvas to replace the current gop rect.)
*/
t_glist *select_owner = 0; /* kludge variable used by displace_withtag fn */
void scalar_select(t_gobj *z, t_glist *owner, int state)
{
//fprintf(stderr,"scalar_select %d\n", state);
t_scalar *x = (t_scalar *)z;
......@@ -250,7 +296,8 @@ static void scalar_select(t_gobj *z, t_glist *owner, int state)
}
gpointer_unset(&gp);
if (state) {
sys_vgui(".x%lx.c addtag selected withtag scalar%lx\n",
select_owner = owner;
sys_vgui(".x%lx.c addtag selected withtag blankscalar%lx\n",
glist_getcanvas(owner), x);
/* how do we navigate through a t_word list?
if (x->sc_vec) {
......@@ -270,8 +317,11 @@ static void scalar_select(t_gobj *z, t_glist *owner, int state)
glist_getcanvas(owner), (t_int)tag);
}*/
} else {
sys_vgui(".x%lx.c dtag scalar%lx selected\n",
select_owner = 0;
sys_vgui(".x%lx.c dtag blankscalar%lx selected\n",
glist_getcanvas(owner), x);
sys_vgui(".x%lx.c dtag .x%lx.x%lx.template%lx selected\n",
glist_getcanvas(owner), glist_getcanvas(owner), owner, x->sc_vec);
/* how do we navigate through a t_word list?
if (x->sc_vec) {
t_word *v = x->sc_vec;
......@@ -304,16 +354,17 @@ static void scalar_displace(t_gobj *z, t_glist *glist, int dx, int dy)
t_atom at[3];
t_gpointer gp;
int xonset, yonset, xtype, ytype, gotx, goty;
t_float basex = 0, basey = 0;
if (!template)
{
error("scalar: couldn't find template %s", templatesym->s_name);
return;
}
gotx = template_find_field(template, gensym("x"), &xonset, &xtype, &zz);
if (gotx && (xtype != DT_FLOAT))
if ((gotx && (xtype != DT_FLOAT)) || select_owner != glist)
gotx = 0;
goty = template_find_field(template, gensym("y"), &yonset, &ytype, &zz);
if (goty && (ytype != DT_FLOAT))
if ((goty && (ytype != DT_FLOAT)) || select_owner != glist)
goty = 0;
if (gotx)
*(t_float *)(((char *)(x->sc_vec)) + xonset) +=
......@@ -330,6 +381,13 @@ static void scalar_displace(t_gobj *z, t_glist *glist, int dx, int dy)
scalar_redraw(x, glist);
}
/* Very complicated at the moment. If a scalar is in a gop canvas, then
we don't need to update its x/y fields (if it even has them) when displacing
it. Otherwise we do. The global selected_owner variable is used to store
the "owner" canvas-- if it matches the glist parameter below then we know
the scalar is directly selected. If not it's in a gop canvas. (This doesn't
yet handle nested GOPs, unfortunately.)
*/
static void scalar_displace_withtag(t_gobj *z, t_glist *glist, int dx, int dy)
{
//fprintf(stderr,"scalar_displace_withtag %lx %d %d\n", (t_int)z, dx, dy);
......@@ -340,16 +398,17 @@ static void scalar_displace_withtag(t_gobj *z, t_glist *glist, int dx, int dy)
t_atom at[3];
t_gpointer gp;
int xonset, yonset, xtype, ytype, gotx, goty;
t_float basex = 0, basey = 0;
if (!template)
{
error("scalar: couldn't find template %s", templatesym->s_name);
return;
}
gotx = template_find_field(template, gensym("x"), &xonset, &xtype, &zz);
if (gotx && (xtype != DT_FLOAT))
if ((gotx && (xtype != DT_FLOAT)) || select_owner != glist)
gotx = 0;
goty = template_find_field(template, gensym("y"), &yonset, &ytype, &zz);
if (goty && (ytype != DT_FLOAT))
if ((goty && (ytype != DT_FLOAT)) || select_owner != glist)
goty = 0;
if (gotx)
*(t_float *)(((char *)(x->sc_vec)) + xonset) +=
......@@ -357,12 +416,20 @@ static void scalar_displace_withtag(t_gobj *z, t_glist *glist, int dx, int dy)
if (goty)
*(t_float *)(((char *)(x->sc_vec)) + yonset) +=
dy * (glist_pixelstoy(glist, 1) - glist_pixelstoy(glist, 0));
scalar_getbasexy(x, &basex, &basey);
gpointer_init(&gp);
gpointer_setglist(&gp, glist, x);
SETPOINTER(&at[0], &gp);
SETFLOAT(&at[1], (t_float)dx);
SETFLOAT(&at[2], (t_float)dy);
template_notify(template, gensym("displace"), 2, at);
t_float xscale = glist_xtopixels(glist, 1) - glist_xtopixels(glist, 0);
t_float yscale = glist_ytopixels(glist, 1) - glist_ytopixels(glist, 0);
sys_vgui(".x%lx.c itemconfigure {.scalar%lx} -matrix { {%g %g} {%g %g} {%d %d} }\n",
glist_getcanvas(glist), x->sc_vec, 1.0, 0.0, 0.0, 1.0, (int)glist_xtopixels(select_owner, basex) + (select_owner == glist ? 0 : dx), (int)glist_ytopixels(select_owner, basey) + (select_owner == glist ? 0 : dy));
//scalar_redraw(x, glist);
}
......@@ -377,6 +444,25 @@ static void scalar_delete(t_gobj *z, t_glist *glist)
/* nothing to do */
}
/* At preset, scalars have a three-level hierarchy in tkpath,
with two levels accessible from within Pd:
scalar - tkpath group with a matrix based on x/y fields,
| gop basexy, and gop/parent canvas scaling values.
| This group is not configurable by the user. This
| way [draw group] doesn't need extra code to include
| basexy and gop settings.
v
dgroup - user-facing group that is parent to all the scalar's
| drawing instructions. Its matrix and options can be
| accessed from [draw group]
v
draw - various drawing instructions (rectangles, paths, etc.).
Each has its own matrix and options that can be
accessed from the corresponding [draw] instruction.
The tag "blankscalar" is for scalars that don't have a visual
representation, but maybe this can just be merged with "scalar"
*/
static void scalar_vis(t_gobj *z, t_glist *owner, int vis)
{
//fprintf(stderr,"scalar_vis %d\n", vis);
......@@ -393,13 +479,28 @@ static void scalar_vis(t_gobj *z, t_glist *owner, int vis)
{
int x1 = glist_xtopixels(owner, basex);
int y1 = glist_ytopixels(owner, basey);
sys_vgui(".x%lx.c create prect %d %d %d %d -tags {scalar%lx}\n",
sys_vgui(".x%lx.c create prect %d %d %d %d -tags {blankscalar%lx}\n",
glist_getcanvas(owner), x1-1, y1-1, x1+1, y1+1, x);
}
else sys_vgui(".x%lx.c delete scalar%lx\n", glist_getcanvas(owner), x);
else sys_vgui(".x%lx.c delete blankscalar%lx\n", glist_getcanvas(owner), x);
return;
}
//else sys_vgui(".x%lx.c delete scalar%lx\n", glist_getcanvas(owner), x);
//else sys_vgui(".x%lx.c delete blankscalar%lx\n", glist_getcanvas(owner), x);
if (vis)
{
t_float xscale = glist_xtopixels(owner, 1) - glist_xtopixels(owner, 0);
t_float yscale = glist_ytopixels(owner, 1) - glist_ytopixels(owner, 0);
/* we could use the tag .template%lx for easy access from
the draw_class, but that's not necessary at this point */
sys_vgui(".x%lx.c create group -tags {.scalar%lx} "
"-matrix { {%g %g} {%g %g} {%d %d} }\n",
glist_getcanvas(owner), x->sc_vec,
1.0, 0.0, 0.0, 1.0, (int)glist_xtopixels(owner, basex), (int)glist_ytopixels(owner, basey)
);
sys_vgui(".x%lx.c create group -tags {.dgroup%lx} -parent {.scalar%lx}\n",
glist_getcanvas(owner), x->sc_vec, x->sc_vec);
}
for (y = templatecanvas->gl_list; y; y = y->g_next)
{
......@@ -407,6 +508,9 @@ static void scalar_vis(t_gobj *z, t_glist *owner, int vis)
if (!wb) continue;
(*wb->w_parentvisfn)(y, owner, x, x->sc_vec, template, basex, basey, vis);
}
if (!vis)
sys_vgui(".x%lx.c delete .scalar%lx\n", glist_getcanvas(owner), x->sc_vec);
sys_unqueuegui(x);
if (glist_isselected(owner, &x->sc_gobj))
{
......@@ -433,9 +537,6 @@ void scalar_redraw(t_scalar *x, t_glist *glist)
//sys_queuegui(x, glist, scalar_doredraw);
}
extern void template_notifyforscalar(t_template *template, t_glist *owner,
t_scalar *sc, t_symbol *s, int argc, t_atom *argv);
int scalar_doclick(t_word *data, t_template *template, t_scalar *sc,
t_array *ap, struct _glist *owner,
t_float xloc, t_float yloc, int xpix, int ypix,
......@@ -485,6 +586,17 @@ static int scalar_click(t_gobj *z, struct _glist *owner,
//fprintf(stderr,"scalar_click %d %d\n", xpix, ypix);
t_scalar *x = (t_scalar *)z;
t_template *template = template_findbyname(x->sc_template);
/* hack for enter/leave notifications */
if (sc_isentered == 0)
{
t_atom at[1];
template_notifyforscalar(template, owner, x, gensym("enter"), 1, at);
sc_isentered = 1;
sc_entered = x;
}
else sc_isentered = 1;
return (scalar_doclick(x->sc_vec, template, x, 0,
owner, 0, 0, xpix, ypix, shift, alt, dbl, doit));
}
......
......@@ -5,6 +5,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h> /* for matrix transforms */
#include "m_pd.h"
#include "s_stuff.h" /* for sys_hostfontsize */
......@@ -951,6 +952,2216 @@ void fielddesc_setcoord(t_fielddesc *f, t_template *template,
}
}
/* ---------------- draw svg shapes and paths ---------------- */
/*
draws belong to templates and describe how the data in the template are to
be drawn. The coordinates of the draw (and other display features) can
be attached to fields in the template.
todo: draw_click doesn't work with paths yet
todo: some better way than drawcurve for defining click widgetbehaviors (just
checking for field variables and moving joints is too simplistic)
todo: make pathgetrect
*/
t_class *draw_class;
typedef struct _draw
{
t_object x_obj;
int x_flags; /* CLOSED and/or BEZ and/or NOMOUSE */
t_symbol *x_drawtype;
t_symbol *x_fill;
t_fielddesc x_fill_r;
t_fielddesc x_fill_g;
t_fielddesc x_fill_b;
t_fielddesc x_fillopacity;
t_fielddesc x_fillrule;
t_symbol *x_stroke;
t_fielddesc x_stroke_r;
t_fielddesc x_stroke_g;
t_fielddesc x_stroke_b;
int x_ndash;
t_fielddesc *x_strokedasharray; /* array of lengths */
t_fielddesc x_strokelinecap;
t_fielddesc x_strokelinejoin;
t_fielddesc x_strokemiterlimit;
t_fielddesc x_strokeopacity;
t_fielddesc x_strokewidth;
t_fielddesc x_rx; /* for rounded rectangles */
t_fielddesc x_ry;
int x_transform_n;
t_fielddesc *x_transform;
t_fielddesc x_width;
t_fielddesc x_vis;
int x_pathrect_cache; /* 0 to recalc on next draw_getrect call
1 for cached
-1 to turn off caching */
int x_x1; /* use these for caching path bbox */
int x_y1;
int x_x2;
int x_y2;
int x_nargs;
t_fielddesc *x_vec;
int *x_nargs_per_cmd; /* points per each path command */
int x_npathcmds;
char *x_pathcmds; /* for path commands */
t_canvas *x_canvas;
} t_draw;
static int is_svgpath_cmd(t_symbol *s)
{
/* 1 for absolute cmd, 2 for relative */
if (s == gensym("M") || s == gensym("Z") || s == gensym("L") ||
s == gensym("H") || s == gensym("V") || s == gensym("C") ||
s == gensym("S") || s == gensym("Q") || s == gensym("T") ||
s == gensym("A"))
return 1;
else if (s == gensym("m") || s == gensym("z") || s == gensym("l") ||
s == gensym("h") || s == gensym("v") || s == gensym("c") ||
s == gensym("s") || s == gensym("q") || s == gensym("t") ||
s == gensym("a"))
return 2;
else return 0;
}
static int path_ncmds(int argc, t_atom *argv)
{
int i, j = 0;
for(i = 0; i < argc; i++)
{
if (argv[i].a_type == A_SYMBOL && is_svgpath_cmd(atom_getsymbol(argv+i)))
j++;
}
return j;
}
t_draw *draw_getgroup(t_draw *x)
{
t_gobj *g;
t_draw *dgroup = 0;
t_template *templ;
t_symbol *s1 = gensym("draw");
t_symbol *s2 = gensym("group");
for(g = x->x_canvas->gl_list; g; g = g->g_next)
{
t_object *ob = pd_checkobject(&g->g_pd);
t_atom *argv;
if (!ob || ob->te_type != T_OBJECT ||
binbuf_getnatom(ob->te_binbuf) < 2)
continue;
argv = binbuf_getvec(ob->te_binbuf);
if (argv[0].a_type != A_SYMBOL || argv[1].a_type != A_SYMBOL
|| argv[0].a_w.w_symbol != s1 || argv[1].a_w.w_symbol != s2)
continue;
dgroup = (t_draw *)g;
break;
}
return (dgroup);
}
static void *draw_new(t_symbol *classsym, t_int argc, t_atom *argv)
{
t_draw *x = (t_draw *)pd_new(draw_class);
/* not sure about classname here... */
if (argc && argv->a_type == A_SYMBOL)
x->x_drawtype = atom_getsymbolarg(0, argc--, argv++);
else
{
pd_error(x, "draw: need an svg shape (rect, circle, path, etc.)");
}
int flags = 0;
int nxy, i;
t_fielddesc *fd;
x->x_canvas = canvas_getcurrent();
fielddesc_setfloat_const(&x->x_vis, 1);
while (1)
{
t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
if (!strcmp(firstarg->s_name, "-v") && argc > 1)
{
fielddesc_setfloatarg(&x->x_vis, 1, argv+1);
argc -= 2; argv += 2;
}
else if (!strcmp(firstarg->s_name, "-x"))
{
flags |= NOMOUSE;
argc -= 1; argv += 1;
}
else break;
}
x->x_flags = flags;
if (argc < 0) argc = 0;
if (x->x_drawtype == gensym("path"))
{
int ncmds = x->x_npathcmds = path_ncmds(argc, argv);
x->x_pathcmds = (char *)t_getbytes(ncmds * sizeof(char));
x->x_nargs_per_cmd = (int *)t_getbytes(ncmds * sizeof(int));
for (i = 0; i < ncmds; i++) x->x_nargs_per_cmd[i] = 0;
nxy = x->x_nargs = argc - ncmds;
}
else if (x->x_drawtype == gensym("group"))
{
nxy = 0;
x->x_nargs = 0;
x->x_vec = 0;
t_draw *dgroup = draw_getgroup(x);
if (dgroup)
{
pd_error(x, "draw group: only one group per canvas allowed");
return (0);
}
}
else /* all other shapes */
{
nxy = (argc + (argc & 1));
x->x_nargs = nxy;
}
x->x_vec = (t_fielddesc *)t_getbytes(nxy * sizeof(t_fielddesc));
if (argc && x->x_drawtype == gensym("path"))
{
if (argv->a_type != A_SYMBOL ||
atom_getsymbol(argv) != gensym("M"))
{
pd_error(x, "draw path: path data must start "
"with a moveto command (M)");
return 0;
}
}
int cmdn = -1; /* hack */
for (i = 0, fd = x->x_vec; i < argc; i++, argv++)
{
if (x->x_drawtype == gensym("path") &&
argv->a_type == A_SYMBOL &&
is_svgpath_cmd(atom_getsymbol(argv)))
{
x->x_pathcmds[++cmdn] = *(atom_getsymbol(argv)->s_name);
}
else
{
fielddesc_setfloatarg(fd++, 1, argv);
/* post("got a coord"); */
if (x->x_drawtype == gensym("path"))
{
(x->x_nargs_per_cmd[cmdn])++;
/* if we get a field variable, just
turn off the get_rect caching */
if (argv->a_type == A_SYMBOL)
x->x_pathrect_cache = -1;
}
}
}
if (argc & 1 && x->x_drawtype != gensym("path")) fielddesc_setfloat_const(fd, 0);
x->x_fill = gensym("\"\"");
fielddesc_setfloat_const(&x->x_fillopacity, 1);
fielddesc_setfloat_const(&x->x_fillrule, 0);
x->x_stroke = gensym("black");
fielddesc_setfloat_const(&x->x_strokelinecap, 0);
fielddesc_setfloat_const(&x->x_strokelinejoin, 0);
fielddesc_setfloat_const(&x->x_strokemiterlimit, 0);
fielddesc_setfloat_const(&x->x_strokeopacity, 1);
fielddesc_setfloat_const(&x->x_strokewidth, 1);
x->x_x1 = 0;
x->x_x2 = 0;
x->x_y1 = 0;
x->x_y2 = 0;
x->x_ndash = 0;
x->x_strokedasharray = (t_fielddesc *)t_getbytes(1 * sizeof(t_fielddesc));
x->x_transform_n = 0;
x->x_transform = (t_fielddesc *)t_getbytes(1 * sizeof(t_fielddesc));
char buf[50];
sprintf(buf, ".x%lx", (long unsigned int)x);
pd_bind(&x->x_obj.ob_pd, gensym(buf));
return (x);
}