21 #define nonzero(x) ((x > 0) ? x : 1.)
22 #define MAXDIMENSIONS 10
23 #define CLOSETOBORDER 0.9
31 float previousPosition[MAXDIMENSIONS];
32 float previousVelocity[MAXDIMENSIONS];
35 float attrSize[MAXDIMENSIONS];
36 t_symbol* attrBoundaryMode;
37 float force[MAXDIMENSIONS];
42 void *push_new(t_symbol *msg,
long argc, t_atom *argv);
43 void push_bang(t_push *x);
44 void push_force(t_push *x, t_symbol *s,
long argc, t_atom *argv);
45 void push_position(t_push *x, t_symbol *s,
long argc, t_atom *argv);
46 void push_clear(t_push *x);
47 void push_assist(t_push *x,
void *b,
long msg,
long arg,
char *dst);
48 t_max_err push_attr_setdimensions(t_push *x,
void *attr,
long argc, t_atom *argv);
49 t_max_err push_attr_setfriction(t_push *x,
void *attr,
long argc, t_atom *argv);
50 t_max_err push_attr_setsize(t_push *x,
void *attr,
long argc, t_atom *argv);
51 t_max_err push_attr_getsize(t_push *x,
void *attr,
long *argc, t_atom **argv);
52 t_max_err push_attr_setBoundaryMode(t_push *x,
void *attr,
long argc, t_atom *argv);
63 int JAMOMA_EXPORT_MAXOBJ
main(
void)
67 common_symbols_init();
68 ps_clip = gensym(
"clip");
69 ps_bounce = gensym(
"bounce");
70 ps_repel = gensym(
"repel");
73 c = class_new(
"j.push",(method)push_new, (method)0L,
sizeof(t_push), (method)0L, A_GIMME, 0);
76 class_addmethod(c, (method)push_bang,
"bang", A_CANT, 0);
77 class_addmethod(c, (method)push_force,
"force", A_GIMME, 0);
78 class_addmethod(c, (method)push_position,
"position", A_GIMME, 0);
79 class_addmethod(c, (method)push_clear,
"clear", 0);
80 class_addmethod(c, (method)push_assist,
"assist", A_CANT, 0);
81 class_addmethod(c, (method)object_obex_dumpout,
"dumpout", A_CANT, 0);
83 CLASS_ATTR_FLOAT(c,
"friction", 0, t_push, attrFriction);
84 CLASS_ATTR_ACCESSORS(c,
"friction", NULL, push_attr_setfriction);
87 CLASS_ATTR_LONG(c,
"dimensions", 0, t_push, attrDimensions);
88 CLASS_ATTR_ACCESSORS(c,
"dimensions", NULL, push_attr_setdimensions);
90 CLASS_ATTR_ATOM(c,
"size", 0, t_push, attrSize);
91 CLASS_ATTR_ACCESSORS(c,
"size", push_attr_getsize, push_attr_setsize);
94 CLASS_ATTR_SYM( c,
"boundary", 0, t_push, attrBoundaryMode);
95 CLASS_ATTR_ACCESSORS(c,
"boundary", NULL, push_attr_setBoundaryMode);
96 CLASS_ATTR_ENUM(c,
"boundary", 0, (
char*)
"none clip bounce fold repel");
99 class_register(CLASS_BOX, c);
105 #pragma mark Object life
109 void *push_new(t_symbol *msg,
long argc, t_atom *argv)
117 object_obex_store((
void *)x, _sym_dumpout, (
object *)outlet_new(x,NULL));
118 x->outlet = floatout(x);
119 x->attrDimensions = 3;
120 x->attrFriction = 0.1;
121 for (i=0; i<MAXDIMENSIONS; i++)
122 x->attrSize[i] = 40.0;
123 x->attrBoundaryMode = gensym(
"none");
125 attr_args_process(x, argc, argv);
135 #pragma mark attribute accessors
139 t_max_err push_attr_setdimensions(t_push *x,
void *attr,
long argc, t_atom *argv)
144 n = atom_getlong(argv);
146 if (n>MAXDIMENSIONS) n = MAXDIMENSIONS;
147 x->attrDimensions = n;
155 t_max_err push_attr_setfriction(t_push *x,
void *attr,
long argc, t_atom *argv)
160 f = atom_getfloat(argv);
161 if (f<=0.0 || f>=1.0) {
162 error(
"Invalid argument for friction. Must be in the range (0, 1)");
171 t_max_err push_attr_setsize(t_push *x,
void *attr,
long argc, t_atom *argv)
176 if ((argc==x->attrDimensions) && argv) {
177 for (i=0; i<x->attrDimensions; i++) {
178 f = atom_getfloat(argv);
184 post(
"j.push: Ignored faulty value for size");
190 t_max_err push_attr_getsize(t_push *x,
void *attr,
long *argc, t_atom **argv)
194 *argc = x->attrDimensions;
195 *argv = (t_atom*)sysmem_newptr((
sizeof(t_atom))*x->attrDimensions);
196 for (i=0; i<x->attrDimensions; i++) {
197 atom_setfloat(*argv+i, x->attrSize[i]);
205 t_max_err push_attr_setBoundaryMode(t_push *x,
void *attr,
long argc, t_atom *argv)
210 s = atom_getsym(argv);
211 if ((s==gensym(
"none")) || (s==ps_clip) || (s==gensym(
"wrap")) || (s==ps_bounce) || (s==ps_repel))
212 x->attrBoundaryMode = s;
225 void push_bang(t_push *x)
228 float position, velocity, vicinity, repel;
229 float rangeLow, rangeHigh;
231 a = (t_atom*)sysmem_newptr(
sizeof(Atom) * x->attrDimensions);
233 for (i=0; i<x->attrDimensions; i++) {
235 rangeHigh = 0.5*x->attrSize[i];
236 rangeLow = -rangeHigh;
239 if (x->attrBoundaryMode == ps_repel) {
241 vicinity = fabs(x->previousPosition[i])/rangeHigh;
242 vicinity = (vicinity-CLOSETOBORDER)/(1.0-CLOSETOBORDER);
243 TTLimit(vicinity, (
float)0.0, (
float)1.0);
244 repel = vicinity*x->previousPosition[i]/rangeHigh;
250 position = x->previousPosition[i] + (1.0-x->attrFriction)*x->previousVelocity[i] + x->force[i] - repel;
251 velocity = position - x->previousPosition[i];
254 if ((x->attrBoundaryMode==ps_clip) || (x->attrBoundaryMode==ps_repel)) {
255 TTLimit(position, rangeLow, rangeHigh);
256 velocity = position - x->previousPosition[i];
258 else if (x->attrBoundaryMode == gensym(
"wrap"))
259 TTInfWrap(position, rangeLow, rangeHigh);
260 else if (x->attrBoundaryMode == ps_bounce) {
262 if ((position*position) >= (rangeHigh*rangeHigh)) {
263 TTFold(position, rangeLow, rangeHigh);
265 velocity = -velocity;
269 x->previousPosition[i] = position;
270 x->previousVelocity[i] = velocity;
272 atom_setfloat(&a[i], position);
276 outlet_anything(x->outlet, _sym_list, x->attrDimensions, a);
282 void push_force(t_push *x, t_symbol *s,
long argc, t_atom *argv)
286 if (argc==x->attrDimensions) {
287 for (i=0; i<x->attrDimensions; i++) {
288 x->force[i] = atom_getfloat(argv);
293 post(
"j.push: force vector has wrong dimension");
300 void push_clear(t_push *x)
304 for (i=0; i< x->attrDimensions; i++) {
305 x->previousPosition[i] = 0.0;
306 x->previousVelocity[i] = 0.0;
314 void push_position(t_push *x, t_symbol *s,
long argc, t_atom *argv)
319 if ((argc==x->attrDimensions) && argv) {
320 for (i=0; i<x->attrDimensions; i++) {
321 max = 0.5*x->attrSize[i];
323 f = atom_getfloat(argv);
324 TTLimit(f, min, max);
325 x->previousPosition[i] = f;
326 x->previousVelocity[i] = 0.0;
336 void push_assist(t_push *x,
void *b,
long msg,
long arg,
char *dst)
343 strcpy(dst,
"(list) force applied to object");
352 strcpy(dst,
"(list) resulting position of object");
355 strcpy(dst,
"dumpout");
int JAMOMA_EXPORT_MAXOBJ main(void)
Set up this class as a Max external the first time an object of this kind is instantiated.
t_class * this_class
Required. Global pointing to this class.