diff options
-rw-r--r-- | doc/help-pdp_canvas.pd | 162 | ||||
-rw-r--r-- | modules/pdp_canvas.c | 417 |
2 files changed, 579 insertions, 0 deletions
diff --git a/doc/help-pdp_canvas.pd b/doc/help-pdp_canvas.pd new file mode 100644 index 0000000..0e61f56 --- /dev/null +++ b/doc/help-pdp_canvas.pd @@ -0,0 +1,162 @@ +#N canvas 121 0 828 668 10; +#X obj 234 469 pdp_xv; +#X obj 227 100 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 123 139 loop \$1; +#X obj 124 117 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 +1; +#X msg 119 80 open \$1; +#X obj 118 56 openpanel; +#X obj 103 39 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 184 101 stop; +#X obj 187 138 metro 70; +#X obj 124 178 pdp_yqt; +#X obj 36 177 pdp_v4l; +#X obj 36 145 metro 70; +#X obj 83 104 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 40 105 stop; +#X obj 716 529 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 716 581 pdp_control; +#X msg 716 554 thread \$1; +#X floatatom 716 642 5 0 0 0 - - -; +#X obj 716 613 route pdp_drop; +#X text 35 641 written by Yves Degoyon ( ydegoyon@free.fr ); +#X floatatom 189 169 5 0 0 0 - - -; +#X text 35 577 pdp_canvas : displaying several video sources; +#X text 34 591 constructor : pdp_canvas <width> <height> <nb inputs> +; +#X text 419 495 <-- you can move video sources by dragging them around +; +#X obj 470 99 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 366 138 loop \$1; +#X obj 367 116 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 +1; +#X msg 362 79 open \$1; +#X obj 361 55 openpanel; +#X obj 346 38 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 427 100 stop; +#X obj 430 137 metro 70; +#X obj 367 177 pdp_yqt; +#X obj 283 178 pdp_v4l; +#X obj 290 154 metro 70; +#X obj 337 113 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 294 114 stop; +#X floatatom 432 168 5 0 0 0 - - -; +#X obj 735 96 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 631 135 loop \$1; +#X obj 632 113 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 +1; +#X msg 627 76 open \$1; +#X obj 626 52 openpanel; +#X obj 611 35 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 692 97 stop; +#X obj 695 134 metro 70; +#X obj 632 174 pdp_yqt; +#X obj 548 176 pdp_v4l; +#X obj 548 152 metro 70; +#X obj 595 111 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 552 112 stop; +#X floatatom 697 165 5 0 0 0 - - -; +#X text 36 605 note : the maximum number of inputs is 10; +#X text 36 618 ( easily hackable in the code ); +#X text 544 397 Change offsets of first video source; +#X obj 548 351 pack f f; +#X floatatom 549 312 5 0 0 0 - - -; +#X floatatom 599 312 5 0 0 0 - - -; +#X obj 589 331 t b f; +#X text 564 294 X; +#X text 609 293 Y; +#X msg 548 375 offset 1 \$1 \$2; +#X obj 81 315 loadbang; +#X msg 173 540 select \$1 \$2; +#X msg 279 539 drag \$1 \$2; +#X msg 367 538 unselect; +#X msg 154 432 cursor 1; +#X msg 82 341 offset 2 320 0; +#X msg 81 365 offset 3 256 240; +#X obj 134 258 pdp_scale 320 240; +#X obj 307 255 pdp_scale 320 240; +#X obj 496 254 pdp_scale 320 240; +#X msg 83 393 dim 640 480; +#X obj 234 432 pdp_canvas 640 480 3; +#X obj 234 497 route press drag release; +#X connect 0 0 74 0; +#X connect 1 0 8 0; +#X connect 2 0 9 0; +#X connect 3 0 2 0; +#X connect 4 0 9 0; +#X connect 5 0 4 0; +#X connect 6 0 5 0; +#X connect 7 0 8 0; +#X connect 8 0 9 0; +#X connect 9 0 69 0; +#X connect 10 0 69 0; +#X connect 11 0 10 0; +#X connect 12 0 11 0; +#X connect 13 0 11 0; +#X connect 14 0 16 0; +#X connect 15 0 18 0; +#X connect 16 0 15 0; +#X connect 18 0 17 0; +#X connect 20 0 9 1; +#X connect 24 0 31 0; +#X connect 25 0 32 0; +#X connect 26 0 25 0; +#X connect 27 0 32 0; +#X connect 28 0 27 0; +#X connect 29 0 28 0; +#X connect 30 0 31 0; +#X connect 31 0 32 0; +#X connect 32 0 70 0; +#X connect 33 0 70 0; +#X connect 34 0 33 0; +#X connect 35 0 34 0; +#X connect 36 0 34 0; +#X connect 37 0 32 1; +#X connect 38 0 45 0; +#X connect 39 0 46 0; +#X connect 40 0 39 0; +#X connect 41 0 46 0; +#X connect 42 0 41 0; +#X connect 43 0 42 0; +#X connect 44 0 45 0; +#X connect 45 0 46 0; +#X connect 46 0 71 0; +#X connect 47 0 71 0; +#X connect 48 0 47 0; +#X connect 49 0 48 0; +#X connect 50 0 48 0; +#X connect 51 0 46 1; +#X connect 55 0 61 0; +#X connect 56 0 55 0; +#X connect 57 0 58 0; +#X connect 58 0 55 0; +#X connect 58 1 55 1; +#X connect 61 0 73 0; +#X connect 62 0 67 0; +#X connect 62 0 68 0; +#X connect 62 0 72 0; +#X connect 63 0 73 0; +#X connect 64 0 73 0; +#X connect 65 0 73 0; +#X connect 66 0 0 0; +#X connect 67 0 73 0; +#X connect 68 0 73 0; +#X connect 69 0 73 1; +#X connect 70 0 73 2; +#X connect 71 0 73 3; +#X connect 72 0 0 0; +#X connect 73 0 66 0; +#X connect 73 0 0 0; +#X connect 74 0 63 0; +#X connect 74 1 64 0; +#X connect 74 2 65 0; diff --git a/modules/pdp_canvas.c b/modules/pdp_canvas.c new file mode 100644 index 0000000..80ce63e --- /dev/null +++ b/modules/pdp_canvas.c @@ -0,0 +1,417 @@ +/* + * PiDiP module. + * Copyright (c) by Yves Degoyon (ydegoyon@free.fr) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* This object is an object allowing juxtaposition of frames from two inlets + * Written by Yves Degoyon + */ + + + +#include "pdp.h" +#include <math.h> + +static char *pdp_canvas_version = "pdp_canvas: version 0.1, display for several video sources, written by Yves Degoyon (ydegoyon@free.fr)"; + +#define MAX_CANVAS_INPUT 10 + +typedef struct pdp_canvas_struct +{ + t_object x_obj; + t_float x_f; + + t_outlet *x_outlet0; + t_int x_dropped; + t_int x_queue_id; + + t_int x_opacket; + + t_int x_current; + t_float x_xmouse; + t_float x_ymouse; + + t_int *x_packets; + t_int *x_widths; + t_int *x_heights; + t_float *x_xoffsets; + t_float *x_yoffsets; + t_int *x_sizes; + + t_int x_owidth; + t_int x_oheight; + t_int x_osize; + t_int x_nbinputs; + +} t_pdp_canvas; + +static void pdp_canvas_process_yv12(t_pdp_canvas *x) +{ + t_int px, py, ppx, ppy, ii, nbs; + short int *pY, *pU, *pV; + short int *piY, *piU, *piV; + t_pdp *oheader; + short int *odata; + t_pdp *iheader; + short int *idata; + + x->x_opacket = pdp_packet_new_image_YCrCb( x->x_owidth, x->x_oheight ); + oheader = pdp_packet_header(x->x_opacket); + odata = (short int *)pdp_packet_data(x->x_opacket); + + oheader->info.image.encoding = PDP_IMAGE_YV12; + oheader->info.image.width = x->x_owidth; + oheader->info.image.height = x->x_oheight; + + memset( odata, 0x00, (x->x_osize + (x->x_osize>>1))<<1 ); + + pY = odata; + pV = odata+x->x_osize; + pU = odata+x->x_osize+(x->x_osize>>2); + for ( py=0; py<x->x_oheight; py++ ) + { + for ( px=0; px<x->x_owidth; px++ ) + { + nbs=0; + for ( ii=0; ii<x->x_nbinputs; ii++) + { + if ( x->x_packets[ii] != -1 ) + { + if ( (px >= (int)x->x_xoffsets[ii]) && ( px < (int)x->x_xoffsets[ii] + x->x_widths[ii] ) + && (py >= (int)x->x_yoffsets[ii]) && ( py < (int)x->x_yoffsets[ii] + x->x_heights[ii] ) + ) + { + nbs++; + idata = (short int *)pdp_packet_data(x->x_packets[ii]); + piY = idata; + piV = idata+x->x_sizes[ii]; + piU = idata+x->x_sizes[ii]+(x->x_sizes[ii]>>2); + ppx = px-(int)x->x_xoffsets[ii]; + ppy = py-(int)x->x_yoffsets[ii]; + *(pY+py*x->x_owidth+px) += *(piY+ppy*x->x_widths[ii]+ppx); + if ( (px%2==0) && (py%2==0) ) + { + *(pU+(py>>1)*(x->x_owidth>>1)+(px>>1)) += + *(piU+(ppy>>1)*(x->x_widths[ii]>>1)+(ppx>>1)); + *(pV+(py>>1)*(x->x_owidth>>1)+(px>>1)) += + *(piV+(ppy>>1)*(x->x_widths[ii]>>1)+(ppx>>1)); + } + } + } + } + } + } + + return; +} + +static void pdp_canvas_sendpacket(t_pdp_canvas *x) +{ + /* unregister and propagate if valid dest packet */ + pdp_packet_pass_if_valid(x->x_outlet0, &x->x_opacket); +} + +static void pdp_canvas_process(t_pdp_canvas *x, t_int ni) +{ + int encoding; + t_pdp *header = 0; + + /* check if image data packets are compatible */ + if ( (header = pdp_packet_header(x->x_packets[ni])) + && (PDP_IMAGE == header->type)){ + + /* pdp_canvas_process inputs and write into active inlet */ + switch(pdp_packet_header(x->x_packets[ni])->info.image.encoding){ + + case PDP_IMAGE_YV12: + pdp_queue_add(x, pdp_canvas_process_yv12, pdp_canvas_sendpacket, &x->x_queue_id); + break; + + case PDP_IMAGE_GREY: + break; + + default: + /* don't know the type, so dont pdp_canvas_process */ + break; + + } + } +} + +static void pdp_canvas_offset(t_pdp_canvas *x, t_floatarg ni, t_floatarg xoffset, t_floatarg yoffset) +{ + if ( ( ni < 1 ) || ( ni > x->x_nbinputs ) ) + { + post( "pdp_canvas : offset : wrong source : %d : must be between 1 and %d", ni, x->x_nbinputs ); + return; + } + x->x_xoffsets[(int)ni-1] = xoffset; + x->x_yoffsets[(int)ni-1] = yoffset; +} + +static void pdp_canvas_select(t_pdp_canvas *x, t_floatarg X, t_floatarg Y) +{ + t_int ii; + + x->x_current = -1; + X = X*x->x_owidth; + Y = Y*x->x_oheight; + // post( "pdp_canvas : select %f %f", X, Y ); + for ( ii=0; ii<x->x_nbinputs; ii++) + { + if ( x->x_packets[ii] != -1 ) + { + if ( (X >= x->x_xoffsets[ii]) && ( X < x->x_xoffsets[ii] + x->x_widths[ii] ) + && (Y >= x->x_yoffsets[ii]) && ( Y < x->x_yoffsets[ii] + x->x_heights[ii] ) + ) + { + x->x_current = ii; + x->x_xmouse = X; + x->x_ymouse = Y; + } + } + } +} + +static void pdp_canvas_drag(t_pdp_canvas *x, t_floatarg X, t_floatarg Y) +{ + X = X*x->x_owidth; + Y = Y*x->x_oheight; + // post( "pdp_canvas : drag %f %f", dx, dy ); + if ( x->x_current != -1 ) + { + x->x_xoffsets[ x->x_current ] += (X-x->x_xmouse); + x->x_yoffsets[ x->x_current ] += (Y-x->x_ymouse); + x->x_xmouse = X; + x->x_ymouse = Y; + } +} + +static void pdp_canvas_unselect(t_pdp_canvas *x) +{ + x->x_current = -1; +} + +static void pdp_canvas_input(t_pdp_canvas *x, t_symbol *s, t_floatarg f, t_int ni) +{ + t_pdp *header; + short int *data; + + /* if this is a register_ro message or register_rw message, register with packet factory */ + + if (s== gensym("register_rw")) + { + /* release the packet */ + if ( x->x_packets[ni] != -1 ) + { + pdp_packet_mark_unused(x->x_packets[ni]); + x->x_packets[ni] = -1; + } + x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packets[ni], (int)f, pdp_gensym("image/YCrCb/*") ); + if ( x->x_packets[ni] != -1 ) + { + header = pdp_packet_header(x->x_packets[ni]); + x->x_widths[ni] = header->info.image.width; + x->x_heights[ni] = header->info.image.height; + x->x_sizes[ni] = x->x_widths[ni]*x->x_heights[ni]; + } + } + + if ((s == gensym("process")) && (-1 != x->x_packets[ni]) && (!x->x_dropped)) + { + /* add the process method and callback to the process queue */ + pdp_canvas_process(x, ni); + } +} + +static void pdp_canvas_input0(t_pdp_canvas *x, t_symbol *s, t_floatarg f) +{ + pdp_canvas_input(x, s, f, 0); +} + +static void pdp_canvas_input1(t_pdp_canvas *x, t_symbol *s, t_floatarg f) +{ + pdp_canvas_input(x, s, f, 1); +} + +static void pdp_canvas_input2(t_pdp_canvas *x, t_symbol *s, t_floatarg f) +{ + pdp_canvas_input(x, s, f, 2); +} + +static void pdp_canvas_input3(t_pdp_canvas *x, t_symbol *s, t_floatarg f) +{ + pdp_canvas_input(x, s, f, 3); +} + +static void pdp_canvas_input4(t_pdp_canvas *x, t_symbol *s, t_floatarg f) +{ + pdp_canvas_input(x, s, f, 4); +} + +static void pdp_canvas_input5(t_pdp_canvas *x, t_symbol *s, t_floatarg f) +{ + pdp_canvas_input(x, s, f, 5); +} + +static void pdp_canvas_input6(t_pdp_canvas *x, t_symbol *s, t_floatarg f) +{ + pdp_canvas_input(x, s, f, 6); +} + +static void pdp_canvas_input7(t_pdp_canvas *x, t_symbol *s, t_floatarg f) +{ + pdp_canvas_input(x, s, f, 7); +} + +static void pdp_canvas_input8(t_pdp_canvas *x, t_symbol *s, t_floatarg f) +{ + pdp_canvas_input(x, s, f, 8); +} + +static void pdp_canvas_input9(t_pdp_canvas *x, t_symbol *s, t_floatarg f) +{ + pdp_canvas_input(x, s, f, 9); +} + +static void pdp_canvas_free(t_pdp_canvas *x) +{ + t_int ii; + + pdp_queue_finish(x->x_queue_id); + for ( ii=0; ii<x->x_nbinputs; ii++) + { + pdp_packet_mark_unused(x->x_packets[ii]); + } + pdp_packet_mark_unused(x->x_opacket); + if ( x->x_packets ) freebytes( x->x_packets, x->x_nbinputs*sizeof(t_int) ); + if ( x->x_widths ) freebytes( x->x_widths, x->x_nbinputs*sizeof(t_int) ); + if ( x->x_heights ) freebytes( x->x_heights, x->x_nbinputs*sizeof(t_int) ); + if ( x->x_sizes ) freebytes( x->x_sizes, x->x_nbinputs*sizeof(t_int) ); + if ( x->x_xoffsets ) freebytes( x->x_xoffsets, x->x_nbinputs*sizeof(t_float) ); + if ( x->x_yoffsets ) freebytes( x->x_yoffsets, x->x_nbinputs*sizeof(t_float) ); +} + +t_class *pdp_canvas_class; + +void *pdp_canvas_new(t_symbol *s, int argc, t_atom *argv) +{ + t_pdp_canvas *x = (t_pdp_canvas *)pd_new(pdp_canvas_class); + t_int ii; + char *imes[32]; + + if ( argc != 3 ) + { + post( "pdp_canvas : wrong constructor : pdp_canvas <width> <height> <nb inputs> (argc=%d)", argc); + return NULL; + } + if ( argv[0].a_type != A_FLOAT || argv[1].a_type != A_FLOAT || + argv[2].a_type != A_FLOAT ) + { + post( "pdp_canvas : wrong constructor : pdp_canvas <width> <height> <nb inputs>"); + return NULL; + } + + x->x_owidth = ( (int) argv[0].a_w.w_float / 8 ) * 8; // round to a multiple of 8 + x->x_oheight = ( (int) argv[1].a_w.w_float / 8 ) * 8; // round to a multiple of 8 + x->x_osize = x->x_owidth*x->x_oheight; + x->x_nbinputs = (int) argv[2].a_w.w_float; + + if ( x->x_owidth < 0 ) + { + post( "pdp_canvas : wrong width : %d", x->x_owidth); + return NULL; + } + if ( x->x_oheight < 0 ) + { + post( "pdp_canvas : wrong height : %d", x->x_oheight); + return NULL; + } + if ( x->x_nbinputs < 0 ) + { + post( "pdp_canvas : wrong number of inputs : %d", x->x_nbinputs); + return NULL; + } + if ( x->x_nbinputs > MAX_CANVAS_INPUT ) + { + post( "pdp_canvas : number of inputs is too high : %d : only %d supported", + x->x_nbinputs, MAX_CANVAS_INPUT); + return NULL; + } + + post ( "pdp_canvas : new %dx%d canvas with %d inputs", x->x_owidth, x->x_oheight, x->x_nbinputs ); + + x->x_packets = ( t_int* ) getbytes( x->x_nbinputs*sizeof(t_int) ); + x->x_widths = ( t_int* ) getbytes( x->x_nbinputs*sizeof(t_int) ); + x->x_heights = ( t_int* ) getbytes( x->x_nbinputs*sizeof(t_int) ); + x->x_sizes = ( t_int* ) getbytes( x->x_nbinputs*sizeof(t_int) ); + x->x_xoffsets = ( t_float* ) getbytes( x->x_nbinputs*sizeof(t_float) ); + x->x_yoffsets = ( t_float* ) getbytes( x->x_nbinputs*sizeof(t_float) ); + + x->x_opacket = pdp_packet_new_image_YCrCb( x->x_owidth, x->x_oheight ); + + for ( ii=0; ii<x->x_nbinputs; ii++) + { + sprintf( (char*)imes, "pdp%d", ii ); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym((char*)imes) ); + x->x_packets[ii] = -1; + x->x_xoffsets[ii] = 0.; + x->x_yoffsets[ii] = 0.; + } + x->x_current = -1; + x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_canvas_setup(void) +{ + char *imes[32]; + + // post( pdp_canvas_version ); + pdp_canvas_class = class_new(gensym("pdp_canvas"), (t_newmethod)pdp_canvas_new, + (t_method)pdp_canvas_free, sizeof(t_pdp_canvas), 0, A_GIMME, A_NULL); + class_sethelpsymbol( pdp_canvas_class, gensym("pdp_canvas.pd") ); + + class_addmethod(pdp_canvas_class, (t_method)pdp_canvas_input0, gensym("pdp0"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_canvas_class, (t_method)pdp_canvas_input1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_canvas_class, (t_method)pdp_canvas_input2, gensym("pdp2"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_canvas_class, (t_method)pdp_canvas_input3, gensym("pdp3"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_canvas_class, (t_method)pdp_canvas_input4, gensym("pdp4"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_canvas_class, (t_method)pdp_canvas_input5, gensym("pdp5"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_canvas_class, (t_method)pdp_canvas_input6, gensym("pdp6"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_canvas_class, (t_method)pdp_canvas_input7, gensym("pdp7"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_canvas_class, (t_method)pdp_canvas_input8, gensym("pdp8"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_canvas_class, (t_method)pdp_canvas_input9, gensym("pdp9"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_canvas_class, (t_method)pdp_canvas_offset, gensym("offset"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_canvas_class, (t_method)pdp_canvas_select, gensym("select"), A_DEFFLOAT, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_canvas_class, (t_method)pdp_canvas_drag, gensym("drag"), A_DEFFLOAT, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_canvas_class, (t_method)pdp_canvas_unselect, gensym("unselect"), A_NULL); + +} + +#ifdef __cplusplus +} +#endif |