diff options
332 files changed, 50297 insertions, 0 deletions
diff --git a/debug/gdb_pdp_load b/debug/gdb_pdp_load new file mode 100644 index 0000000..c27a048 --- /dev/null +++ b/debug/gdb_pdp_load @@ -0,0 +1,29 @@ +cd ~/pd/packet +file ~/pd/distro/pd/bin/pd.debug +# file ~/pd/distro/pd/bin/pd +#set args -noadc -nodac -lib pdp -lib opengl/pdp_opengl:scaf/pdp_scaf -nodac -noadc -path abstractions:opengl/abstractions opengl/doc/examples/example06.pd +set args -nodac -noadc -nomidi -lib pdp -path abstractions ../deadlocktest.pd +#set args -nodac -noadc -nomidi -lib pdp -path abstractions -nogui +#set args -nodac -noadc -nomidi -lib pdp -path abstractions ../xvdualtest.pd +#opengl/test/pdp_ogl_draw_limb.pd +# set args -lib pdp -nodac -noadc -path abstractions test/test_pdp_thread.pd +# set args -lib pdp -nodac -noadc test/test_pdp_ca.pd +# set args -r 44100 -alsa -frags 64 -lib pdp -nodac -noadc test/test_pdp_qt_read.pd +# dir ~/pd/distro/pd/src +dir include +dir modules +dir system +dir system/mmx +dir scaf/include +dir scaf/pdp + +# until i figure out how to stop pd without hanging it +# or set a breakpoint before a library is loaded +# i'll use the bng_new routine (alt-b) to stop + +break bng_new + +# uncomment this to break in the library loader +# break sys_load_lib + + diff --git a/debug/gdb_pdp_load_rt b/debug/gdb_pdp_load_rt new file mode 100644 index 0000000..7ab3681 --- /dev/null +++ b/debug/gdb_pdp_load_rt @@ -0,0 +1,10 @@ +cd /home/tom/pd/packet +file /home/tom/pd/distro/pd/bin/pd.debug +# file ~/pd/distro/pd/bin/pd +set args -rt -r 44100 -alsa -frags 64 -lib pdp -nodac -noadc -nogui test/test_pdp_qt_read.pd +dir modules +dir system +dir mmx +dir scaf +dir scaf/modules +dir scaf/system diff --git a/doc/examples/example01.pd b/doc/examples/example01.pd new file mode 100644 index 0000000..94db2ea --- /dev/null +++ b/doc/examples/example01.pd @@ -0,0 +1,45 @@ +#N canvas 657 0 518 446 10; +#X obj 133 414 pdp_xv; +#X obj 177 76 pdp_v4l; +#X obj 177 33 metro 40; +#X obj 176 8 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 35 149 pdp_conv; +#X obj 35 173 pdp_conv_sobel_edge; +#X obj 412 60 pdp_control; +#X msg 412 32 thread \$1; +#X obj 412 8 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X obj 133 352 pdp_gradient; +#X obj 133 288 pdp_motion_phase; +#X msg 254 30 type grey; +#X obj 35 125 pdp_del 8; +#X obj 35 198 pdp_gain 6; +#X msg 240 252 0.45; +#X text 223 125 8 frames delay; +#X text 223 149 smooth; +#X text 223 174 edge detect; +#X text 222 200 amplify; +#X text 232 6 process in greyscale; +#X text 322 287 motion phase shifter; +#X text 320 354 grey -> colour palette; +#X msg 36 323 rgb 1 0.5 0; +#X obj 133 252 pdp_add; +#X msg 133 216 debug; +#X connect 1 0 12 0; +#X connect 1 0 23 1; +#X connect 2 0 1 0; +#X connect 3 0 2 0; +#X connect 4 0 5 0; +#X connect 5 0 13 0; +#X connect 7 0 6 0; +#X connect 8 0 7 0; +#X connect 9 0 0 0; +#X connect 10 0 9 0; +#X connect 11 0 1 0; +#X connect 12 0 4 0; +#X connect 13 0 23 0; +#X connect 14 0 10 1; +#X connect 22 0 9 0; +#X connect 23 0 10 0; +#X connect 24 0 23 0; diff --git a/doc/examples/example02.pd b/doc/examples/example02.pd new file mode 100644 index 0000000..0a46e04 --- /dev/null +++ b/doc/examples/example02.pd @@ -0,0 +1,44 @@ +#N canvas 85 437 473 316 10; +#X obj 91 268 pdp_xv; +#X obj 91 73 pdp_v4l; +#X obj 91 30 metro 40; +#X obj 90 5 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 -1 +; +#X obj 326 57 pdp_control; +#X msg 326 29 thread \$1; +#X obj 326 5 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X text 146 3 process in greyscale; +#X obj 135 195 pdp_gain; +#X obj 135 222 pdp_gain; +#X msg 168 27 type yv12; +#X obj 91 129 pdp_mix; +#X msg 169 51 type grey; +#X obj 216 194 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -6 0 10 +-262144 -1 -1 0.62 256; +#X obj 139 103 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -6 0 10 +-262144 -1 -1 0.82 256; +#X obj 215 133 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -6 0 10 +-262144 -1 -1 8 256; +#X obj 135 162 pdp_del 25; +#X obj 216 173 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -6 0 10 +-262144 -1 -1 1.5 256; +#X text 289 177 gains clip at -1 \, 1; +#X msg 159 129 reset; +#X connect 1 0 11 0; +#X connect 2 0 1 0; +#X connect 3 0 2 0; +#X connect 5 0 4 0; +#X connect 6 0 5 0; +#X connect 8 0 9 0; +#X connect 9 0 11 1; +#X connect 10 0 1 0; +#X connect 11 0 0 0; +#X connect 11 0 16 0; +#X connect 12 0 1 0; +#X connect 13 0 9 1; +#X connect 14 0 11 2; +#X connect 15 0 16 1; +#X connect 16 0 8 0; +#X connect 17 0 8 1; +#X connect 19 0 16 0; diff --git a/doc/examples/example03.pd b/doc/examples/example03.pd new file mode 100644 index 0000000..0eddd0d --- /dev/null +++ b/doc/examples/example03.pd @@ -0,0 +1,86 @@ +#N canvas 141 84 841 685 10; +#X obj 68 318 pdp_noise; +#X obj 68 85 metro 40; +#X obj 68 58 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 68 484 pdp_del 50; +#X obj 112 424 pdp_gain; +#X floatatom 240 518 5 0 0; +#X obj 68 514 pdp_blur; +#X obj 243 499 hsl 128 15 0 1 0 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 10100 1; +#X floatatom 240 367 5 0 0; +#X obj 243 342 hsl 128 15 0 5 0 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 0 1; +#X floatatom 240 587 5 0 0; +#X obj 243 567 hsl 128 15 0 1 0 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 4100 1; +#X floatatom 239 428 5 0 0; +#X obj 242 409 hsl 128 15 -5 5 0 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 11900 1; +#X msg 15 460 reset; +#X obj 68 459 pdp_add; +#X obj 68 357 pdp_gain; +#X text 203 7 this example shows how to use a delay line with a loop +gain > 1 and some processing inside the loop to produce a plasma like +effect. (WARNING: this can produce a very intense strobe effect \, +so if you're sensitive to flashing lights please be careful...); +#X text 391 407 a |gain| > 1 ensures regeneration; +#X floatatom 119 56 5 0 0; +#X obj 68 582 pdp_motion_phase; +#X floatatom 133 459 5 0 0; +#X text 392 495 blur ensures spatial coupling (determines the speed +at which "blobs" move around the screen); +#X text 392 565 a motion phase effect to spice it up (this causes local +negative feedback around suddon changes); +#X msg 109 13 40; +#X msg 144 13 1000; +#X msg 109 250 type grey; +#X msg 109 135 type yv12; +#X obj 68 619 pdp_xv; +#X text 201 247 it also works for black and white \, but all negative +colours will be clipped to 0 (black) on output.; +#X text 393 340 mix in some noise to get it going (set blur to minimal +when starting so the added noise won't be blurred to black); +#X text 202 96 it illustrates one of the advantages of working in an +additive/subtractive colour space. (here yuv or YCrCb). since legal +colours can be both positive and negative \, the analogy with audio +signals is easily drawn. this network can be seen as a nonlinear feedback +delay network. (nonlinear because of the saturating gain). the image +delay line can be seen as a parallel delay line \, one for each pixel. +coupling between the delays is done using a spatial blur effect. the +additional temporal filtering isn't necessary \, but it produces a +nice additional effect.; +#X obj 534 661 pdp_control; +#X obj 534 684 print; +#X msg 534 637 thread \$1; +#X obj 534 614 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X connect 0 0 16 0; +#X connect 1 0 0 0; +#X connect 2 0 1 0; +#X connect 3 0 6 0; +#X connect 4 0 15 1; +#X connect 6 0 20 0; +#X connect 7 0 5 0; +#X connect 7 0 6 1; +#X connect 9 0 8 0; +#X connect 9 0 16 1; +#X connect 11 0 10 0; +#X connect 11 0 20 1; +#X connect 13 0 12 0; +#X connect 13 0 4 1; +#X connect 14 0 3 0; +#X connect 15 0 3 0; +#X connect 16 0 15 0; +#X connect 19 0 1 1; +#X connect 20 0 4 0; +#X connect 20 0 28 0; +#X connect 21 0 3 1; +#X connect 24 0 19 0; +#X connect 25 0 19 0; +#X connect 26 0 0 0; +#X connect 27 0 0 0; +#X connect 32 0 33 0; +#X connect 34 0 32 0; +#X connect 35 0 34 0; diff --git a/doc/examples/example04.pd b/doc/examples/example04.pd new file mode 100644 index 0000000..501d283 --- /dev/null +++ b/doc/examples/example04.pd @@ -0,0 +1,85 @@ +#N canvas 89 39 931 736 10; +#X obj 68 204 pdp_noise; +#X obj 68 85 metro 40; +#X obj 68 58 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 112 303 pdp_gain; +#X floatatom 240 518 5 0 0; +#X obj 68 514 pdp_blur; +#X obj 243 499 hsl 128 15 0 1 0 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 6500 1; +#X floatatom 240 233 5 0 0; +#X obj 243 208 hsl 128 15 0 5 0 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 0 1; +#X floatatom 240 587 5 0 0; +#X obj 243 567 hsl 128 15 0 1 0 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 5000 1; +#X floatatom 239 307 5 0 0; +#X obj 242 288 hsl 128 15 -5 5 0 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 8920 1; +#X msg 15 339 reset; +#X obj 68 338 pdp_add; +#X obj 68 243 pdp_gain; +#X text 393 286 a |gain| > 1 ensures regeneration; +#X floatatom 119 56 5 0 0; +#X obj 68 582 pdp_motion_phase; +#X floatatom 133 338 5 0 0; +#X text 392 495 blur ensures spatial coupling (determines the speed +at which "blobs" move around the screen); +#X text 392 565 a motion phase effect to spice it up (this causes local +negative feedback around suddon changes); +#X msg 109 13 40; +#X msg 144 13 1000; +#X msg 146 119 type grey; +#X msg 147 90 type yv12; +#X obj 68 619 pdp_xv; +#X text 393 206 mix in some noise to get it going (set blur to minimal +when starting so the added noise won't be blurred to black); +#X obj 68 363 pdp_del 50; +#X text 242 14 this example is like example03 with a zoom / rotation +object thrown in; +#X obj 68 480 pdp_zrot; +#X floatatom 239 377 5 0 0; +#X obj 242 358 hsl 128 15 0.1 10 1 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 8567 1; +#X floatatom 239 446 5 0 0; +#X obj 242 426 hsl 128 15 0 360 0 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 300 1; +#X text 393 357 zoom; +#X msg 239 334 1; +#X msg 239 403 0; +#X msg 239 261 1; +#X text 392 420 rotation; +#X connect 0 0 15 0; +#X connect 1 0 0 0; +#X connect 2 0 1 0; +#X connect 3 0 14 1; +#X connect 5 0 18 0; +#X connect 6 0 4 0; +#X connect 6 0 5 1; +#X connect 8 0 7 0; +#X connect 8 0 15 1; +#X connect 10 0 9 0; +#X connect 10 0 18 1; +#X connect 12 0 11 0; +#X connect 12 0 3 1; +#X connect 13 0 28 0; +#X connect 14 0 28 0; +#X connect 15 0 14 0; +#X connect 17 0 1 1; +#X connect 18 0 3 0; +#X connect 18 0 26 0; +#X connect 19 0 28 1; +#X connect 22 0 17 0; +#X connect 23 0 17 0; +#X connect 24 0 0 0; +#X connect 25 0 0 0; +#X connect 28 0 30 0; +#X connect 30 0 5 0; +#X connect 31 0 30 1; +#X connect 32 0 31 0; +#X connect 33 0 30 2; +#X connect 34 0 33 0; +#X connect 36 0 32 0; +#X connect 37 0 34 0; +#X connect 38 0 12 0; diff --git a/doc/examples/example05.pd b/doc/examples/example05.pd new file mode 100644 index 0000000..02bc688 --- /dev/null +++ b/doc/examples/example05.pd @@ -0,0 +1,142 @@ +#N canvas 584 220 538 637 10; +#X obj 10 11 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 120 117 pdp_grey; +#X obj 435 194 pdp_control; +#X msg 435 167 thread 0; +#X obj 121 224 pdp_reg; +#X floatatom 81 7 5 0 0; +#X msg 35 10 stop; +#X floatatom 187 341 5 0 0; +#X obj 120 410 pdp_zrot; +#X floatatom 188 389 5 0 0; +#X obj 120 453 pdp_blur; +#X floatatom 188 435 5 0 0; +#X obj 120 92 pdp_noise; +#X obj 120 70 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#N canvas 623 175 567 478 nlmap 0; +#X obj 89 138 pdp_affine; +#X msg 123 108 -1; +#X msg 156 108 1; +#X obj 92 161 pdp_mul; +#X obj 95 189 pdp_gain; +#X floatatom 234 159 5 0 0; +#X msg 259 119 3.73; +#X obj 100 272 pdp_affine; +#X msg 134 242 -1; +#X msg 167 242 1; +#X obj 103 295 pdp_mul; +#X obj 106 323 pdp_gain; +#X floatatom 168 299 5 0 0; +#X msg 185 271 3.73; +#X obj 254 54 inlet; +#X obj 79 55 inlet; +#X obj 98 405 outlet; +#X obj 164 60 loadbang; +#X obj 190 84 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X text 260 220 this computes f(f(image)); +#X text 261 236 with f(x) = k*x*(1-x); +#X text 286 160 k; +#X text 260 253 the logistic map; +#X text 173 353 2 iterations are used to eliminate most of the high +frequency flickering; +#X connect 0 0 3 0; +#X connect 1 0 0 1; +#X connect 2 0 0 2; +#X connect 3 0 4 0; +#X connect 4 0 10 1; +#X connect 4 0 7 0; +#X connect 5 0 4 1; +#X connect 5 0 12 0; +#X connect 6 0 5 0; +#X connect 7 0 10 0; +#X connect 8 0 7 1; +#X connect 9 0 7 2; +#X connect 10 0 11 0; +#X connect 11 0 16 0; +#X connect 12 0 11 1; +#X connect 13 0 12 0; +#X connect 14 0 5 0; +#X connect 15 0 3 1; +#X connect 15 0 0 0; +#X connect 17 0 18 0; +#X connect 18 0 2 0; +#X connect 18 0 1 0; +#X connect 18 0 6 0; +#X connect 18 0 8 0; +#X connect 18 0 9 0; +#X restore 121 274 pd nlmap; +#X obj 73 576 pdp_xv; +#X floatatom 180 232 5 0 0; +#X text 196 275 2 iterations of the logistic map function; +#X obj 121 143 pdp_mul; +#X obj 297 94 pdp_noise; +#X obj 297 72 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 297 121 pdp_mul; +#X obj 73 521 pdp_saturation; +#X floatatom 166 490 5 0 0; +#X obj 30 36 metro 70; +#X msg 181 206 3.8; +#X msg 186 318 1.17; +#X msg 188 368 -2.33; +#X text 242 341 zoom; +#X text 241 391 rotate; +#X msg 188 414 0.33; +#X text 139 12 feedback with nonlinear mapping + zoom + rotate + blur +; +#X msg 82 -15 40; +#X msg 116 -15 500; +#X text 111 47 grey1; +#X obj 212 119 pdp_grey; +#X obj 212 94 pdp_noise; +#X obj 212 72 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X text 203 49 grey2; +#X text 287 50 colour1; +#X obj 388 95 pdp_noise; +#X obj 388 73 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X text 378 51 colour2; +#X msg 238 463 -0.5; +#X msg 282 463 0.5; +#X connect 0 0 24 0; +#X connect 1 0 18 1; +#X connect 1 0 18 0; +#X connect 3 0 2 0; +#X connect 4 0 14 0; +#X connect 5 0 24 1; +#X connect 6 0 24 0; +#X connect 7 0 8 1; +#X connect 8 0 10 0; +#X connect 9 0 8 2; +#X connect 10 0 4 1; +#X connect 11 0 10 1; +#X connect 12 0 1 0; +#X connect 13 0 12 0; +#X connect 14 0 8 0; +#X connect 14 0 22 0; +#X connect 16 0 14 1; +#X connect 18 0 4 0; +#X connect 19 0 21 1; +#X connect 19 0 21 0; +#X connect 20 0 19 0; +#X connect 21 0 4 0; +#X connect 22 0 15 0; +#X connect 23 0 22 1; +#X connect 24 0 4 0; +#X connect 25 0 16 0; +#X connect 26 0 7 0; +#X connect 27 0 9 0; +#X connect 30 0 11 0; +#X connect 32 0 5 0; +#X connect 33 0 5 0; +#X connect 35 0 4 0; +#X connect 36 0 35 0; +#X connect 37 0 36 0; +#X connect 40 0 4 0; +#X connect 41 0 40 0; +#X connect 43 0 23 0; +#X connect 44 0 23 0; diff --git a/doc/examples/example06.pd b/doc/examples/example06.pd new file mode 100644 index 0000000..82de63b --- /dev/null +++ b/doc/examples/example06.pd @@ -0,0 +1,76 @@ +#N canvas 92 197 605 585 10; +#X obj 24 85 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 42 25 stop; +#X msg 80 24 bang; +#X floatatom 122 25 5 0 0; +#X obj 60 485 pdp_xv; +#X obj 60 439 pdp_bq; +#X obj 111 334 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X obj 169 332 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 97 278 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X obj 154 277 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X msg 95 303 lr \$1; +#X msg 150 304 rl \$1; +#X msg 99 350 tb \$1; +#X msg 154 351 bt \$1; +#X obj 392 240 hsl 128 15 0.05 0.5 1 1 empty empty empty -2 -6 0 8 +-262144 -1 -1 3000 1; +#X obj 450 280 hsl 128 15 0.1 10 1 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 1900 1; +#X obj 391 307 t b f; +#X obj 394 345 pack s 0 0; +#X msg 391 378 \$1 \$2 \$3; +#X obj 447 310 t b f; +#X msg 301 199 lpf; +#X msg 333 200 apf; +#X obj 130 198 random 2; +#X obj 195 198 random 2; +#X obj 60 147 pdp_trigger; +#X obj 128 235 random 2; +#X obj 193 235 random 2; +#X obj 60 111 pdp_v4l; +#X obj 301 121 loadbang; +#X obj 60 53 metro 40; +#X text 388 219 frequency; +#X text 447 261 Q; +#X text 312 175 filter type; +#X connect 0 0 27 0; +#X connect 1 0 29 0; +#X connect 2 0 29 0; +#X connect 3 0 29 1; +#X connect 5 0 4 0; +#X connect 6 0 12 0; +#X connect 7 0 13 0; +#X connect 8 0 10 0; +#X connect 9 0 11 0; +#X connect 10 0 5 0; +#X connect 11 0 5 0; +#X connect 12 0 5 0; +#X connect 13 0 5 0; +#X connect 14 0 16 0; +#X connect 15 0 19 0; +#X connect 16 0 17 0; +#X connect 16 1 17 1; +#X connect 17 0 18 0; +#X connect 18 0 5 0; +#X connect 19 0 17 0; +#X connect 19 1 17 2; +#X connect 20 0 17 0; +#X connect 21 0 17 0; +#X connect 22 0 8 0; +#X connect 23 0 9 0; +#X connect 24 0 5 0; +#X connect 24 1 23 0; +#X connect 24 1 22 0; +#X connect 24 1 26 0; +#X connect 24 1 25 0; +#X connect 25 0 6 0; +#X connect 26 0 7 0; +#X connect 27 0 24 0; +#X connect 28 0 20 0; +#X connect 29 0 27 0; diff --git a/doc/examples/example07.pd b/doc/examples/example07.pd new file mode 100644 index 0000000..0c1ca8c --- /dev/null +++ b/doc/examples/example07.pd @@ -0,0 +1,73 @@ +#N canvas 466 98 659 764 10; +#X obj 18 649 pdp_xv; +#X obj 17 58 pdp_noise; +#X obj 16 14 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 17 325 pdp_add; +#X obj 17 277 pdp_gain; +#X obj 87 277 pdp_gain; +#X floatatom 127 238 5 0 0; +#X floatatom 174 238 5 0 0; +#X obj 17 120 pdp_mix; +#X floatatom 96 92 5 0 0; +#X obj 16 35 metro 40; +#X obj 17 87 pdp_grey; +#X msg 96 70 0.8; +#X floatatom 76 212 5 0 0; +#X obj 105 375 pdp_del 1; +#X msg 163 349 1; +#X obj 17 440 pdp_add; +#X obj 105 400 pdp_gain; +#X floatatom 208 382 5 0 0; +#X obj 17 243 pdp_blur; +#X msg 133 69 1; +#X floatatom 76 560 5 0 0; +#X obj 17 591 pdp_blur; +#X obj 18 619 pdp_gain; +#X floatatom 101 594 5 0 0; +#X msg 73 535 0.22; +#X msg 208 358 -0.61; +#X msg 132 214 4.3; +#X msg 178 215 -6.69; +#X msg 76 183 0.32; +#X msg 130 566 4; +#X text 287 386 subtract previous frame (time derivative); +#X text 97 47 some noise to get started; +#X text 235 216 construct a laplace like operator by blurring the image +and subtractiong the original from it; +#X text 371 12 a surface wave patch; +#X floatatom 67 8 5 0 0; +#X connect 1 0 11 0; +#X connect 2 0 10 0; +#X connect 3 0 16 0; +#X connect 4 0 3 0; +#X connect 5 0 3 1; +#X connect 6 0 4 1; +#X connect 7 0 5 1; +#X connect 8 0 5 0; +#X connect 8 0 14 0; +#X connect 8 0 19 0; +#X connect 9 0 8 2; +#X connect 10 0 1 0; +#X connect 11 0 8 0; +#X connect 12 0 9 0; +#X connect 13 0 19 1; +#X connect 14 0 17 0; +#X connect 15 0 14 1; +#X connect 16 0 22 0; +#X connect 16 0 8 1; +#X connect 17 0 16 1; +#X connect 18 0 17 1; +#X connect 19 0 4 0; +#X connect 20 0 9 0; +#X connect 21 0 22 1; +#X connect 22 0 23 0; +#X connect 23 0 0 0; +#X connect 24 0 23 1; +#X connect 25 0 21 0; +#X connect 26 0 18 0; +#X connect 27 0 6 0; +#X connect 28 0 7 0; +#X connect 29 0 13 0; +#X connect 30 0 24 0; +#X connect 35 0 10 1; diff --git a/doc/examples/example08.pd b/doc/examples/example08.pd new file mode 100644 index 0000000..9008ccd --- /dev/null +++ b/doc/examples/example08.pd @@ -0,0 +1,57 @@ +#N canvas 508 53 640 487 10; +#X obj 17 376 pdp_xv; +#X obj 17 11 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 17 32 metro 40; +#X floatatom 67 8 5 0 0 0 - - -; +#X obj 17 58 pdp_v4l; +#X obj 17 279 pdp_zrot; +#X obj 175 144 unpack 0 0; +#X obj 280 263 * 360; +#X obj 281 240 * 3; +#X msg 140 303 cursor; +#X obj 140 280 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X floatatom 325 226 5 0 0 0 - - -; +#X floatatom 325 249 5 0 0 0 - - -; +#X obj 175 108 route drag; +#X obj 17 231 pdp_mix; +#X floatatom 61 205 5 0 0 0 - - -; +#X obj 17 453 print; +#X obj 17 422 spigot; +#X obj 54 397 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X text 83 396 print the mouse event messages; +#X floatatom 175 180 5 0 0 0 - - -; +#X floatatom 240 182 5 0 0 0 - - -; +#X text 109 41 using the mouse pointer in an xv window to control a +patch; +#X text 262 108 drag event coordinates mapped to zoom and rotation +; +#X msg 86 178 0.98; +#X msg 47 177 0; +#X connect 0 0 13 0; +#X connect 0 0 17 0; +#X connect 1 0 2 0; +#X connect 2 0 4 0; +#X connect 3 0 2 1; +#X connect 4 0 14 0; +#X connect 5 0 0 0; +#X connect 5 0 14 1; +#X connect 6 0 8 0; +#X connect 6 0 20 0; +#X connect 6 1 7 0; +#X connect 6 1 21 0; +#X connect 7 0 5 2; +#X connect 8 0 5 1; +#X connect 9 0 0 0; +#X connect 10 0 9 0; +#X connect 11 0 8 1; +#X connect 12 0 7 1; +#X connect 13 0 6 0; +#X connect 14 0 5 0; +#X connect 15 0 14 2; +#X connect 17 0 16 0; +#X connect 18 0 17 1; +#X connect 24 0 15 0; +#X connect 25 0 15 0; diff --git a/doc/examples/example09.pd b/doc/examples/example09.pd new file mode 100644 index 0000000..2da1b51 --- /dev/null +++ b/doc/examples/example09.pd @@ -0,0 +1,35 @@ +#N canvas 43 348 497 337 10; +#X obj 88 104 pdp_grey2mask; +#X obj 88 148 pdp_gain; +#X obj 88 174 pdp_gain; +#X obj 88 198 pdp_gain; +#X msg 6 130 chanmask 1; +#X msg 6 180 chanmask 4; +#X msg 6 156 chanmask 2; +#X obj 6 103 loadbang; +#X floatatom 208 130 5 0 0; +#X floatatom 208 156 5 0 0; +#X floatatom 208 180 5 0 0; +#X obj 88 234 pdp_xv; +#X obj 88 40 metro 30; +#X obj 88 13 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 88 75 pdp_v4l; +#X text 26 267 a simple colour gradient patch using grey2mask and individual +channel gains (set with the binary chanmask); +#X connect 0 0 1 0; +#X connect 1 0 2 0; +#X connect 2 0 3 0; +#X connect 3 0 11 0; +#X connect 4 0 1 0; +#X connect 4 0 6 0; +#X connect 5 0 3 0; +#X connect 6 0 2 0; +#X connect 6 0 5 0; +#X connect 7 0 4 0; +#X connect 8 0 1 1; +#X connect 9 0 2 1; +#X connect 10 0 3 1; +#X connect 12 0 14 0; +#X connect 13 0 12 0; +#X connect 14 0 0 0; diff --git a/doc/examples/example10.pd b/doc/examples/example10.pd new file mode 100644 index 0000000..129209d --- /dev/null +++ b/doc/examples/example10.pd @@ -0,0 +1,55 @@ +#N canvas 147 266 497 337 10; +#X obj 88 104 pdp_grey2mask; +#X msg 6 130 chanmask 1; +#X msg 6 186 chanmask 4; +#X msg 6 158 chanmask 2; +#X obj 6 103 loadbang; +#X floatatom 207 130 5 0 0; +#X floatatom 253 130 5 0 0; +#X floatatom 299 130 5 0 0; +#X obj 88 234 pdp_xv; +#X obj 88 40 metro 30; +#X obj 88 13 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 88 75 pdp_v4l; +#X obj 88 148 pdp_cheby3o; +#X floatatom 345 130 5 0 0; +#X floatatom 207 158 5 0 0; +#X floatatom 253 158 5 0 0; +#X floatatom 299 158 5 0 0; +#X obj 88 176 pdp_cheby3o; +#X floatatom 345 158 5 0 0; +#X floatatom 207 186 5 0 0; +#X floatatom 253 186 5 0 0; +#X floatatom 299 186 5 0 0; +#X obj 88 204 pdp_cheby3o; +#X floatatom 345 186 5 0 0; +#X text 26 267 a more complex colour gradient patch using grey2mask +and individual channel chebychev colour shapers (set with the binary +chanmask); +#X connect 0 0 12 0; +#X connect 1 0 3 0; +#X connect 1 0 12 0; +#X connect 1 0 12 0; +#X connect 2 0 22 0; +#X connect 3 0 2 0; +#X connect 3 0 17 0; +#X connect 4 0 1 0; +#X connect 5 0 12 1; +#X connect 6 0 12 2; +#X connect 7 0 12 3; +#X connect 9 0 11 0; +#X connect 10 0 9 0; +#X connect 11 0 0 0; +#X connect 12 0 17 0; +#X connect 13 0 12 4; +#X connect 14 0 17 1; +#X connect 15 0 17 2; +#X connect 16 0 17 3; +#X connect 17 0 22 0; +#X connect 18 0 17 4; +#X connect 19 0 22 1; +#X connect 20 0 22 2; +#X connect 21 0 22 3; +#X connect 22 0 8 0; +#X connect 23 0 22 4; diff --git a/doc/examples/example11.pd b/doc/examples/example11.pd new file mode 100644 index 0000000..c427e9a --- /dev/null +++ b/doc/examples/example11.pd @@ -0,0 +1,80 @@ +#N canvas 210 529 680 275 10; +#N canvas 0 0 450 300 graph1 0; +#X array mapping 64 float 1; +#A 0 0.0916017 -0.201423 -0.477099 -0.711681 -0.884964 -0.982024 -0.9945 +-0.921318 -0.76878 -0.550026 -0.283897 0.00668462 0.296691 0.561142 +0.777261 0.926433 0.995809 0.979413 0.878658 0.702222 0.465302 0.188305 +-0.104911 -0.389091 -0.639758 -0.835322 -0.958937 -0.999957 -0.954848 +-0.827497 -0.628871 -0.37608 -0.0908956 0.202118 0.477722 0.712179 +0.885295 0.982158 0.994426 0.92104 0.768324 0.54943 0.283212 -0.00739881 +-0.297373 -0.561733 -0.777711 -0.926702 -0.995875 -0.979271 -0.87832 +-0.701718 -0.464675 -0.187609 0.105617 0.389745 0.640304 0.835712 0.959139 +0.999952 0.954637 0.827096 0.628316 0.375418; +#X coords 0 1 63 -1 200 140 1; +#X restore 242 21 graph; +#X msg 50 142 approx mapping; +#X obj 20 86 pdp_t; +#X text 235 165 -1 ----------- 0 ----------- 1; +#X obj 50 115 spigot; +#X obj 87 92 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 20 225 pdp_cheby 10; +#X obj 515 138 tabsend~ mapping; +#X obj 515 112 osc~; +#X floatatom 515 65 5 0 0; +#X floatatom 573 64 5 0 0; +#N canvas 0 0 450 300 fblock 0; +#X obj 36 36 inlet; +#X obj 101 35 inlet; +#X obj 42 196 outlet; +#X obj 104 83 samplerate~; +#X obj 59 158 +; +#X obj 103 144 *; +#X obj 103 59 t b b f; +#X text 200 35 fblock: compute block relative frequencies; +#X text 200 79 right inlet is also "active"; +#X text 201 119 main usage is to compute block synchronous frequencies +; +#X text 200 134 for spectral domain processing; +#X text 201 49 out = left + right * (sys samplerate / blocksize); +#X obj 101 115 / 64; +#X connect 0 0 4 0; +#X connect 1 0 6 0; +#X connect 3 0 12 0; +#X connect 4 0 2 0; +#X connect 5 0 4 1; +#X connect 6 0 4 0; +#X connect 6 1 3 0; +#X connect 6 2 5 1; +#X connect 12 0 5 0; +#X restore 515 89 pd fblock; +#X obj 20 40 metro 40; +#X obj 20 62 pdp_v4l; +#X msg 515 37 0.17; +#X text 236 208 send a signal to a table and use this as an intensity +mapping function in pdp_cheby; +#X obj 20 250 pdp_xv; +#X obj 20 15 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X msg 573 36 3; +#X msg 133 207 chanmask \$1; +#X floatatom 133 185 5 0 0; +#X msg 133 165 1; +#X connect 1 0 6 0; +#X connect 2 0 6 0; +#X connect 2 1 4 0; +#X connect 4 0 1 0; +#X connect 5 0 4 1; +#X connect 6 0 16 0; +#X connect 8 0 7 0; +#X connect 9 0 11 0; +#X connect 10 0 11 1; +#X connect 11 0 8 0; +#X connect 12 0 13 0; +#X connect 13 0 2 0; +#X connect 14 0 9 0; +#X connect 17 0 12 0; +#X connect 18 0 10 0; +#X connect 19 0 6 0; +#X connect 20 0 19 0; +#X connect 21 0 20 0; diff --git a/doc/examples/example12.pd b/doc/examples/example12.pd new file mode 100644 index 0000000..faa2730 --- /dev/null +++ b/doc/examples/example12.pd @@ -0,0 +1,42 @@ +#N canvas 578 52 635 489 10; +#X obj 83 183 metro 40; +#X obj 83 154 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 83 361 pdp_xv; +#X obj 165 299 pdp_loop 50; +#X obj 218 167 f 0; +#X obj 218 198 + 1; +#X obj 218 107 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 247 140 0; +#X obj 165 361 pdp_xv; +#X msg 165 259 store \$1; +#X obj 83 225 pdp_v4l; +#X msg 29 118 open /dev/video1; +#X floatatom 218 230 5 0 0; +#X obj 312 385 pdp_save_png_sequence 50; +#X obj 312 351 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 29 96 open /dev/video0; +#X text 337 349 <- click to save sequence in /tmp dir; +#X text 247 106 <- click to make a snapshot; +#X text 288 139 <- click to reset recording to loop; +#X text 273 229 <- recorded frame; +#X text 28 27 make loop of snapshots; +#X connect 0 0 10 0; +#X connect 0 0 3 0; +#X connect 1 0 0 0; +#X connect 3 0 8 0; +#X connect 3 0 13 0; +#X connect 4 0 5 0; +#X connect 5 0 4 1; +#X connect 5 0 9 0; +#X connect 5 0 12 0; +#X connect 6 0 4 0; +#X connect 7 0 4 1; +#X connect 9 0 3 0; +#X connect 10 0 2 0; +#X connect 10 0 3 0; +#X connect 11 0 10 0; +#X connect 14 0 13 0; +#X connect 15 0 11 0; diff --git a/doc/examples/example13.pd b/doc/examples/example13.pd new file mode 100644 index 0000000..369c895 --- /dev/null +++ b/doc/examples/example13.pd @@ -0,0 +1,104 @@ +#N canvas 419 114 799 646 10; +#X obj 450 429 pdp_xv; +#X obj 545 76 pdp_control; +#X msg 545 48 thread \$1; +#X obj 545 24 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X obj 134 40 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X msg 471 397 size 640 480; +#X obj 239 393 +; +#X obj 190 432 vsl 15 128 1 0 0 0 empty empty empty 0 -8 0 8 -262144 +-1 -1 0 1; +#X obj 190 393 -; +#X obj 59 386 hsl 128 15 0 1 0 0 empty empty empty -2 -6 0 8 -262144 +-1 -1 0 1; +#X obj 59 401 hsl 128 15 0 1 0 0 empty empty empty -2 -6 0 8 -262144 +-1 -1 0 1; +#X obj 59 416 hsl 128 15 0 1 0 0 empty empty empty -2 -6 0 8 -262144 +-1 -1 0 1; +#X obj 205 432 vsl 15 128 1 0 0 0 empty empty empty 0 -8 0 8 -262144 +-1 -1 0 1; +#X obj 220 432 vsl 15 128 1 0 0 0 empty empty empty 0 -8 0 8 -262144 +-1 -1 0 1; +#X obj 190 366 unpack f f; +#X obj 62 317 unpack f f; +#X obj 68 360 +; +#X obj 45 360 -; +#X obj 151 264 pack f f; +#X obj 215 265 pack f f; +#X msg 295 77 dim 320 240; +#X obj 134 72 metro 40; +#X msg 294 54 dim 640 480; +#X obj 134 100 pdp_v4l; +#X obj 450 366 pdp_zoom; +#X floatatom 450 308 5 0 0; +#X msg 553 311 centerx \$1; +#X floatatom 553 289 5 0 0; +#X floatatom 636 292 5 0 0; +#X msg 635 310 centery \$1; +#X obj 511 197 unpack f f f f; +#X obj 450 287 min; +#X obj 446 252 expr .5/($f1+.02); +#X obj 572 252 expr .5/($f1+.02); +#X msg 450 339 zoomx \$1 \, zoomy \$1; +#X msg 295 8 open /dev/video0; +#X msg 295 30 open /dev/video1; +#X obj 309 244 pack f f f f; +#X obj 134 156 pdp_diff; +#X text 208 156 <- compute difference between current and previous +frame; +#X obj 134 226 pdp_cog_abs_thresh 0.15; +#X text 331 492 using the blob tracker on a difference signal to detect +motion; +#X connect 2 0 1 0; +#X connect 3 0 2 0; +#X connect 4 0 21 0; +#X connect 5 0 0 0; +#X connect 6 0 13 0; +#X connect 8 0 7 0; +#X connect 14 0 12 0; +#X connect 14 0 8 0; +#X connect 14 0 6 0; +#X connect 14 1 8 1; +#X connect 14 1 6 1; +#X connect 15 0 17 0; +#X connect 15 0 16 0; +#X connect 15 0 10 0; +#X connect 15 1 16 1; +#X connect 15 1 17 1; +#X connect 16 0 11 0; +#X connect 17 0 9 0; +#X connect 18 0 15 0; +#X connect 19 0 14 0; +#X connect 20 0 23 0; +#X connect 21 0 23 0; +#X connect 22 0 23 0; +#X connect 23 0 38 0; +#X connect 24 0 0 0; +#X connect 25 0 34 0; +#X connect 26 0 24 0; +#X connect 27 0 26 0; +#X connect 28 0 29 0; +#X connect 29 0 24 0; +#X connect 30 0 27 0; +#X connect 30 1 32 0; +#X connect 30 2 28 0; +#X connect 30 3 33 0; +#X connect 31 0 25 0; +#X connect 32 0 31 0; +#X connect 33 0 31 1; +#X connect 34 0 24 0; +#X connect 35 0 23 0; +#X connect 36 0 23 0; +#X connect 37 0 30 0; +#X connect 38 0 24 0; +#X connect 38 0 40 0; +#X connect 40 1 18 0; +#X connect 40 1 37 0; +#X connect 40 2 19 0; +#X connect 40 2 37 2; +#X connect 40 3 18 1; +#X connect 40 3 37 1; +#X connect 40 4 19 1; +#X connect 40 4 37 3; diff --git a/doc/examples/example14.pd b/doc/examples/example14.pd new file mode 100644 index 0000000..f29e1b2 --- /dev/null +++ b/doc/examples/example14.pd @@ -0,0 +1,54 @@ +#N canvas 621 348 611 467 10; +#X obj 168 329 pdp_xv; +#X obj 168 78 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 168 142 pdp_v4l; +#X obj 168 108 metro 40; +#X msg 265 83 open /dev/video1; +#X floatatom 311 151 5 0 0; +#X obj 168 194 pdp_agc 0.5; +#X floatatom 310 211 5 0 0; +#X obj 168 245 pdp_contrast 0.5; +#X msg 4 157 chanmask \$1; +#X floatatom 4 133 5 0 0; +#X msg 4 104 1; +#X msg 35 104 3; +#X msg 67 104 5; +#X msg 99 104 7; +#X obj 314 192 hsl 128 15 0 1 0 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 12300 1; +#X obj 314 132 hsl 128 15 0 1 0 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 7900 1; +#X msg 265 58 open /dev/video0; +#X floatatom 310 272 5 0 0; +#X obj 314 253 hsl 128 15 0 3 0 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 0 1; +#X obj 168 298 pdp_saturation 0.5; +#X text 7 79 Y; +#X text 36 78 YCr; +#X text 68 79 YCb; +#X text 98 78 YCrCb; +#X text 25 15 some basic image enhancements; +#X text 13 60 agc color channels; +#X obj 183 166 pdp_flip_lr; +#X connect 1 0 3 0; +#X connect 2 0 27 0; +#X connect 3 0 2 0; +#X connect 4 0 2 0; +#X connect 5 0 6 1; +#X connect 6 0 8 0; +#X connect 7 0 8 1; +#X connect 8 0 20 0; +#X connect 9 0 6 0; +#X connect 10 0 9 0; +#X connect 11 0 10 0; +#X connect 12 0 10 0; +#X connect 13 0 10 0; +#X connect 14 0 10 0; +#X connect 15 0 7 0; +#X connect 16 0 5 0; +#X connect 17 0 2 0; +#X connect 18 0 20 1; +#X connect 19 0 18 0; +#X connect 20 0 0 0; +#X connect 27 0 6 0; diff --git a/doc/examples/example15.pd b/doc/examples/example15.pd new file mode 100644 index 0000000..5301fc0 --- /dev/null +++ b/doc/examples/example15.pd @@ -0,0 +1,27 @@ +#N canvas 632 359 559 496 10; +#X obj 127 57 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 127 81 metro 40; +#X obj 148 57 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 126 110 pdp_v4l; +#X msg 229 56 open /dev/video0; +#X msg 228 80 open /dev/video1; +#X obj 126 151 pdp_motion_fade 1; +#X obj 126 174 pdp_contrast 0.16; +#X obj 126 199 pdp_mul; +#X obj 126 224 pdp_gain 22; +#X text 7 2 using motion_fade \, contrast \, mul and gain to get a +motion triggered effect; +#X obj 126 258 pdp_xv; +#X connect 0 0 1 0; +#X connect 1 0 3 0; +#X connect 2 0 1 0; +#X connect 3 0 6 0; +#X connect 4 0 3 0; +#X connect 5 0 3 0; +#X connect 6 0 7 0; +#X connect 7 0 8 1; +#X connect 7 0 8 0; +#X connect 8 0 9 0; +#X connect 9 0 11 0; diff --git a/doc/introduction/control.pd b/doc/introduction/control.pd new file mode 100644 index 0000000..3898e1e --- /dev/null +++ b/doc/introduction/control.pd @@ -0,0 +1,17 @@ +#N canvas 372 355 668 154 10; +#X obj 33 107 pdp_xv; +#X obj 33 57 pdp_v4l; +#X msg 33 12 bang; +#X obj 33 81 pdp_trigger; +#X obj 33 35 metro 1000; +#X obj 105 108 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X text 140 20 pdp_trigger sends out a bang message on the right outlet +before it passes the incoming pdp message on the left outlet.; +#X msg 73 12 stop; +#X connect 1 0 3 0; +#X connect 2 0 4 0; +#X connect 3 0 0 0; +#X connect 3 1 5 0; +#X connect 4 0 1 0; +#X connect 7 0 4 0; diff --git a/doc/introduction/input_output.pd b/doc/introduction/input_output.pd new file mode 100644 index 0000000..07aa793 --- /dev/null +++ b/doc/introduction/input_output.pd @@ -0,0 +1,82 @@ +#N canvas 250 34 894 848 10; +#X obj 107 427 pdp_v4l; +#X obj 107 53 metro 40; +#X msg 159 14 stop; +#X msg 107 14 bang; +#X msg 51 14 bang; +#X obj 107 695 pdp_xv; +#X msg 209 93 open /dev/video0; +#X msg 209 117 open /dev/video1; +#X text 347 95 you can choose the input device using the 'open' message. +the default is /dev/video0; +#X msg 209 142 close; +#X text 348 143 closes the video port; +#X msg 209 168 type yv12; +#X msg 209 192 type grey; +#X text 348 171 type sets the ouput image package type. currently only +yv12 (luma/chroma color) and greyscale are supported.; +#X msg 210 221 dim 320 240; +#X msg 210 244 dim 640 480; +#X text 348 215 dim sets the dimensions of the captured frame. please +note that in all objects dimensions and packet type (color/greyscale) +have to be the same to be combined (i.e. mixed); +#X msg 210 556 dim 320 240; +#X msg 210 579 dim 640 480; +#X text 349 559 dim sets the window dimensions; +#X msg 210 510 create; +#X msg 210 531 destroy; +#X text 208 447 pdp_xv ouputs video in a window using the xVideo extension. +if your graphics card/driver supports it you can have multiple output +windows. if a pdp message is received and a window is not open \, one +is created automaticly.; +#X text 349 513 use these messages to explicitly create/destroy the +window; +#X text 207 18 pdp_v4l grabs video from the video4linux device. it +grabs a frame whenever a bang message is received. the output rate +is limited by the maximum framerate of the video device. if there is +no device opened \, it will attempt to open /dev/video0; +#X msg 212 627 cursor \$1; +#X obj 212 607 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X text 348 627 enables/disables cursor in xv window; +#X msg 210 319 channel \$1; +#X floatatom 210 295 5 0 0 0 - - -; +#X text 347 320 sets the v4l channel (like tuner \, composite \, svideo +\, ...); +#X floatatom 210 359 5 0 0 0 - - -; +#X msg 210 383 freq \$1; +#X floatatom 271 359 5 0 0 0 - - -; +#X msg 271 383 freqMHz \$1; +#X text 346 359 sets the v4l tuner frequency (in v4l units and MHz) +; +#X text 347 655 specify the x window display; +#X msg 212 653 display :0; +#X obj 107 748 print; +#X text 211 745 the output channel sends mouse event messages (press/release/drag +and individual p/r/d for each button); +#X connect 0 0 5 0; +#X connect 1 0 0 0; +#X connect 2 0 1 0; +#X connect 3 0 1 0; +#X connect 4 0 0 0; +#X connect 5 0 38 0; +#X connect 6 0 0 0; +#X connect 7 0 0 0; +#X connect 9 0 0 0; +#X connect 11 0 0 0; +#X connect 12 0 0 0; +#X connect 14 0 0 0; +#X connect 15 0 0 0; +#X connect 17 0 5 0; +#X connect 18 0 5 0; +#X connect 20 0 5 0; +#X connect 21 0 5 0; +#X connect 25 0 5 0; +#X connect 26 0 25 0; +#X connect 28 0 0 0; +#X connect 29 0 28 0; +#X connect 31 0 32 0; +#X connect 32 0 0 0; +#X connect 33 0 34 0; +#X connect 34 0 0 0; +#X connect 37 0 5 0; diff --git a/doc/introduction/quicktime.pd b/doc/introduction/quicktime.pd new file mode 100644 index 0000000..2f32cfd --- /dev/null +++ b/doc/introduction/quicktime.pd @@ -0,0 +1,101 @@ +#N canvas 400 126 715 814 10; +#X obj 59 391 pdp_qt; +#X obj 59 462 pdp_xv; +#X floatatom 77 429 5 0 0; +#X floatatom 127 430 5 0 0; +#X obj 56 41 metro 40; +#X msg 56 13 bang; +#X msg 97 13 stop; +#X msg 15 13 bang; +#X obj 140 41 openpanel; +#X msg 140 66 open \$1; +#X msg 140 13 bang; +#X msg 140 92 close; +#X text 249 66 open/close for file access; +#X floatatom 140 120 5 0 0; +#X floatatom 140 146 5 0 0; +#X text 248 117 float on left inlet selects a frame for output; +#X msg 140 197 loop \$1; +#X obj 203 182 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X text 250 198 automatic looping can be enabled/disabled; +#X text 251 9 pdp_qt plays a quicktime movie.; +#X text 250 221 this enables automatic playback at the frame rate specified +in the movie file. in pdp_qt~ playback is synchronized to the audio +stream.; +#X obj 335 535 table array; +#X msg 142 341 dump array 0; +#X text 252 330 if the movie contains audio \, this command dumps the +audio data into an array specified by the first argument. the second +argument is the audio channel (default = 0 = left); +#X msg 142 291 stop; +#X text 251 289 stops automatic playback (same as autoplay 0); +#X msg 141 222 autoplay 1; +#X msg 142 267 play; +#X text 252 432 the second outlet outputs the current frame number. +the third outlet outputs the total number of frames in a movie when +it is opened.; +#X obj 56 786 pdp_xv; +#X obj 56 715 pdp_qt~; +#X obj 84 757 dac~; +#X msg 33 644 play; +#X obj 127 635 openpanel; +#X msg 127 660 open \$1; +#X msg 127 607 bang; +#X msg 9 760 close; +#X text 251 660 pdp_qt~ is the same as pdp_qt exept that it also outputs +the audio data corresponding to the current frame on its 2 rightmost +outlets. if there is a lag between audio and video a pdp_del object +can be inserted to delay the image. note that in order to get acceptable +audio quality with relatively few dropouts you might need to increase +the pd audio latency.; +#X msg 7 429 close; +#X msg 142 315 cont; +#X text 251 269 starts automatic playback (same as 0 \, autplay 1 \, +bang); +#X text 251 310 resumes automatic playback (same as autplay 1 \, bang) +; +#X msg 9 617 loop 1; +#X floatatom 78 645 5 0 0; +#X obj 448 535 tabplay~ array; +#X obj 448 576 dac~; +#X obj 448 506 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 126 685 dump array 0; +#X text 249 137 float on right inlet selects the frame to be read on +the next sync event (bang message / internal sync).; +#X connect 0 0 1 0; +#X connect 0 1 2 0; +#X connect 0 2 3 0; +#X connect 4 0 0 0; +#X connect 5 0 4 0; +#X connect 6 0 4 0; +#X connect 7 0 0 0; +#X connect 8 0 9 0; +#X connect 9 0 0 0; +#X connect 10 0 8 0; +#X connect 11 0 0 0; +#X connect 13 0 0 0; +#X connect 14 0 0 1; +#X connect 16 0 0 0; +#X connect 17 0 16 0; +#X connect 22 0 0 0; +#X connect 24 0 0 0; +#X connect 26 0 0 0; +#X connect 27 0 0 0; +#X connect 30 0 29 0; +#X connect 30 3 31 0; +#X connect 30 4 31 1; +#X connect 32 0 30 0; +#X connect 33 0 34 0; +#X connect 34 0 30 0; +#X connect 35 0 33 0; +#X connect 36 0 29 0; +#X connect 38 0 1 0; +#X connect 39 0 0 0; +#X connect 42 0 30 0; +#X connect 43 0 30 1; +#X connect 44 0 45 0; +#X connect 44 0 45 1; +#X connect 46 0 44 0; +#X connect 47 0 30 0; diff --git a/doc/introduction/traffic.pd b/doc/introduction/traffic.pd new file mode 100644 index 0000000..40f102d --- /dev/null +++ b/doc/introduction/traffic.pd @@ -0,0 +1,101 @@ +#N canvas 155 92 978 574 10; +#X msg 362 2 stop; +#X obj 362 27 metro 40; +#X obj 362 53 pdp_v4l; +#X obj 32 524 pdp_xv; +#X obj 847 336 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 847 388 pdp_control; +#X msg 847 361 thread \$1; +#X obj 434 56 hdl 15 1 1 4 empty empty empty 0 -6 0 8 -262144 -1 -1 +2; +#X obj 432 278 pdp_del 25; +#X obj 410 332 pdp_mix; +#X obj 457 305 hsl 128 15 0 1 0 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 6500 1; +#X floatatom 497 249 5 0 0; +#X text 457 83 packet router. second inlet sets destination outlet. +creation argument sets number of outlets.; +#X obj 240 333 pdp_snap; +#X obj 240 302 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X text 249 357 packet snapshot; +#X msg 262 301 snap; +#X obj 410 456 pdp_trigger; +#X text 508 463 before it passes the packet; +#X text 507 450 trigger sends a bang on right outlet; +#X obj 482 487 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X text 248 389 bang sends out packet; +#X obj 434 146 send packet; +#X text 524 138 pdp packets can be sent over send/receive pairs; +#X text 523 152 (not over netsend/netreceive pairs!); +#X obj 451 382 pdp_pps; +#X floatatom 451 412 5 0 0; +#X text 513 381 packet rate calculator; +#X obj 32 21 receive packet; +#X obj 203 254 pdp_reg; +#X text 68 222 a packet register; +#X text 58 235 (like int and float); +#X obj 32 81 pdp_mix; +#X obj 79 51 hsl 128 15 0 1 0 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 10500 1; +#X obj 32 136 pdp_conv; +#X obj 203 227 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X text 115 70 feedback; +#X obj 362 87 pdp_route 4; +#X text 107 82 is allowed; +#X obj 335 3 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X text 754 292 enable or disable processing; +#X text 754 307 in separate thread; +#X text 471 342 second inlet 0->1; +#X text 472 328 mix (crossfade) 2 packets.; +#X floatatom 83 111 5 0 0; +#X text 58 253 left: hot packet; +#X text 58 267 right: cold packet; +#X floatatom 847 449 5 0 0; +#X obj 847 420 route pdp_drop; +#X text 801 473 dropped packet counter; +#X text 43 159 convolution: default is blur; +#X text 135 110 number of passes; +#X text 248 373 snap takes snapshot; +#X text 134 118 comment; +#X text 431 185 packet delay line. second inlet sets delay. creation +argument sets total delay line length. WARNING: this uses a lot of +memory. keep the size small to prevent the system to start swapping +to disk.; +#X connect 0 0 1 0; +#X connect 1 0 2 0; +#X connect 2 0 37 0; +#X connect 4 0 6 0; +#X connect 5 0 48 0; +#X connect 6 0 5 0; +#X connect 7 0 37 1; +#X connect 8 0 9 1; +#X connect 9 0 17 0; +#X connect 9 0 25 0; +#X connect 10 0 9 2; +#X connect 11 0 8 1; +#X connect 13 0 3 0; +#X connect 14 0 13 0; +#X connect 16 0 13 0; +#X connect 17 0 3 0; +#X connect 17 1 20 0; +#X connect 25 0 26 0; +#X connect 28 0 32 0; +#X connect 29 0 3 0; +#X connect 32 0 34 0; +#X connect 33 0 32 2; +#X connect 34 0 32 1; +#X connect 34 0 3 0; +#X connect 35 0 29 0; +#X connect 37 0 29 1; +#X connect 37 1 13 1; +#X connect 37 2 8 0; +#X connect 37 2 9 0; +#X connect 37 3 22 0; +#X connect 39 0 1 0; +#X connect 44 0 34 1; +#X connect 48 0 47 0; diff --git a/doc/objects/README b/doc/objects/README new file mode 100644 index 0000000..94f8bb5 --- /dev/null +++ b/doc/objects/README @@ -0,0 +1,4 @@ +This directory contains help patches for the individual pdp modules and abstractions. +Use the pdp_help_input.pd and pdp_help_output.pd patches to setup your desired in/out for +the help patches. + diff --git a/doc/objects/pdp_abs.pd b/doc/objects/pdp_abs.pd new file mode 100644 index 0000000..eef5a94 --- /dev/null +++ b/doc/objects/pdp_abs.pd @@ -0,0 +1,21 @@ +#N canvas 504 211 500 438 10; +#X msg 77 38 start; +#X msg 124 38 stop; +#X obj 77 70 pdp_help_input; +#X obj 77 340 pdp_help_output; +#X obj 77 163 pdp_gain; +#X floatatom 128 135 5 0 0; +#X msg 128 109 0.5; +#X obj 77 296 pdp_gain; +#X msg 128 268 1; +#X text 229 235 absolute value; +#X obj 77 231 pdp_abs; +#X connect 0 0 2 0; +#X connect 1 0 2 0; +#X connect 2 0 4 0; +#X connect 4 0 10 0; +#X connect 5 0 4 1; +#X connect 6 0 5 0; +#X connect 7 0 3 0; +#X connect 8 0 7 1; +#X connect 10 0 7 0; diff --git a/doc/objects/pdp_add.pd b/doc/objects/pdp_add.pd new file mode 100644 index 0000000..fa5cd1f --- /dev/null +++ b/doc/objects/pdp_add.pd @@ -0,0 +1,34 @@ +#N canvas 180 63 511 383 10; +#X msg 77 38 start; +#X msg 124 38 stop; +#X obj 77 70 pdp_help_input; +#X obj 77 322 pdp_help_output; +#X obj 77 279 pdp_add; +#X obj 121 246 pdp_reg; +#X obj 196 183 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X text 229 181 click here; +#X obj 77 163 pdp_gain; +#X floatatom 128 135 5 0 0 0 - - -; +#X msg 128 109 0.5; +#X text 229 283 adds (and saturates) 2 packets; +#X msg 230 246 chanmask \$1; +#X floatatom 230 221 5 0 0 0 - - -; +#X msg 374 131 thread \$1; +#X obj 373 107 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 377 164 pdp_control; +#X connect 0 0 2 0; +#X connect 1 0 2 0; +#X connect 2 0 8 0; +#X connect 4 0 3 0; +#X connect 5 0 4 1; +#X connect 6 0 5 0; +#X connect 8 0 4 0; +#X connect 8 0 5 1; +#X connect 9 0 8 1; +#X connect 10 0 9 0; +#X connect 12 0 4 0; +#X connect 13 0 12 0; +#X connect 14 0 16 0; +#X connect 15 0 14 0; diff --git a/doc/objects/pdp_and.pd b/doc/objects/pdp_and.pd new file mode 100644 index 0000000..e352b16 --- /dev/null +++ b/doc/objects/pdp_and.pd @@ -0,0 +1,24 @@ +#N canvas 552 356 511 383 10; +#X msg 77 38 start; +#X msg 124 38 stop; +#X obj 77 70 pdp_help_input; +#X obj 77 322 pdp_help_output; +#X obj 121 246 pdp_reg; +#X obj 196 183 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X text 229 181 click here; +#X obj 77 163 pdp_gain; +#X floatatom 128 135 5 0 0; +#X msg 128 109 0.5; +#X obj 77 279 pdp_and; +#X text 229 283 bitwise and; +#X connect 0 0 2 0; +#X connect 1 0 2 0; +#X connect 2 0 7 0; +#X connect 4 0 10 1; +#X connect 5 0 4 0; +#X connect 7 0 10 0; +#X connect 7 0 4 1; +#X connect 8 0 7 1; +#X connect 9 0 8 0; +#X connect 10 0 3 0; diff --git a/doc/objects/pdp_bitdepth.pd b/doc/objects/pdp_bitdepth.pd new file mode 100644 index 0000000..4c5ae11 --- /dev/null +++ b/doc/objects/pdp_bitdepth.pd @@ -0,0 +1,32 @@ +#N canvas 504 211 500 438 10; +#X msg 140 61 start; +#X msg 187 61 stop; +#X obj 140 93 pdp_help_input; +#X obj 140 352 pdp_help_output; +#X obj 140 308 pdp_gain; +#X msg 191 280 1; +#X floatatom 219 209 8 0 0; +#X obj 222 185 hsl 128 15 0 8 0 0 empty empty empty -2 -6 0 8 -262144 +-1 -1 2500 1; +#X floatatom 238 278 5 0 0; +#X obj 140 243 pdp_bitdepth; +#X text 292 247 set bit depth (0->16); +#X obj 140 158 pdp_gain; +#X msg 191 130 1; +#X floatatom 227 130 5 0 0; +#X msg 32 192 chanmask \$1; +#X floatatom 32 164 5 0 0; +#X connect 0 0 2 0; +#X connect 1 0 2 0; +#X connect 2 0 11 0; +#X connect 4 0 3 0; +#X connect 5 0 4 1; +#X connect 6 0 9 1; +#X connect 7 0 6 0; +#X connect 8 0 4 1; +#X connect 9 0 4 0; +#X connect 11 0 9 0; +#X connect 12 0 11 1; +#X connect 13 0 11 1; +#X connect 14 0 9 0; +#X connect 15 0 14 0; diff --git a/doc/objects/pdp_bitmask.pd b/doc/objects/pdp_bitmask.pd new file mode 100644 index 0000000..c92ab9e --- /dev/null +++ b/doc/objects/pdp_bitmask.pd @@ -0,0 +1,22 @@ +#N canvas 504 211 500 438 10; +#X msg 77 38 start; +#X msg 124 38 stop; +#X obj 77 70 pdp_help_input; +#X obj 77 287 pdp_help_output; +#X obj 77 243 pdp_gain; +#X msg 128 215 1; +#X text 229 182 apply a bitwise mask (16 bit); +#X floatatom 149 144 8 0 0; +#X obj 152 120 hsl 128 15 0 65535 0 0 empty empty empty -2 -6 0 8 -262144 +-1 -1 0 1; +#X floatatom 175 213 5 0 0; +#X obj 77 178 pdp_bitmask; +#X connect 0 0 2 0; +#X connect 1 0 2 0; +#X connect 2 0 10 0; +#X connect 4 0 3 0; +#X connect 5 0 4 1; +#X connect 7 0 10 1; +#X connect 8 0 7 0; +#X connect 9 0 4 1; +#X connect 10 0 4 0; diff --git a/doc/objects/pdp_bq.pd b/doc/objects/pdp_bq.pd new file mode 100644 index 0000000..3078c45 --- /dev/null +++ b/doc/objects/pdp_bq.pd @@ -0,0 +1,154 @@ +#N canvas 364 134 765 779 10; +#X floatatom 100 598 5 0 0; +#X msg 28 361 ver \$1; +#X msg 28 393 hor \$1; +#X obj 96 362 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X obj 95 389 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X obj 28 629 pdp_bq; +#X floatatom 89 495 5 0 0; +#X msg 28 495 onep \$1; +#X floatatom 89 526 5 0 0; +#X msg 28 530 twop \$1; +#X obj 85 272 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X obj 87 304 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X obj 79 209 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 82 244 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X msg 28 209 lr \$1; +#X msg 28 244 rl \$1; +#X msg 28 277 tb \$1; +#X msg 28 305 bt \$1; +#X obj 454 406 t b f; +#X floatatom 489 369 5 0 0; +#X floatatom 488 317 5 0 0; +#X obj 454 436 pack s 0 0; +#X msg 454 469 \$1 \$2 \$3; +#X obj 489 405 t b f; +#X msg 410 370 lpf; +#X msg 409 344 hpf; +#X msg 409 398 apf; +#X msg 409 425 bsf; +#X obj 461 38 pdp_help_input; +#X msg 461 13 start; +#X msg 507 13 stop; +#X obj 28 746 pdp_help_output; +#X text 159 598 right inlet sets number of passes; +#X text 37 16 pdp_bq: a spatial biquad filter; +#X obj 495 196 pdp_blur; +#X obj 598 194 pdp_phase; +#X obj 461 93 pdp_route 3; +#X obj 533 65 hdl 15 1 0 3 empty empty empty 0 -6 0 8 -262144 -1 -1 +0; +#X obj 41 670 r \$0-out; +#X obj 495 246 s \$0-out; +#X floatatom 544 119 5 0 0; +#X floatatom 617 117 5 0 0; +#X text 312 358 high pass; +#X text 313 382 low pass; +#X text 314 410 all pass; +#X text 313 439 band stop; +#X text 541 367 pole Q; +#X text 94 31 it is a bit awkward to use directly; +#X text 94 45 try one of the abstractions (pdp_blur and; +#X text 95 61 pdp_phase); +#X text 122 208 left->right; +#X text 124 242 right->left; +#X text 126 272 top->bottom; +#X text 126 300 bottom->top; +#X text 133 359 bt and tb; +#X text 132 383 lr and rl; +#X text 147 494 one pole filter; +#X text 146 524 double one pole filter; +#X msg 89 464 0.1; +#X msg 556 95 0.5; +#X msg 616 94 0.5; +#X text 588 62 choose example here; +#X msg 672 118 1; +#X msg 673 140 0; +#X msg 673 163 -1; +#X msg 712 116 1; +#X msg 713 138 0; +#X msg 713 161 -1; +#X text 93 91 "unstable" behaviour is possible; +#X msg 490 347 0.1; +#X msg 488 293 0.3; +#X obj 28 720 pdp_gain; +#X floatatom 112 693 5 0 0; +#X msg 112 671 1; +#X text 95 107 when frequency and Q are outside their; +#X text 96 122 sensible ranges; +#X text 122 180 set filter direction:; +#X text 264 342 set the filter type:; +#X text 137 476 set the filter type:; +#X text 538 319 (between 0 and 1 \, 0.5 = nyquist); +#X text 540 333 comment; +#X text 540 305 pole frequency; +#X msg 100 572 1; +#X msg 457 611 chanmask \$1; +#X floatatom 457 585 5 0 0; +#X text 456 633 binary channel mask; +#X connect 0 0 5 1; +#X connect 1 0 5 0; +#X connect 2 0 5 0; +#X connect 3 0 1 0; +#X connect 4 0 2 0; +#X connect 5 0 71 0; +#X connect 6 0 7 0; +#X connect 7 0 5 0; +#X connect 8 0 9 0; +#X connect 8 0 9 0; +#X connect 9 0 5 0; +#X connect 10 0 16 0; +#X connect 11 0 17 0; +#X connect 12 0 14 0; +#X connect 13 0 15 0; +#X connect 14 0 5 0; +#X connect 15 0 5 0; +#X connect 16 0 5 0; +#X connect 17 0 5 0; +#X connect 18 0 21 0; +#X connect 18 1 21 1; +#X connect 19 0 23 0; +#X connect 20 0 18 0; +#X connect 21 0 22 0; +#X connect 22 0 5 0; +#X connect 23 0 21 0; +#X connect 23 1 21 2; +#X connect 24 0 21 0; +#X connect 25 0 21 0; +#X connect 26 0 21 0; +#X connect 27 0 21 0; +#X connect 28 0 36 0; +#X connect 29 0 28 0; +#X connect 30 0 28 0; +#X connect 34 0 39 0; +#X connect 35 0 39 0; +#X connect 36 0 5 0; +#X connect 36 1 34 0; +#X connect 36 2 35 0; +#X connect 37 0 36 1; +#X connect 38 0 71 0; +#X connect 40 0 34 1; +#X connect 41 0 35 1; +#X connect 58 0 6 0; +#X connect 59 0 40 0; +#X connect 60 0 41 0; +#X connect 62 0 35 2; +#X connect 63 0 35 2; +#X connect 64 0 35 2; +#X connect 65 0 35 3; +#X connect 66 0 35 3; +#X connect 67 0 35 3; +#X connect 69 0 19 0; +#X connect 70 0 20 0; +#X connect 71 0 31 0; +#X connect 72 0 71 1; +#X connect 73 0 72 0; +#X connect 82 0 0 0; +#X connect 83 0 5 0; +#X connect 84 0 83 0; diff --git a/doc/objects/pdp_bqt.pd b/doc/objects/pdp_bqt.pd new file mode 100644 index 0000000..5076168 --- /dev/null +++ b/doc/objects/pdp_bqt.pd @@ -0,0 +1,98 @@ +#N canvas 384 88 785 659 10; +#X floatatom 88 211 5 0 0; +#X msg 27 211 onep \$1; +#X floatatom 88 242 5 0 0; +#X msg 27 246 twop \$1; +#X obj 454 406 t b f; +#X floatatom 489 369 5 0 0; +#X floatatom 488 317 5 0 0; +#X obj 454 436 pack s 0 0; +#X msg 454 469 \$1 \$2 \$3; +#X obj 489 405 t b f; +#X msg 410 370 lpf; +#X msg 409 344 hpf; +#X msg 409 398 apf; +#X msg 409 425 bsf; +#X obj 461 38 pdp_help_input; +#X msg 461 13 start; +#X msg 507 13 stop; +#X obj 27 616 pdp_help_output; +#X obj 461 93 pdp_route 3; +#X obj 533 65 hdl 15 1 0 3 empty empty empty 0 -6 0 8 -262144 -1 -1 +0; +#X obj 40 540 r \$0-out; +#X obj 558 231 s \$0-out; +#X floatatom 490 157 5 0 0; +#X floatatom 601 156 5 0 0; +#X text 312 358 high pass; +#X text 313 382 low pass; +#X text 314 410 all pass; +#X text 313 439 band stop; +#X text 541 367 pole Q; +#X text 99 31 it is a bit awkward to use directly; +#X text 146 210 one pole filter; +#X text 145 240 double one pole filter; +#X msg 88 180 0.1; +#X msg 502 133 0.5; +#X msg 600 133 0.5; +#X text 588 62 choose example here; +#X text 93 91 "unstable" behaviour is possible; +#X msg 490 347 0.1; +#X msg 488 293 0.3; +#X obj 27 590 pdp_gain; +#X floatatom 118 564 5 0 0; +#X msg 118 542 1; +#X text 95 107 when frequency and Q are outside their; +#X text 96 122 sensible ranges; +#X text 264 342 set the filter type:; +#X text 136 192 set the filter type:; +#X text 538 319 (between 0 and 1 \, 0.5 = nyquist); +#X text 540 333 comment; +#X text 540 305 pole frequency; +#X text 37 16 pdp_bqt: a temporal biquad filter; +#X text 99 45 try one of the abstractions (pdp_motion_blur and; +#X text 100 61 pdp_motion_phase); +#X obj 434 190 pdp_motion_blur; +#X obj 558 190 pdp_motion_phase; +#X obj 27 499 pdp_bqt; +#X msg 48 312 reset; +#X text 95 313 reset state; +#X connect 0 0 1 0; +#X connect 1 0 54 0; +#X connect 2 0 3 0; +#X connect 2 0 3 0; +#X connect 3 0 54 0; +#X connect 4 0 7 0; +#X connect 4 1 7 1; +#X connect 5 0 9 0; +#X connect 6 0 4 0; +#X connect 7 0 8 0; +#X connect 8 0 54 0; +#X connect 9 0 7 0; +#X connect 9 1 7 2; +#X connect 10 0 7 0; +#X connect 11 0 7 0; +#X connect 12 0 7 0; +#X connect 13 0 7 0; +#X connect 14 0 18 0; +#X connect 15 0 14 0; +#X connect 16 0 14 0; +#X connect 18 0 54 0; +#X connect 18 1 52 0; +#X connect 18 2 53 0; +#X connect 19 0 18 1; +#X connect 20 0 39 0; +#X connect 22 0 52 1; +#X connect 23 0 53 1; +#X connect 32 0 0 0; +#X connect 33 0 22 0; +#X connect 34 0 23 0; +#X connect 37 0 5 0; +#X connect 38 0 6 0; +#X connect 39 0 17 0; +#X connect 40 0 39 1; +#X connect 41 0 40 0; +#X connect 52 0 21 0; +#X connect 53 0 21 0; +#X connect 54 0 39 0; +#X connect 55 0 54 0; diff --git a/doc/objects/pdp_cheby.pd b/doc/objects/pdp_cheby.pd new file mode 100644 index 0000000..68e24a4 --- /dev/null +++ b/doc/objects/pdp_cheby.pd @@ -0,0 +1,66 @@ +#N canvas 117 219 672 516 10; +#X msg 67 108 coef 0 \$1; +#X floatatom 67 84 5 0 0; +#X floatatom 137 84 5 0 0; +#X msg 137 108 coef 1 \$1; +#X floatatom 206 83 5 0 0; +#X msg 206 108 coef 2 \$1; +#X floatatom 275 84 5 0 0; +#X msg 275 108 coef 3 \$1; +#X floatatom 243 359 5 0 0; +#X text 122 394 creation arg: order (nb coefs = order + 1); +#X text 123 410 (default = minimal order = 2); +#X msg 243 309 reset; +#X obj 21 46 pdp_help_input; +#X msg 21 16 start; +#X msg 70 16 stop; +#X obj 21 445 pdp_help_output; +#X text 296 359 right inlet: number of iterations; +#X text 295 308 set all coefs to 0; +#X msg 243 338 1; +#X msg 243 267 chanmask \$1; +#X floatatom 243 244 5 0 0; +#X text 157 63 set individual coefficients; +#N canvas 0 0 450 300 graph1 0; +#X array mapping 64 float 1; +#A 0 -0.908307 -0.86545 -0.794021 -0.76545 -0.694021 -0.622593 -0.451164 +-0.0511646 0.234549 0.377406 0.427406 0.477406 0.520263 0.534549 0.548835 +0.534549 0.505978 0.477406 0.448835 0.420264 0.348835 0.298835 0.148835 +0.0845496 -0.0511645 -0.151164 -0.236879 -0.322593 -0.436878 -0.436878 +-0.436878 -0.436878 -0.422593 -0.394021 -0.36545 -0.308307 -0.26545 +-0.136879 0.120264 0.291692 0.434549 0.534549 0.591692 0.648835 0.677406 +0.677406 0.663121 0.648835 0.648835 0.634549 0.605978 0.605978 0.605978 +0.605978 0.605978 0.605978 0.634549 0.648835 0.677406 0.705978 0.76312 +0.848835 0.934549 0.977406; +#X coords 0 1 63 -1 200 140 1; +#X restore 427 20 graph; +#X msg 242 217 approx mapping; +#X obj 21 158 pdp_t; +#X text 418 165 -1 ----------- 0 ----------- 1; +#X obj 242 190 spigot; +#X obj 279 167 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X text 361 216 approximate a mapping function; +#X obj 21 403 pdp_cheby 10; +#X connect 0 0 29 0; +#X connect 1 0 0 0; +#X connect 2 0 3 0; +#X connect 3 0 29 0; +#X connect 4 0 5 0; +#X connect 5 0 29 0; +#X connect 6 0 7 0; +#X connect 7 0 29 0; +#X connect 8 0 29 1; +#X connect 11 0 29 0; +#X connect 12 0 24 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 18 0 8 0; +#X connect 19 0 29 0; +#X connect 20 0 19 0; +#X connect 23 0 29 0; +#X connect 24 0 29 0; +#X connect 24 1 26 0; +#X connect 26 0 23 0; +#X connect 27 0 26 1; +#X connect 29 0 15 0; diff --git a/doc/objects/pdp_chrot.pd b/doc/objects/pdp_chrot.pd new file mode 100644 index 0000000..fb59ed5 --- /dev/null +++ b/doc/objects/pdp_chrot.pd @@ -0,0 +1,13 @@ +#N canvas 355 66 554 208 10; +#X obj 74 64 pdp_help_input; +#X msg 74 31 start; +#X msg 124 31 stop; +#X obj 74 121 pdp_chrot; +#X obj 74 157 pdp_help_output; +#X floatatom 151 99 5 0 0; +#X text 204 100 rotate the chroma components by this angle; +#X connect 0 0 3 0; +#X connect 1 0 0 0; +#X connect 2 0 0 0; +#X connect 3 0 4 0; +#X connect 5 0 3 1; diff --git a/doc/objects/pdp_cog.pd b/doc/objects/pdp_cog.pd new file mode 100644 index 0000000..70d8ef7 --- /dev/null +++ b/doc/objects/pdp_cog.pd @@ -0,0 +1,32 @@ +#N canvas 683 169 505 377 10; +#X floatatom 146 142 5 0 0; +#X floatatom 146 166 5 0 0; +#X floatatom 146 190 5 0 0; +#X floatatom 146 214 5 0 0; +#X floatatom 146 239 5 0 0; +#X text 32 12 pdp_cog: compute intensity \, center of gravity and standard +deviation. (interpret an image as a gaussian blob).; +#X text 201 215 standard deviation x; +#X text 200 239 standard deviation y; +#X obj 78 50 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X obj 21 236 pdp_help_output; +#X obj 78 73 pdp_help_input; +#X text 200 141 average intensity; +#X text 200 168 center of gravity x; +#X text 200 190 center of gravity y; +#X text 203 47 creation argument is threshold; +#X obj 78 124 pdp_cog; +#X floatatom 375 291 5 0 0; +#X obj 226 317 pdp_cog_abs_thresh 0.1; +#X text 87 342 the same \, but takes the absolute value and performs +a thresholding operation; +#X connect 8 0 10 0; +#X connect 10 0 9 0; +#X connect 10 0 15 0; +#X connect 15 0 0 0; +#X connect 15 1 1 0; +#X connect 15 2 2 0; +#X connect 15 3 3 0; +#X connect 15 4 4 0; +#X connect 16 0 17 1; diff --git a/doc/objects/pdp_constant.pd b/doc/objects/pdp_constant.pd new file mode 100644 index 0000000..b17c488 --- /dev/null +++ b/doc/objects/pdp_constant.pd @@ -0,0 +1,21 @@ +#N canvas 306 280 575 277 10; +#X obj 46 231 pdp_help_output; +#X obj 46 149 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 125 76 dim 320 240; +#X text 221 76 set packet dimensions; +#X msg 125 103 type grey; +#X msg 125 126 type yv12; +#X obj 46 198 pdp_constant; +#X floatatom 125 172 5 0 0; +#X text 221 105 generate greyscale image; +#X text 221 124 generate colour image (default); +#X text 221 174 set constant; +#X text 118 26 pdp_constant creates an image filled with a constant +when a bang is received; +#X connect 1 0 6 0; +#X connect 2 0 6 0; +#X connect 4 0 6 0; +#X connect 5 0 6 0; +#X connect 6 0 0 0; +#X connect 7 0 6 1; diff --git a/doc/objects/pdp_control.pd b/doc/objects/pdp_control.pd new file mode 100644 index 0000000..cfe7704 --- /dev/null +++ b/doc/objects/pdp_control.pd @@ -0,0 +1,59 @@ +#N canvas 259 276 910 567 10; +#X obj 143 325 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 143 415 pdp_control; +#X msg 143 366 thread \$1; +#X obj 48 54 pdp_help_input; +#X msg 48 24 start; +#X msg 105 24 stop; +#X obj 48 205 pdp_help_output; +#X obj 48 154 pdp_conv; +#X floatatom 117 86 5 0 0; +#X obj 46 361 osc~; +#X floatatom 46 326 5 0 0; +#X obj 46 430 osc~; +#X floatatom 79 402 5 0 0; +#X obj 46 460 dac~; +#X obj 143 454 print; +#X text 182 323 switch thread processing on or of; +#X text 197 455 a pdp_drop message will be sent out; +#X text 197 471 when a package is dropped; +#X text 119 155 a convolution object to burn cycles; +#X obj 666 254 pdp_control; +#X msg 666 226 collectgarbage; +#X obj 646 478 pdp_control; +#X text 175 82 increase this with thread processing enabled \, no audio +should be dropped. if you do it with thread processing disabled \, +increasing it too much can lock up the machine when real time scheduling +is enabled.; +#X msg 646 452 memlimit \$1; +#X msg 688 422 5e+07; +#X msg 615 421 0; +#X text 687 402 50M; +#X text 613 401 off; +#X text 472 178 free all unused packets. pdp's garbage collection is +"lazy" meaning packets will only be freed when the maximum usage limit +is reached.; +#X text 179 25 pdp_control: fine tune the pdp system. (threads & memory). +; +#X text 470 357 set the max memory usage limit for the packet pool. +the default is off (value <= 0).; +#X text 475 511 (this is a safety measure: in pdp it is easy to use +too much memory \, i.e. with delay lines \, which will likely crash +pd); +#X connect 0 0 2 0; +#X connect 1 0 14 0; +#X connect 2 0 1 0; +#X connect 3 0 7 0; +#X connect 4 0 3 0; +#X connect 5 0 3 0; +#X connect 7 0 6 0; +#X connect 8 0 7 1; +#X connect 9 0 11 0; +#X connect 10 0 9 0; +#X connect 11 0 13 0; +#X connect 12 0 11 1; +#X connect 20 0 19 0; +#X connect 23 0 21 0; +#X connect 24 0 23 0; +#X connect 25 0 23 0; diff --git a/doc/objects/pdp_conv.pd b/doc/objects/pdp_conv.pd new file mode 100644 index 0000000..aed62e2 --- /dev/null +++ b/doc/objects/pdp_conv.pd @@ -0,0 +1,44 @@ +#N canvas 450 114 702 535 10; +#X obj 39 353 pdp_conv; +#X floatatom 90 326 5 0 0; +#X msg 87 195 hor \$1; +#X msg 86 137 ver \$1; +#X obj 87 170 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1 1 +; +#X obj 86 112 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1 1 +; +#X msg 89 264 vmask 0.25 0.5 0.25; +#X msg 89 291 hmask 0.25 0.5 0.25; +#X msg 88 239 vmask 0.25 -0.5 0.25; +#X obj 39 63 pdp_help_input; +#X msg 39 24 start; +#X msg 86 24 stop; +#X obj 39 480 pdp_help_output; +#X obj 39 436 pdp_gain; +#X floatatom 90 409 5 0 0; +#X msg 90 386 1; +#X text 162 327 right inlet sets number of iterations; +#X text 263 239 these messages set the horizontal and vertical convolution +masks. note that there is no support for 2 dimensional masks. if you +want that you'll need to factor things out. (see the pdp_conv_* abstractions +for examples); +#X text 264 157 enable/disable horizontal and vertical masks; +#X text 162 428 note: mask coefficents are between -1 and 1; +#X text 162 441 use a gain object to compensate for this; +#X msg 128 385 9; +#X connect 0 0 13 0; +#X connect 1 0 0 1; +#X connect 2 0 0 0; +#X connect 3 0 0 0; +#X connect 4 0 2 0; +#X connect 5 0 3 0; +#X connect 6 0 0 0; +#X connect 7 0 0 0; +#X connect 8 0 0 0; +#X connect 9 0 0 0; +#X connect 10 0 9 0; +#X connect 11 0 9 0; +#X connect 13 0 12 0; +#X connect 14 0 13 1; +#X connect 15 0 14 0; +#X connect 21 0 14 0; diff --git a/doc/objects/pdp_convert.pd b/doc/objects/pdp_convert.pd new file mode 100644 index 0000000..498aaa3 --- /dev/null +++ b/doc/objects/pdp_convert.pd @@ -0,0 +1,17 @@ +#N canvas 556 468 575 277 10; +#X obj 46 40 pdp_help_input; +#X msg 46 10 start; +#X msg 95 10 stop; +#X obj 46 225 pdp_help_output; +#X obj 118 69 hdl 15 1 0 2 empty empty empty 0 -6 0 8 -262144 -1 -1 +0; +#X obj 46 90 pdp_route 2; +#X obj 118 154 pdp_convert image/grey/*; +#X text 307 153 convert a packet; +#X connect 0 0 5 0; +#X connect 1 0 0 0; +#X connect 2 0 0 0; +#X connect 4 0 5 1; +#X connect 5 0 3 0; +#X connect 5 1 6 0; +#X connect 6 0 3 0; diff --git a/doc/objects/pdp_del.pd b/doc/objects/pdp_del.pd new file mode 100644 index 0000000..607a632 --- /dev/null +++ b/doc/objects/pdp_del.pd @@ -0,0 +1,31 @@ +#N canvas 414 20 609 368 10; +#X floatatom 107 116 5 0 0 0 - - -; +#X floatatom 64 207 5 0 0 0 - - -; +#X obj 20 60 pdp_help_input; +#X msg 20 31 start; +#X msg 72 30 stop; +#X obj 20 236 pdp_mix; +#X obj 20 268 pdp_help_output; +#X msg 64 183 0.5; +#X text 164 116 right inlet sets current delay length; +#X text 164 149 a packet delay line.; +#X text 164 180 (dont make this too large \, packets are not compressed!) +; +#X obj 42 147 pdp_del 50; +#X text 164 165 first creation arg = max delay length; +#X text 165 213 second creation arg: initial delay (default = max) +; +#X obj 176 259 pdp_description; +#X obj 176 285 print; +#X msg 339 259 _debug; +#X connect 0 0 11 1; +#X connect 1 0 5 2; +#X connect 2 0 5 0; +#X connect 2 0 11 0; +#X connect 3 0 2 0; +#X connect 4 0 2 0; +#X connect 5 0 6 0; +#X connect 7 0 1 0; +#X connect 11 0 5 1; +#X connect 11 0 14 0; +#X connect 16 0 11 0; diff --git a/doc/objects/pdp_description.pd b/doc/objects/pdp_description.pd new file mode 100644 index 0000000..f065d83 --- /dev/null +++ b/doc/objects/pdp_description.pd @@ -0,0 +1,28 @@ +#N canvas 338 375 593 300 10; +#X symbolatom 78 197 40 0 0; +#X obj 78 46 pdp_noise; +#X obj 78 23 bng 15 250 50 0 empty empty empty 0 -6 32 8 -262144 -1 +-1; +#X obj 183 44 pdp_noise; +#X obj 183 21 bng 15 250 50 0 empty empty empty 0 -6 32 8 -262144 -1 +-1; +#X obj 183 71 pdp_grey; +#X text 263 139 output packet description as a symbol; +#X obj 288 44 pdp_noise; +#X obj 288 21 bng 15 250 50 0 empty empty empty 0 -6 32 8 -262144 -1 +-1; +#X obj 288 71 pdp_mchp; +#X floatatom 178 171 5 0 0; +#X obj 78 118 pdp_reg; +#X obj 78 142 pdp_description; +#X connect 1 0 11 0; +#X connect 2 0 1 0; +#X connect 3 0 5 0; +#X connect 4 0 3 0; +#X connect 5 0 11 0; +#X connect 7 0 9 0; +#X connect 8 0 7 0; +#X connect 9 0 11 0; +#X connect 11 0 12 0; +#X connect 12 0 0 0; +#X connect 12 1 10 0; diff --git a/doc/objects/pdp_flip_lr.pd b/doc/objects/pdp_flip_lr.pd new file mode 100644 index 0000000..b28c3bd --- /dev/null +++ b/doc/objects/pdp_flip_lr.pd @@ -0,0 +1,11 @@ +#N canvas 504 211 449 178 10; +#X msg 77 38 start; +#X msg 124 38 stop; +#X obj 77 70 pdp_help_input; +#X obj 77 136 pdp_help_output; +#X obj 77 101 pdp_flip_lr; +#X text 222 101 flip left <-> right; +#X connect 0 0 2 0; +#X connect 1 0 2 0; +#X connect 2 0 4 0; +#X connect 4 0 3 0; diff --git a/doc/objects/pdp_flip_tb.pd b/doc/objects/pdp_flip_tb.pd new file mode 100644 index 0000000..7048a75 --- /dev/null +++ b/doc/objects/pdp_flip_tb.pd @@ -0,0 +1,11 @@ +#N canvas 504 211 449 178 10; +#X msg 77 38 start; +#X msg 124 38 stop; +#X obj 77 70 pdp_help_input; +#X obj 77 136 pdp_help_output; +#X obj 77 101 pdp_flip_tb; +#X text 222 101 flip top <-> bottom; +#X connect 0 0 2 0; +#X connect 1 0 2 0; +#X connect 2 0 4 0; +#X connect 4 0 3 0; diff --git a/doc/objects/pdp_gain.pd b/doc/objects/pdp_gain.pd new file mode 100644 index 0000000..7e3f50b --- /dev/null +++ b/doc/objects/pdp_gain.pd @@ -0,0 +1,23 @@ +#N canvas 444 413 538 379 10; +#X msg 91 25 start; +#X msg 139 25 stop; +#X obj 91 56 pdp_help_input; +#X obj 91 312 pdp_help_output; +#X obj 91 236 pdp_gain; +#X floatatom 142 207 5 0 0; +#X text 201 205 right inlet sets overal gain; +#X text 201 252 creation argument sets initial gain; +#X text 200 270 (default = 1); +#X text 202 236 pdp_gain clips when overdriven; +#X msg 109 124 chanmask \$1; +#X floatatom 109 100 5 0 0; +#X text 203 124 set which channels are processed; +#X text 203 140 using a binary mask. LSB = chan 0; +#X text 203 157 default (any negative number) = all; +#X connect 0 0 2 0; +#X connect 1 0 2 0; +#X connect 2 0 4 0; +#X connect 4 0 3 0; +#X connect 5 0 4 1; +#X connect 10 0 4 0; +#X connect 11 0 10 0; diff --git a/doc/objects/pdp_grey2mask.pd b/doc/objects/pdp_grey2mask.pd new file mode 100644 index 0000000..9a561ff --- /dev/null +++ b/doc/objects/pdp_grey2mask.pd @@ -0,0 +1,25 @@ +#N canvas 369 257 656 300 10; +#X obj 46 40 pdp_help_input; +#X msg 46 10 start; +#X msg 95 10 stop; +#X obj 46 275 pdp_help_output; +#X obj 90 146 pdp_grey2mask; +#X obj 46 183 pdp_mul; +#X obj 46 247 pdp_gain; +#X floatatom 97 220 5 0 0; +#X text 194 136 convert a grey scale image or the luma channel of a +colour image to an image mask. (to be used for multiplication); +#X obj 90 119 pdp_reg; +#X obj 172 73 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X text 197 70 click here to propagate a new mask; +#X connect 0 0 5 0; +#X connect 0 0 9 1; +#X connect 1 0 0 0; +#X connect 2 0 0 0; +#X connect 4 0 5 1; +#X connect 5 0 6 0; +#X connect 6 0 3 0; +#X connect 7 0 6 1; +#X connect 9 0 4 0; +#X connect 10 0 9 0; diff --git a/doc/objects/pdp_help_input.pd b/doc/objects/pdp_help_input.pd new file mode 100644 index 0000000..3a9edf7 --- /dev/null +++ b/doc/objects/pdp_help_input.pd @@ -0,0 +1,79 @@ +#N canvas 394 33 741 682 10; +#X obj 23 524 pdp_v4l; +#X text 17 11 this abstraction is used as an input module in most of +the documentation patches. change it to reflect your preferred input +object.; +#X obj 262 234 inlet; +#X msg 315 324 stop; +#X obj 258 672 outlet; +#X obj 262 385 metro; +#X obj 292 360 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -6 0 10 +-262144 -1 -1 40 256; +#X msg 23 287 open /dev/video0; +#X obj 260 88 loadbang; +#X obj 199 169 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 315 167 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X text 171 189 connect here; +#X text 291 187 connect here; +#X obj 187 470 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 334 468 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X text 45 329 v4l device; +#X text 18 312 change this to your; +#X obj 492 515 pdp_qt; +#X obj 260 137 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 262 426 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X text 520 308 change this to the movie; +#X text 519 323 you want to use; +#X msg 520 379 loop 1; +#X msg 262 325 bang; +#X text 163 203 for video4linux; +#X text 294 201 for quicktime; +#X text 156 497 connect here; +#X text 148 511 for video4linux; +#X text 302 497 connect here; +#X text 305 511 for quicktime; +#X text 308 377 set framerate here; +#X msg 492 288 open /tmp/test.mov; +#X obj 262 258 route start stop; +#X obj 329 292 select 0; +#X obj 262 292 select 1; +#X msg 40 357 open /dev/video1; +#X obj 247 601 pdp_noise; +#X obj 268 523 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X text 236 552 connect here; +#X text 239 566 for noise input; +#X text 293 137 disconnect for noise input; +#X connect 0 0 4 0; +#X connect 2 0 32 0; +#X connect 3 0 5 0; +#X connect 5 0 19 0; +#X connect 6 0 5 1; +#X connect 7 0 0 0; +#X connect 8 0 18 0; +#X connect 9 0 7 0; +#X connect 10 0 31 0; +#X connect 13 0 0 0; +#X connect 14 0 17 0; +#X connect 17 0 4 0; +#X connect 18 0 9 0; +#X connect 19 0 13 0; +#X connect 22 0 17 0; +#X connect 23 0 5 0; +#X connect 31 0 17 0; +#X connect 31 0 22 0; +#X connect 32 0 23 0; +#X connect 32 1 3 0; +#X connect 32 2 34 0; +#X connect 33 0 3 0; +#X connect 34 0 23 0; +#X connect 34 1 33 0; +#X connect 35 0 0 0; +#X connect 36 0 4 0; +#X connect 37 0 36 0; diff --git a/doc/objects/pdp_help_output.pd b/doc/objects/pdp_help_output.pd new file mode 100644 index 0000000..0ed52d5 --- /dev/null +++ b/doc/objects/pdp_help_output.pd @@ -0,0 +1,14 @@ +#N canvas 482 342 510 304 10; +#X obj 59 95 inlet; +#X obj 59 178 pdp_xv; +#X text 17 11 this abstraction is used as an output module in most +of the documentation patches. change it to reflect your preferred output +object.; +#X obj 232 179 pdp_glx; +#X text 31 201 X11 XVideo output; +#X text 198 199 X11 openGL output; +#X text 60 217 (linux); +#X text 199 214 (linux \, mesa \, osx); +#X msg 106 141 display acer:0; +#X connect 0 0 1 0; +#X connect 8 0 1 0; diff --git a/doc/objects/pdp_histo.pd b/doc/objects/pdp_histo.pd new file mode 100644 index 0000000..f99a27e --- /dev/null +++ b/doc/objects/pdp_histo.pd @@ -0,0 +1,36 @@ +#N canvas 594 324 616 432 10; +#X msg 87 208 size \$1; +#X floatatom 87 184 5 0 0; +#N canvas 0 0 450 300 graph2 0; +#X array array1 64 float 0; +#X coords 0 1 63 -1 200 140 1; +#X restore 390 32 graph; +#X obj 127 47 pdp_help_input; +#X obj 127 113 pdp_help_output; +#X obj 127 77 pdp_gain; +#X floatatom 251 50 5 0 0; +#X obj 127 23 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X msg 86 271 array array1; +#X floatatom 155 183 5 0 0; +#X msg 155 207 scale \$1; +#X text 37 355 the size is rounded to the next power of 2; +#X text 36 373 first argument is size \, second is optional scaling +factor.; +#X text 37 338 create a histogram from an image and send to a table +; +#X floatatom 229 183 5 0 0; +#X msg 229 207 samplesize \$1; +#X obj 19 299 pdp_histo array1 64 10; +#X connect 0 0 16 0; +#X connect 1 0 0 0; +#X connect 3 0 5 0; +#X connect 5 0 4 0; +#X connect 5 0 16 0; +#X connect 6 0 5 1; +#X connect 7 0 3 0; +#X connect 8 0 16 0; +#X connect 9 0 10 0; +#X connect 10 0 16 0; +#X connect 14 0 15 0; +#X connect 15 0 16 0; diff --git a/doc/objects/pdp_hthresh.pd b/doc/objects/pdp_hthresh.pd new file mode 100644 index 0000000..6d71925 --- /dev/null +++ b/doc/objects/pdp_hthresh.pd @@ -0,0 +1,26 @@ +#N canvas 504 211 500 438 10; +#X msg 77 38 start; +#X msg 124 38 stop; +#X obj 77 70 pdp_help_input; +#X obj 77 340 pdp_help_output; +#X obj 77 163 pdp_gain; +#X floatatom 128 135 5 0 0; +#X msg 128 109 0.5; +#X obj 77 296 pdp_gain; +#X msg 128 268 1; +#X floatatom 160 199 5 0 0; +#X text 234 283 (-t > x > t) -> 0; +#X text 234 248 ( x > t) -> x; +#X text 234 266 (-t > x) -> x; +#X text 233 230 hard threshold; +#X obj 77 231 pdp_hthresh; +#X connect 0 0 2 0; +#X connect 1 0 2 0; +#X connect 2 0 4 0; +#X connect 4 0 14 0; +#X connect 5 0 4 1; +#X connect 6 0 5 0; +#X connect 7 0 3 0; +#X connect 8 0 7 1; +#X connect 9 0 14 1; +#X connect 14 0 7 0; diff --git a/doc/objects/pdp_loop.pd b/doc/objects/pdp_loop.pd new file mode 100644 index 0000000..b097cd8 --- /dev/null +++ b/doc/objects/pdp_loop.pd @@ -0,0 +1,62 @@ +#N canvas 427 312 733 458 10; +#X obj 32 85 metro 40; +#X obj 17 59 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 152 393 pdp_loop 25; +#X msg 275 109 record; +#X floatatom 83 58 5 0 0; +#X msg 39 58 stop; +#X floatatom 274 363 5 0 0; +#X floatatom 274 338 5 0 0; +#X msg 275 82 store \$1; +#X floatatom 275 57 5 0 0; +#X msg 274 158 stop; +#X obj 152 428 pdp_help_output; +#X obj 152 87 pdp_help_input; +#X msg 152 59 start; +#X msg 199 59 stop; +#X text 365 325 set playback position; +#X text 372 345 hot; +#X text 369 362 cold; +#X text 365 159 stop recording; +#X text 366 107 start recording at position 0; +#X text 365 82 store a single packet at an arbitrary position; +#X text 154 33 source playback; +#X text 16 34 loop playback; +#X text 272 393 creation arg: loop size; +#X msg 275 132 record 10 2; +#X text 365 133 start recording at position 10 \, recording 2 packets +; +#X msg 274 209 loop \$1; +#X obj 274 188 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X text 365 210 looping on/off; +#X msg 274 310 0; +#X msg 274 273 size \$1; +#X floatatom 274 249 5 0 0; +#X text 366 270 set a new loop size. (don't make this too large); +#X msg 561 356 collectgarbage; +#X obj 561 387 pdp_control; +#X msg 546 329 thread 1; +#X connect 0 0 2 0; +#X connect 1 0 0 0; +#X connect 2 0 11 0; +#X connect 3 0 2 0; +#X connect 4 0 0 1; +#X connect 5 0 0 0; +#X connect 6 0 2 1; +#X connect 7 0 2 0; +#X connect 8 0 2 0; +#X connect 9 0 8 0; +#X connect 10 0 2 0; +#X connect 12 0 2 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 24 0 2 0; +#X connect 26 0 2 0; +#X connect 27 0 26 0; +#X connect 29 0 7 0; +#X connect 30 0 2 0; +#X connect 31 0 30 0; +#X connect 33 0 34 0; +#X connect 35 0 34 0; diff --git a/doc/objects/pdp_mix.pd b/doc/objects/pdp_mix.pd new file mode 100644 index 0000000..12dc169 --- /dev/null +++ b/doc/objects/pdp_mix.pd @@ -0,0 +1,21 @@ +#N canvas 314 353 576 288 10; +#X obj 103 132 pdp_reg; +#X obj 201 86 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X floatatom 200 155 5 0 0; +#X obj 81 48 pdp_help_input; +#X msg 81 18 start; +#X msg 130 18 stop; +#X obj 81 238 pdp_help_output; +#X text 268 80 click here; +#X obj 81 184 pdp_mix; +#X text 268 159 crossfade between 2 packets; +#X text 268 175 0 = left inlet \, 1 = middle inlet; +#X connect 0 0 8 1; +#X connect 1 0 0 0; +#X connect 2 0 8 2; +#X connect 3 0 0 1; +#X connect 3 0 8 0; +#X connect 4 0 3 0; +#X connect 5 0 3 0; +#X connect 8 0 6 0; diff --git a/doc/objects/pdp_mix2.pd b/doc/objects/pdp_mix2.pd new file mode 100644 index 0000000..aa492b1 --- /dev/null +++ b/doc/objects/pdp_mix2.pd @@ -0,0 +1,25 @@ +#N canvas 314 353 576 288 10; +#X obj 98 132 pdp_reg; +#X obj 201 86 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X floatatom 205 138 5 0 0; +#X obj 81 48 pdp_help_input; +#X msg 81 18 start; +#X msg 130 18 stop; +#X obj 81 238 pdp_help_output; +#X text 268 80 click here; +#X obj 81 201 pdp_mix2; +#X floatatom 205 161 5 0 0; +#X text 158 199 pdp_mix2 adds two packets after applying attenuation +; +#X text 268 136 left packet attenuation; +#X text 268 159 right packet attenuation; +#X connect 0 0 8 1; +#X connect 1 0 0 0; +#X connect 2 0 8 2; +#X connect 3 0 0 1; +#X connect 3 0 8 0; +#X connect 4 0 3 0; +#X connect 5 0 3 0; +#X connect 8 0 6 0; +#X connect 9 0 8 3; diff --git a/doc/objects/pdp_mul.pd b/doc/objects/pdp_mul.pd new file mode 100644 index 0000000..24d6461 --- /dev/null +++ b/doc/objects/pdp_mul.pd @@ -0,0 +1,28 @@ +#N canvas 224 229 462 390 10; +#X msg 130 53 start; +#X msg 177 53 stop; +#X obj 130 85 pdp_help_input; +#X obj 130 345 pdp_help_output; +#X obj 174 179 pdp_reg; +#X obj 248 142 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X text 281 140 click here; +#X obj 130 310 pdp_gain; +#X floatatom 181 282 5 0 0; +#X text 282 216 multiplies 2 packets; +#X obj 130 212 pdp_mul; +#X msg 181 256 2; +#X floatatom 40 150 5 0 0; +#X msg 40 177 chanmask \$1; +#X connect 0 0 2 0; +#X connect 1 0 2 0; +#X connect 2 0 10 0; +#X connect 2 0 4 1; +#X connect 4 0 10 1; +#X connect 5 0 4 0; +#X connect 7 0 3 0; +#X connect 8 0 7 1; +#X connect 10 0 7 0; +#X connect 11 0 8 0; +#X connect 12 0 13 0; +#X connect 13 0 10 0; diff --git a/doc/objects/pdp_netsend.pd b/doc/objects/pdp_netsend.pd new file mode 100644 index 0000000..8828c17 --- /dev/null +++ b/doc/objects/pdp_netsend.pd @@ -0,0 +1,62 @@ +#N canvas 236 47 523 395 10; +#X obj 174 74 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 155 43 metro 40; +#X obj 155 18 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X obj 167 171 pdp_convert bitmap/yv12/*; +#X floatatom 238 20 5 0 0 0 - - -; +#X msg 263 132 sleepgrain \$1; +#X floatatom 263 112 5 0 0 0 - - -; +#X floatatom 308 74 5 0 0 0 - - -; +#X msg 308 94 udpsize \$1; +#X obj 295 44 hsl 128 15 1024 60000 1 0 empty empty empty -2 -6 0 8 +-262144 -1 -1 4000 1; +#X msg 339 161 sleep \$1; +#X obj 379 136 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X floatatom 327 200 5 0 0 0 - - -; +#X msg 327 220 sleepperiod \$1; +#X msg 16 13 connect acer 7777; +#X obj 124 212 pdp_netsend; +#X msg 324 15 1472; +#X msg 211 81 dim 160 120; +#X msg 212 62 dim 320 240; +#X msg 18 44 connect localhost 7777; +#X obj 65 247 pdp_netreceive 7777; +#X obj 78 275 pdp_xv; +#X obj 123 136 pdp_route; +#X obj 203 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X floatatom 281 248 5 0 0 0 - - -; +#X msg 281 268 timeout \$1; +#X obj 154 103 pdp_v4l; +#X obj 132 275 pdp_xv; +#X text 97 334 this is still experimental (SIGSEGVs ahead); +#X connect 0 0 26 0; +#X connect 1 0 26 0; +#X connect 2 0 1 0; +#X connect 3 0 15 0; +#X connect 4 0 1 1; +#X connect 5 0 15 0; +#X connect 6 0 5 0; +#X connect 7 0 8 0; +#X connect 8 0 15 0; +#X connect 9 0 7 0; +#X connect 10 0 15 0; +#X connect 11 0 10 0; +#X connect 12 0 13 0; +#X connect 13 0 15 0; +#X connect 14 0 15 0; +#X connect 16 0 8 0; +#X connect 17 0 26 0; +#X connect 18 0 26 0; +#X connect 19 0 15 0; +#X connect 20 0 21 0; +#X connect 22 0 15 0; +#X connect 22 1 3 0; +#X connect 23 0 22 1; +#X connect 24 0 25 0; +#X connect 25 0 15 0; +#X connect 26 0 22 0; +#X connect 26 0 27 0; diff --git a/doc/objects/pdp_noise.pd b/doc/objects/pdp_noise.pd new file mode 100644 index 0000000..732d4a1 --- /dev/null +++ b/doc/objects/pdp_noise.pd @@ -0,0 +1,21 @@ +#N canvas 614 448 575 277 10; +#X obj 46 231 pdp_help_output; +#X obj 46 198 pdp_noise; +#X obj 46 149 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 174 71 dim 320 240; +#X text 270 71 set packet dimensions; +#X msg 174 98 type grey; +#X msg 174 121 type yv12; +#X text 270 100 generate greyscale; +#X text 270 119 generate colour (default); +#X msg 174 152 seed 123; +#X text 270 152 set seed value; +#X text 167 21 pdp_noise creates a random image (with uniform distribution +between -1 and 1) when a bang is received; +#X connect 1 0 0 0; +#X connect 2 0 1 0; +#X connect 3 0 1 0; +#X connect 5 0 1 0; +#X connect 6 0 1 0; +#X connect 9 0 1 0; diff --git a/doc/objects/pdp_not.pd b/doc/objects/pdp_not.pd new file mode 100644 index 0000000..c213080 --- /dev/null +++ b/doc/objects/pdp_not.pd @@ -0,0 +1,21 @@ +#N canvas 504 211 500 438 10; +#X msg 77 38 start; +#X msg 124 38 stop; +#X obj 77 70 pdp_help_input; +#X obj 77 340 pdp_help_output; +#X obj 77 163 pdp_gain; +#X floatatom 128 135 5 0 0; +#X msg 128 109 0.5; +#X obj 77 231 pdp_not; +#X text 229 235 bitwise not; +#X obj 77 296 pdp_gain; +#X msg 128 268 1; +#X connect 0 0 2 0; +#X connect 1 0 2 0; +#X connect 2 0 4 0; +#X connect 4 0 7 0; +#X connect 5 0 4 1; +#X connect 6 0 5 0; +#X connect 7 0 9 0; +#X connect 9 0 3 0; +#X connect 10 0 9 1; diff --git a/doc/objects/pdp_or.pd b/doc/objects/pdp_or.pd new file mode 100644 index 0000000..22e91e6 --- /dev/null +++ b/doc/objects/pdp_or.pd @@ -0,0 +1,24 @@ +#N canvas 552 356 511 383 10; +#X msg 77 38 start; +#X msg 124 38 stop; +#X obj 77 70 pdp_help_input; +#X obj 77 322 pdp_help_output; +#X obj 114 246 pdp_reg; +#X obj 196 183 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X text 229 181 click here; +#X obj 77 163 pdp_gain; +#X floatatom 128 135 5 0 0; +#X msg 128 109 0.5; +#X obj 77 279 pdp_or; +#X text 229 283 bitwise or; +#X connect 0 0 2 0; +#X connect 1 0 2 0; +#X connect 2 0 7 0; +#X connect 4 0 10 1; +#X connect 5 0 4 0; +#X connect 7 0 4 1; +#X connect 7 0 10 0; +#X connect 8 0 7 1; +#X connect 9 0 8 0; +#X connect 10 0 3 0; diff --git a/doc/objects/pdp_plasma.pd b/doc/objects/pdp_plasma.pd new file mode 100644 index 0000000..3a9a566 --- /dev/null +++ b/doc/objects/pdp_plasma.pd @@ -0,0 +1,29 @@ +#N canvas 655 0 575 333 10; +#X obj 46 262 pdp_help_output; +#X obj 46 149 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 174 71 dim 320 240; +#X text 270 71 set packet dimensions; +#X msg 174 98 type grey; +#X msg 174 121 type yv12; +#X text 270 100 generate greyscale; +#X text 270 119 generate colour (default); +#X msg 174 152 seed 123; +#X text 270 152 set seed value; +#X text 167 21 pdp_noise creates a random image (with uniform distribution +between -1 and 1) when a bang is received; +#X obj 46 198 pdp_plasma; +#X floatatom 174 176 5 0 0 0 - - -; +#X text 270 176 turbulence; +#X obj 46 241 pdp_reg; +#X obj 113 221 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X connect 1 0 11 0; +#X connect 2 0 11 0; +#X connect 4 0 11 0; +#X connect 5 0 11 0; +#X connect 8 0 11 0; +#X connect 11 0 14 0; +#X connect 12 0 11 1; +#X connect 14 0 0 0; +#X connect 15 0 14 0; diff --git a/doc/objects/pdp_pointcloud.pd b/doc/objects/pdp_pointcloud.pd new file mode 100644 index 0000000..c7c7f47 --- /dev/null +++ b/doc/objects/pdp_pointcloud.pd @@ -0,0 +1,32 @@ +#N canvas 462 571 450 371 10; +#X obj 40 94 pdp_help_input; +#X obj 40 36 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X obj 40 174 pdp_help_output; +#X text 111 11 convert an image to a point cloud; +#X text 111 43 creation argument is number of points; +#X text 111 26 (containing the points with highest intesity); +#X floatatom 168 114 5 0 0; +#X text 219 114 <- nb points; +#X obj 40 140 pdp_pointcloud 10; +#X floatatom 265 151 5 0 0; +#X msg 267 174 nbclusters \$1; +#X obj 180 216 pdp_description; +#X obj 180 243 print; +#X obj 35 296 pdp_xv; +#X obj 39 221 pdp_m_mm A A^T; +#X obj 34 273 pdp_scale 64 64; +#X obj 34 252 pdp_convert image/*/*; +#X connect 0 0 8 0; +#X connect 1 0 0 0; +#X connect 6 0 8 1; +#X connect 8 0 2 0; +#X connect 8 1 11 0; +#X connect 8 1 14 1; +#X connect 8 1 14 0; +#X connect 9 0 10 0; +#X connect 10 0 8 0; +#X connect 11 0 12 0; +#X connect 14 0 16 0; +#X connect 15 0 13 0; +#X connect 16 0 15 0; diff --git a/doc/objects/pdp_positive.pd b/doc/objects/pdp_positive.pd new file mode 100644 index 0000000..5452d2d --- /dev/null +++ b/doc/objects/pdp_positive.pd @@ -0,0 +1,27 @@ +#N canvas 479 219 500 438 10; +#X msg 77 38 start; +#X msg 124 38 stop; +#X obj 77 70 pdp_help_input; +#X obj 77 340 pdp_help_output; +#X floatatom 128 135 5 0 0; +#X obj 77 296 pdp_gain; +#X msg 145 271 1; +#X obj 77 231 pdp_positive; +#X text 224 230 test positive and return a bitmask; +#X text 225 245 >= 0 -> all one / < 0 -> all zero; +#X text 223 264 to use in conjunction with logic ops; +#X obj 77 268 pdp_xor; +#X obj 277 146 pdp_cheby; +#X obj 77 163 pdp_offset; +#X msg 128 109 -0.5; +#X connect 0 0 2 0; +#X connect 1 0 2 0; +#X connect 2 0 11 1; +#X connect 2 0 13 0; +#X connect 4 0 13 1; +#X connect 5 0 3 0; +#X connect 6 0 5 1; +#X connect 7 0 11 0; +#X connect 11 0 5 0; +#X connect 13 0 7 0; +#X connect 14 0 4 0; diff --git a/doc/objects/pdp_qt.pd b/doc/objects/pdp_qt.pd new file mode 100644 index 0000000..9ff6154 --- /dev/null +++ b/doc/objects/pdp_qt.pd @@ -0,0 +1,71 @@ +#N canvas 400 126 740 623 10; +#X obj 59 391 pdp_qt; +#X floatatom 77 429 5 0 0; +#X floatatom 127 430 5 0 0; +#X obj 56 41 metro 40; +#X msg 56 13 bang; +#X msg 97 13 stop; +#X msg 15 13 bang; +#X obj 140 41 openpanel; +#X msg 140 66 open \$1; +#X msg 140 13 bang; +#X msg 140 92 close; +#X text 249 66 open/close for file access; +#X floatatom 140 120 5 0 0; +#X floatatom 140 146 5 0 0; +#X text 248 117 float on left inlet selects a frame for output; +#X msg 140 197 loop \$1; +#X obj 203 182 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X text 250 198 automatic looping can be enabled/disabled; +#X text 251 9 pdp_qt plays a quicktime movie.; +#X text 250 221 this enables automatic playback at the frame rate specified +in the movie file. in pdp_qt~ playback is synchronized to the audio +stream.; +#X msg 142 341 dump array 0; +#X text 252 330 if the movie contains audio \, this command dumps the +audio data into an array specified by the first argument. the second +argument is the audio channel (default = 0 = left); +#X msg 142 291 stop; +#X text 251 289 stops automatic playback (same as autoplay 0); +#X msg 141 222 autoplay 1; +#X msg 142 267 play; +#X text 252 432 the second outlet outputs the current frame number. +the third outlet outputs the total number of frames in a movie when +it is opened.; +#X msg 142 315 cont; +#X text 251 269 starts automatic playback (same as 0 \, autplay 1 \, +bang); +#X text 251 310 resumes automatic playback (same as autplay 1 \, bang) +; +#X text 249 137 float on right inlet selects the frame to be read on +the next sync event (bang message / internal sync).; +#X obj 59 462 pdp_help_output; +#X obj 335 535 table array; +#X obj 448 535 tabplay~ array; +#X obj 448 576 dac~; +#X obj 448 506 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X connect 0 0 31 0; +#X connect 0 1 1 0; +#X connect 0 2 2 0; +#X connect 3 0 0 0; +#X connect 4 0 3 0; +#X connect 5 0 3 0; +#X connect 6 0 0 0; +#X connect 7 0 8 0; +#X connect 8 0 0 0; +#X connect 9 0 7 0; +#X connect 10 0 0 0; +#X connect 12 0 0 0; +#X connect 13 0 0 1; +#X connect 15 0 0 0; +#X connect 16 0 15 0; +#X connect 20 0 0 0; +#X connect 22 0 0 0; +#X connect 24 0 0 0; +#X connect 25 0 0 0; +#X connect 27 0 0 0; +#X connect 33 0 34 0; +#X connect 33 0 34 1; +#X connect 35 0 33 0; diff --git a/doc/objects/pdp_qt~.pd b/doc/objects/pdp_qt~.pd new file mode 100644 index 0000000..b03e4e1 --- /dev/null +++ b/doc/objects/pdp_qt~.pd @@ -0,0 +1,25 @@ +#N canvas 400 126 692 254 10; +#X obj 62 122 pdp_qt~; +#X obj 90 164 dac~; +#X msg 39 51 play; +#X obj 133 42 openpanel; +#X msg 133 67 open \$1; +#X msg 133 14 bang; +#X text 257 67 pdp_qt~ is the same as pdp_qt exept that it also outputs +the audio data corresponding to the current frame on its 2 rightmost +outlets. if there is a lag between audio and video a pdp_del object +can be inserted to delay the image. note that in order to get acceptable +audio quality with relatively few dropouts you might need to increase +the pd audio latency.; +#X msg 15 24 loop 1; +#X floatatom 84 52 5 0 0; +#X obj 62 214 pdp_help_output; +#X connect 0 0 9 0; +#X connect 0 3 1 0; +#X connect 0 4 1 1; +#X connect 2 0 0 0; +#X connect 3 0 4 0; +#X connect 4 0 0 0; +#X connect 5 0 3 0; +#X connect 7 0 0 0; +#X connect 8 0 0 1; diff --git a/doc/objects/pdp_randmix.pd b/doc/objects/pdp_randmix.pd new file mode 100644 index 0000000..6614979 --- /dev/null +++ b/doc/objects/pdp_randmix.pd @@ -0,0 +1,24 @@ +#N canvas 314 353 584 288 10; +#X obj 81 184 pdp_randmix; +#X obj 117 132 pdp_reg; +#X obj 200 87 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X floatatom 200 155 5 0 0; +#X obj 81 48 pdp_help_input; +#X msg 81 18 start; +#X msg 130 18 stop; +#X obj 81 238 pdp_help_output; +#X text 268 80 click here; +#X text 268 159 random crossfade between 2 packets; +#X text 268 175 0 = left \, 1 = right; +#X obj 203 125 hsl 128 15 0 1 0 0 empty empty empty -2 -6 0 8 -262144 +-1 -1 6100 1; +#X connect 0 0 7 0; +#X connect 1 0 0 1; +#X connect 2 0 1 0; +#X connect 3 0 0 2; +#X connect 4 0 0 0; +#X connect 4 0 1 1; +#X connect 5 0 4 0; +#X connect 6 0 4 0; +#X connect 11 0 3 0; diff --git a/doc/objects/pdp_rawin.pd b/doc/objects/pdp_rawin.pd new file mode 100644 index 0000000..6dcc342 --- /dev/null +++ b/doc/objects/pdp_rawin.pd @@ -0,0 +1,28 @@ +#N canvas 504 520 687 380 10; +#X msg 137 68 open /tmp/otherpipe; +#X msg 437 157 open; +#X text 169 111 set type (how to interpret raw data); +#X obj 75 307 pdp_help_output; +#X text 476 157 open default pipe; +#X text 177 196 creation args: <pipe> <type>; +#X obj 405 218 print done; +#X text 270 244 2nd outlet: bang if pipe is closed; +#X text 271 260 connect to [open< to ensure pipe stays open; +#X text 283 69 open any pipe for reading; +#X msg 152 90 close; +#X text 198 90 close pipe; +#X obj 437 137 spigot; +#X obj 473 116 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 171 129 type bitmap/rgb/320x240; +#X obj 137 174 pdp_rawin /tmp/pipe image/grey/320x240; +#X text 102 19 pdp_rawin: read raw data from a pipe (or file); +#X connect 0 0 15 0; +#X connect 1 0 15 0; +#X connect 10 0 15 0; +#X connect 12 0 1 0; +#X connect 13 0 12 1; +#X connect 14 0 15 0; +#X connect 15 0 3 0; +#X connect 15 1 6 0; +#X connect 15 1 12 0; diff --git a/doc/objects/pdp_rawout.pd b/doc/objects/pdp_rawout.pd new file mode 100644 index 0000000..0f231bf --- /dev/null +++ b/doc/objects/pdp_rawout.pd @@ -0,0 +1,28 @@ +#N canvas 254 556 687 380 10; +#X msg 132 63 open /tmp/otherpipe; +#X msg 177 145 open; +#X text 216 145 open default pipe; +#X obj 132 219 print done; +#X text 117 266 connect to [open< to ensure pipe stays open; +#X text 278 64 open any pipe for reading; +#X msg 147 85 close; +#X text 193 85 close pipe; +#X obj 177 125 spigot; +#X obj 230 124 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X text 134 15 pdp_rawout: write raw data to a pipe (or file); +#X text 293 169 creation args: <pipe>; +#X obj 132 169 pdp_rawout /tmp/pipe; +#X obj 15 124 pdp_help_input; +#X obj 15 98 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X text 116 250 outlet: bang if pipe is closed; +#X connect 0 0 12 0; +#X connect 1 0 12 0; +#X connect 6 0 12 0; +#X connect 8 0 1 0; +#X connect 9 0 8 1; +#X connect 12 0 3 0; +#X connect 12 0 8 0; +#X connect 13 0 12 0; +#X connect 14 0 13 0; diff --git a/doc/objects/pdp_reg.pd b/doc/objects/pdp_reg.pd new file mode 100644 index 0000000..dca00ef --- /dev/null +++ b/doc/objects/pdp_reg.pd @@ -0,0 +1,38 @@ +#N canvas 327 276 676 444 10; +#X obj 41 318 pdp_reg; +#X obj 41 287 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 85 15 start; +#X msg 135 15 stop; +#X obj 85 53 pdp_help_input; +#X obj 41 359 pdp_help_output; +#X text 121 90 pdp_reg works in the same way as the pd float or int +objects; +#X text 271 124 bang: sends stored packet to output; +#X text 271 109 pdp: stores packet and sends to output; +#X text 271 145 pdp: stores a new packet; +#X text 121 111 left intlet (hot):; +#X text 120 145 right intlet (cold):; +#X msg 122 236 load_png \$1; +#X obj 122 212 openpanel; +#X obj 122 190 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 219 189 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 219 235 save_png \$1; +#X text 331 226 as a png image file.; +#X text 332 211 you can save the contents of the register; +#X obj 219 211 savepanel; +#X msg 219 266 save_png /tmp/snap.png; +#X connect 0 0 5 0; +#X connect 1 0 0 0; +#X connect 2 0 4 0; +#X connect 3 0 4 0; +#X connect 4 0 0 1; +#X connect 12 0 0 0; +#X connect 13 0 12 0; +#X connect 14 0 13 0; +#X connect 15 0 19 0; +#X connect 16 0 0 0; +#X connect 19 0 16 0; +#X connect 20 0 0 0; diff --git a/doc/objects/pdp_rotate.pd b/doc/objects/pdp_rotate.pd new file mode 100644 index 0000000..6c60c60 --- /dev/null +++ b/doc/objects/pdp_rotate.pd @@ -0,0 +1,30 @@ +#N canvas 467 414 562 448 10; +#X msg 195 174 centerx \$1; +#X floatatom 195 145 5 0 0; +#X floatatom 279 145 5 0 0; +#X msg 279 174 centery \$1; +#X obj 46 40 pdp_help_input; +#X msg 46 10 start; +#X msg 95 10 stop; +#X obj 46 401 pdp_help_output; +#X text 194 70 (0 \, 0) = top left; +#X text 194 84 (1 \, 1) = bottom right; +#X msg 247 113 0.5; +#X floatatom 187 318 5 0 0; +#X msg 187 288 0; +#X text 192 6 pdp_zrot: zoom and rotation; +#X obj 46 363 pdp_rotate; +#X text 239 319 right inlet sets rotation angle; +#X text 194 54 set rotation center; +#X connect 0 0 14 0; +#X connect 1 0 0 0; +#X connect 2 0 3 0; +#X connect 3 0 14 0; +#X connect 4 0 14 0; +#X connect 5 0 4 0; +#X connect 6 0 4 0; +#X connect 10 0 1 0; +#X connect 10 0 2 0; +#X connect 11 0 14 1; +#X connect 12 0 11 0; +#X connect 14 0 7 0; diff --git a/doc/objects/pdp_route.pd b/doc/objects/pdp_route.pd new file mode 100644 index 0000000..c9d341d --- /dev/null +++ b/doc/objects/pdp_route.pd @@ -0,0 +1,22 @@ +#N canvas 614 448 575 277 10; +#X obj 46 40 pdp_help_input; +#X msg 46 10 start; +#X msg 95 10 stop; +#X obj 46 225 pdp_help_output; +#X obj 46 172 pdp_gain 1; +#X obj 130 172 pdp_gain 2; +#X obj 118 69 hdl 15 1 0 2 empty empty empty 0 -6 0 8 -262144 -1 -1 +0; +#X text 155 88 routes a packet to a specified outlet \, determined +by the right inlet; +#X text 155 124 creation argument = number of outlets (default = 2) +; +#X obj 46 90 pdp_route 2; +#X connect 0 0 9 0; +#X connect 1 0 0 0; +#X connect 2 0 0 0; +#X connect 4 0 3 0; +#X connect 5 0 3 0; +#X connect 6 0 9 1; +#X connect 9 0 4 0; +#X connect 9 1 5 0; diff --git a/doc/objects/pdp_scale.pd b/doc/objects/pdp_scale.pd new file mode 100644 index 0000000..9ed7996 --- /dev/null +++ b/doc/objects/pdp_scale.pd @@ -0,0 +1,32 @@ +#N canvas 475 141 635 386 10; +#X msg 76 207 dim 256 256; +#X msg 76 235 dim 320 240; +#X obj 28 275 pdp_scale 320 240; +#X msg 75 181 dim 32 32; +#X msg 259 234 quality \$1; +#X obj 28 65 pdp_help_input; +#X msg 28 36 start; +#X msg 80 35 stop; +#X obj 28 317 pdp_help_output; +#X text 347 225 0 = nearest neighbour; +#X text 347 240 1 = bilinear; +#X text 74 154 set new packet dimensions; +#X text 161 28 pdp_scale rescales the packet format.; +#X text 161 56 use this if you want to combine different packet sizes. +or have movies that don't have a legal size (not a multiple of 8x8) +; +#X msg 259 204 0; +#X msg 294 204 1; +#X text 159 103 (try to avoid rescaling by using movies with equal +(legal) dimensions \, it is not a cheap operation and can easily be +done in advance); +#X connect 0 0 2 0; +#X connect 1 0 2 0; +#X connect 2 0 8 0; +#X connect 3 0 2 0; +#X connect 4 0 2 0; +#X connect 5 0 2 0; +#X connect 6 0 5 0; +#X connect 7 0 5 0; +#X connect 14 0 4 0; +#X connect 15 0 4 0; diff --git a/doc/objects/pdp_scanxy~.pd b/doc/objects/pdp_scanxy~.pd new file mode 100644 index 0000000..5edad44 --- /dev/null +++ b/doc/objects/pdp_scanxy~.pd @@ -0,0 +1,76 @@ +#N canvas 362 152 806 785 10; +#X floatatom 73 226 5 0 0; +#X obj 73 602 dac~; +#X obj 13 48 pdp_help_input; +#X msg 13 19 start; +#X obj 13 632 pdp_help_output; +#X obj 73 546 *~; +#X floatatom 89 517 5 0 0; +#X obj 73 486 hip~ 20; +#X floatatom 117 459 5 0 0; +#X floatatom 131 406 5 0 0; +#X obj 73 433 lop~ 1000; +#X msg 222 342 interpolate \$1; +#X obj 222 316 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X text 251 313 set interpolation between consecutive packets on/off +; +#X text 216 377 (the audio crossfade size is determined by the pd blocksize. +so you can use a block~ object to set this); +#X obj 73 375 pdp_scanxy~; +#X floatatom 145 228 5 0 0; +#X floatatom 73 146 5 0 0; +#X msg 224 225 0; +#X msg 255 225 0.25; +#X obj 224 197 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 61 20 stop; +#X obj 13 96 pdp_blur; +#X floatatom 58 72 5 0 0; +#X floatatom 161 167 5 0 0; +#X obj 145 198 * 1; +#X text 220 46 pdp_scanxy~: scanned synthesis with coordinate input. +(0 \, 0) = top left \, (1 \, 1) = bottom right; +#X obj 73 267 osc~; +#X obj 145 266 osc~; +#X text 223 164 set frequency ratio for lissajous path; +#X text 250 196 resync phase; +#X obj 73 293 *~ 0.5; +#X obj 145 293 *~ 0.5; +#X obj 73 318 +~ 0.5; +#X obj 145 318 +~ 0.5; +#X text 220 87 the waveform is scanned from the luma plane of an image. +the path is determined by the left(x) and right(y) coordinate inlets. +; +#X connect 0 0 27 0; +#X connect 2 0 22 0; +#X connect 3 0 2 0; +#X connect 5 0 1 0; +#X connect 5 0 1 1; +#X connect 6 0 5 1; +#X connect 7 0 5 0; +#X connect 8 0 7 1; +#X connect 9 0 10 1; +#X connect 10 0 7 0; +#X connect 11 0 15 0; +#X connect 12 0 11 0; +#X connect 15 0 10 0; +#X connect 16 0 28 0; +#X connect 17 0 0 0; +#X connect 17 0 25 0; +#X connect 18 0 27 1; +#X connect 19 0 28 1; +#X connect 20 0 18 0; +#X connect 20 0 19 0; +#X connect 21 0 2 0; +#X connect 22 0 4 0; +#X connect 22 0 15 0; +#X connect 23 0 22 1; +#X connect 24 0 25 1; +#X connect 25 0 16 0; +#X connect 27 0 31 0; +#X connect 28 0 32 0; +#X connect 31 0 33 0; +#X connect 32 0 34 0; +#X connect 33 0 15 0; +#X connect 34 0 15 1; diff --git a/doc/objects/pdp_scan~.pd b/doc/objects/pdp_scan~.pd new file mode 100644 index 0000000..69b0900 --- /dev/null +++ b/doc/objects/pdp_scan~.pd @@ -0,0 +1,41 @@ +#N canvas 387 370 666 499 10; +#X obj 73 140 pdp_scan~; +#X obj 73 113 phasor~; +#X floatatom 73 86 5 0 0; +#X obj 73 353 dac~; +#X obj 13 48 pdp_help_input; +#X msg 13 19 start; +#X obj 13 397 pdp_help_output; +#X obj 73 311 *~; +#X floatatom 89 282 5 0 0; +#X obj 73 251 hip~ 20; +#X floatatom 117 224 5 0 0; +#X floatatom 131 171 5 0 0; +#X obj 73 198 lop~ 1000; +#X msg 217 102 interpolate \$1; +#X obj 217 76 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X text 216 124 set interpolation between consecutive packets on/off +; +#X text 216 142 (the audio crossfade size is determined by the pd blocksize. +so you can use a block~ object to set this); +#X text 218 236 the waveform is scanned from the luma plane of an image. +the path is an oval centered at the middle of the image with axes equal +to 60% of the image width/height.; +#X text 214 43 pdp_scan~: oval scanned synthesis with a phase input +; +#X connect 0 0 12 0; +#X connect 1 0 0 0; +#X connect 2 0 1 0; +#X connect 4 0 0 0; +#X connect 4 0 6 0; +#X connect 5 0 4 0; +#X connect 7 0 3 0; +#X connect 7 0 3 1; +#X connect 8 0 7 1; +#X connect 9 0 7 0; +#X connect 10 0 9 1; +#X connect 11 0 12 1; +#X connect 12 0 9 0; +#X connect 13 0 0 0; +#X connect 14 0 13 0; diff --git a/doc/objects/pdp_scope~.pd b/doc/objects/pdp_scope~.pd new file mode 100644 index 0000000..eeeaabe --- /dev/null +++ b/doc/objects/pdp_scope~.pd @@ -0,0 +1,23 @@ +#N canvas 526 43 567 300 10; +#X obj 37 200 pdp_scope~; +#X obj 37 44 metro 40; +#X obj 37 19 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X floatatom 94 18 5 0 0; +#X msg 131 131 type grey; +#X msg 131 109 type yv12; +#X obj 37 256 pdp_help_output; +#X msg 131 157 dim 320 240; +#X obj 59 121 osc~; +#X floatatom 59 88 5 0 0; +#X text 131 66 a very simple oscilloscope; +#X text 227 132 set output image type and dimensions; +#X connect 0 0 6 0; +#X connect 1 0 0 0; +#X connect 2 0 1 0; +#X connect 3 0 1 1; +#X connect 4 0 0 0; +#X connect 5 0 0 0; +#X connect 7 0 0 0; +#X connect 8 0 0 0; +#X connect 9 0 8 0; diff --git a/doc/objects/pdp_sign.pd b/doc/objects/pdp_sign.pd new file mode 100644 index 0000000..2e3f775 --- /dev/null +++ b/doc/objects/pdp_sign.pd @@ -0,0 +1,25 @@ +#N canvas 479 219 500 438 10; +#X msg 77 38 start; +#X msg 124 38 stop; +#X obj 77 70 pdp_help_input; +#X obj 77 340 pdp_help_output; +#X floatatom 128 135 5 0 0; +#X obj 77 296 pdp_gain; +#X msg 145 271 1; +#X msg 128 109 -0.5; +#X obj 77 231 pdp_sign; +#X text 239 231 get the sign (-1 \, 1); +#X obj 77 268 pdp_mul; +#X obj 77 163 pdp_gain; +#X obj 173 207 pdp_abs; +#X connect 0 0 2 0; +#X connect 1 0 2 0; +#X connect 2 0 10 1; +#X connect 2 0 11 0; +#X connect 4 0 11 1; +#X connect 5 0 3 0; +#X connect 6 0 5 1; +#X connect 7 0 4 0; +#X connect 8 0 10 0; +#X connect 10 0 5 0; +#X connect 11 0 8 0; diff --git a/doc/objects/pdp_snap.pd b/doc/objects/pdp_snap.pd new file mode 100644 index 0000000..b5c2752 --- /dev/null +++ b/doc/objects/pdp_snap.pd @@ -0,0 +1,21 @@ +#N canvas 623 480 596 300 10; +#X msg 92 15 start; +#X msg 142 15 stop; +#X obj 92 53 pdp_help_input; +#X obj 41 240 pdp_help_output; +#X text 140 172 bang: sends stored packet to output; +#X text 113 143 left intlet (hot):; +#X text 112 202 right intlet (cold):; +#X obj 41 171 pdp_snap; +#X text 115 103 pdp_reg takes a snapshot from a pdp stream.; +#X text 263 201 pdp inlet; +#X text 139 157 snap: stores the next packet that arrives on second +inlet; +#X msg 8 130 bang; +#X msg 49 130 snap; +#X connect 0 0 2 0; +#X connect 1 0 2 0; +#X connect 2 0 7 1; +#X connect 7 0 3 0; +#X connect 11 0 7 0; +#X connect 12 0 7 0; diff --git a/doc/objects/pdp_sthresh.pd b/doc/objects/pdp_sthresh.pd new file mode 100644 index 0000000..0267fc5 --- /dev/null +++ b/doc/objects/pdp_sthresh.pd @@ -0,0 +1,26 @@ +#N canvas 504 211 500 438 10; +#X msg 77 38 start; +#X msg 124 38 stop; +#X obj 77 70 pdp_help_input; +#X obj 77 340 pdp_help_output; +#X obj 77 163 pdp_gain; +#X floatatom 128 135 5 0 0; +#X msg 128 109 0.5; +#X obj 77 296 pdp_gain; +#X msg 128 268 1; +#X obj 77 231 pdp_sthresh; +#X floatatom 160 199 5 0 0; +#X text 233 230 soft threshold; +#X text 234 283 (-t > x > t) -> 0; +#X text 234 266 (-t > x) -> (x + t); +#X text 234 248 ( x > t) -> (x - t); +#X connect 0 0 2 0; +#X connect 1 0 2 0; +#X connect 2 0 4 0; +#X connect 4 0 9 0; +#X connect 5 0 4 1; +#X connect 6 0 5 0; +#X connect 7 0 3 0; +#X connect 8 0 7 1; +#X connect 9 0 7 0; +#X connect 10 0 9 1; diff --git a/doc/objects/pdp_trigger.pd b/doc/objects/pdp_trigger.pd new file mode 100644 index 0000000..2cabece --- /dev/null +++ b/doc/objects/pdp_trigger.pd @@ -0,0 +1,79 @@ +#N canvas 218 0 631 489 10; +#X obj 46 40 pdp_help_input; +#X msg 46 10 start; +#X msg 95 10 stop; +#X obj 46 179 pdp_help_output; +#X obj 46 102 pdp_trigger; +#X text 163 98 default behaviour is to outputs bang on the right output +before sending packet to the left output; +#X obj 118 146 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 45 269 pdp_noise; +#X obj 45 245 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 45 294 pdp_trigger bang pdp bang bang pdp; +#X obj 45 460 print o1; +#X obj 278 326 print o5; +#X obj 161 388 print o3; +#X obj 103 429 print o2; +#X obj 219 354 print o4; +#X text 163 57 pdp_trigger behaves very much like the pd trigger object +; +#X text 162 243 you can give it pdp (p) or bang (b) arguments to send +out packets or bangs from right to left; +#X obj 365 406 pdp_t b p b b p; +#X text 325 386 there is also a short version:; +#X text 142 565 confusing note:; +#X obj 46 575 pdp_noise; +#X obj 46 551 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 46 604 pdp_add; +#X obj 61 746 pdp_noise; +#X obj 61 722 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 61 806 pdp_add; +#X obj 105 776 pdp_gain; +#X text 142 584 you don't need a trigger object if you connect a pdp +object's outlet to only one active inlet.; +#X text 139 657 if an outlet is connected to more than one active inlet +\, you need a trigger object like you would do with standard pd message +objects; +#X obj 285 725 pdp_noise; +#X obj 285 701 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 285 806 pdp_add; +#X obj 343 778 pdp_gain; +#X obj 285 751 pdp_t p p; +#X floatatom 156 750 5 0 0; +#X floatatom 394 750 5 0 0; +#X text 287 829 correct; +#X text 139 852 (even more confusing note: this is because pdp uses +a 3 phase communication protocol.); +#X text 452 459 (scroll down for more); +#X text 48 829 unpredictable; +#X connect 0 0 4 0; +#X connect 1 0 0 0; +#X connect 2 0 0 0; +#X connect 4 0 3 0; +#X connect 4 1 6 0; +#X connect 7 0 9 0; +#X connect 8 0 7 0; +#X connect 9 0 10 0; +#X connect 9 1 13 0; +#X connect 9 2 12 0; +#X connect 9 3 14 0; +#X connect 9 4 11 0; +#X connect 20 0 22 0; +#X connect 20 0 22 1; +#X connect 21 0 20 0; +#X connect 23 0 25 0; +#X connect 23 0 26 0; +#X connect 24 0 23 0; +#X connect 26 0 25 1; +#X connect 29 0 33 0; +#X connect 30 0 29 0; +#X connect 32 0 31 1; +#X connect 33 0 31 0; +#X connect 33 1 32 0; +#X connect 34 0 26 1; +#X connect 35 0 32 1; diff --git a/doc/objects/pdp_v4l.pd b/doc/objects/pdp_v4l.pd new file mode 100644 index 0000000..3b1ea9d --- /dev/null +++ b/doc/objects/pdp_v4l.pd @@ -0,0 +1,71 @@ +#N canvas 283 209 927 686 10; +#X obj 107 53 metro 40; +#X msg 159 14 stop; +#X msg 107 14 bang; +#X msg 51 14 bang; +#X msg 210 132 open /dev/video0; +#X msg 210 156 open /dev/video1; +#X text 348 128 you can choose the input device using the 'open' message. +the default is /dev/video0; +#X msg 210 181 close; +#X text 349 182 closes the video port; +#X msg 210 207 type yv12; +#X msg 210 231 type grey; +#X text 349 210 type sets the ouput image package type. currently only +yv12 (luma/chroma color) and greyscale are supported.; +#X msg 211 260 dim 320 240; +#X msg 211 283 dim 640 480; +#X msg 212 336 channel \$1; +#X floatatom 212 312 5 0 0 0 - - -; +#X floatatom 210 459 5 0 0 0 - - -; +#X msg 210 483 freq \$1; +#X floatatom 271 459 5 0 0 0 - - -; +#X msg 271 483 freqMHz \$1; +#X text 346 459 sets the v4l tuner frequency (in v4l units and MHz) +; +#X obj 107 580 pdp_help_output; +#X text 348 526 creation arguments: <input device> <capture format> +; +#X text 347 620 i.e. if you get weird colours \, try; +#X obj 601 620 pdp_v4l /dev/video RGB24; +#X text 206 14 pdp_v4l grabs video from the video4linux device. it +sends out the most recently grabbed frame whenever a bang message is +received \, and will then discard that frame (it will be sent out on +time at most). the output framerate is limited by the device only. +; +#X text 206 89 (to make sure you receive every frame with little jitter +\, poll pdp_v4l with a high rate metronome); +#X text 348 554 capture format can be one of "auto" \, "YUV420P" \, +"YUV422" \, "RGB24" or "RGB32". for most cards autodetect (default) +should work. if not \, add the desired capture format argument when +you create a pdp_v4l object.; +#X obj 107 527 pdp_v4l; +#X text 349 338 sets the v4l channel (like tuner \, composite \, svideo +\, ...); +#X msg 212 366 norm PAL; +#X msg 211 410 norm SECAM; +#X msg 211 388 norm NTSC; +#X msg 211 431 norm AUTO; +#X text 349 377 sets the video norm; +#X connect 0 0 28 0; +#X connect 1 0 0 0; +#X connect 2 0 0 0; +#X connect 3 0 28 0; +#X connect 4 0 28 0; +#X connect 5 0 28 0; +#X connect 7 0 28 0; +#X connect 9 0 28 0; +#X connect 10 0 28 0; +#X connect 12 0 28 0; +#X connect 13 0 28 0; +#X connect 14 0 28 0; +#X connect 15 0 14 0; +#X connect 16 0 17 0; +#X connect 17 0 28 0; +#X connect 18 0 19 0; +#X connect 19 0 28 0; +#X connect 28 0 21 0; +#X connect 30 0 28 0; +#X connect 31 0 28 0; +#X connect 32 0 28 0; +#X connect 33 0 28 0; diff --git a/doc/objects/pdp_xor.pd b/doc/objects/pdp_xor.pd new file mode 100644 index 0000000..40366e2 --- /dev/null +++ b/doc/objects/pdp_xor.pd @@ -0,0 +1,28 @@ +#N canvas 552 356 511 383 10; +#X msg 100 45 start; +#X msg 147 45 stop; +#X obj 100 77 pdp_help_input; +#X obj 100 329 pdp_help_output; +#X obj 144 252 pdp_reg; +#X obj 213 204 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X text 246 202 click here; +#X obj 100 170 pdp_gain; +#X floatatom 151 142 5 0 0; +#X msg 151 116 0.5; +#X obj 100 286 pdp_xor; +#X text 252 290 bitwise xor; +#X msg 11 205 chanmask \$1; +#X floatatom 11 180 5 0 0; +#X connect 0 0 2 0; +#X connect 1 0 2 0; +#X connect 2 0 7 0; +#X connect 4 0 10 1; +#X connect 5 0 4 0; +#X connect 7 0 4 1; +#X connect 7 0 10 0; +#X connect 8 0 7 1; +#X connect 9 0 8 0; +#X connect 10 0 3 0; +#X connect 12 0 10 0; +#X connect 13 0 12 0; diff --git a/doc/objects/pdp_xv.pd b/doc/objects/pdp_xv.pd new file mode 100644 index 0000000..ef77559 --- /dev/null +++ b/doc/objects/pdp_xv.pd @@ -0,0 +1,61 @@ +#N canvas 251 11 708 682 10; +#X msg 132 223 dim 320 240; +#X msg 132 246 dim 640 480; +#X text 300 227 dim sets the window dimensions; +#X msg 131 151 create; +#X msg 131 172 destroy; +#X text 129 88 pdp_xv ouputs video in a window using the xVideo extension. +if your graphics card/driver supports it you can have multiple output +windows. if a pdp message is received and a window is not open \, one +is created automaticly.; +#X text 229 159 use these messages to explicitly create/destroy the +window; +#X msg 133 463 cursor \$1; +#X obj 133 443 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X text 298 464 enables/disables cursor in xv window; +#X obj 29 61 pdp_help_input; +#X msg 29 25 start; +#X msg 78 24 stop; +#X text 295 200 specify the x window display; +#X msg 131 197 display :0; +#X obj 29 587 print; +#X text 133 584 the output channel sends mouse event messages (press/release/drag +and individual p/r/d for each button); +#X obj 29 551 pdp_xv; +#X msg 132 273 pos 100 100; +#X text 300 273 set window position; +#X msg 132 336 fullscreen; +#X text 298 340 resize to entire screen; +#X text 299 305 set both at once; +#X msg 132 303 posdim 100 300 320 240; +#X msg 131 417 tile 5 5 \$1 \$2; +#X text 297 418 take a part of the screen (for tiling multiple pdp_xv's) +; +#X obj 131 396 pack 0 0; +#X obj 190 396 t b f; +#X floatatom 131 377 5 0 0 0 - - -; +#X floatatom 190 376 5 0 0 0 - - -; +#X msg 134 489 movecursor 0.5 0.5; +#X text 299 486 move the cursor inside the window; +#X connect 0 0 17 0; +#X connect 1 0 17 0; +#X connect 3 0 17 0; +#X connect 4 0 17 0; +#X connect 7 0 17 0; +#X connect 8 0 7 0; +#X connect 10 0 17 0; +#X connect 11 0 10 0; +#X connect 12 0 10 0; +#X connect 14 0 17 0; +#X connect 17 0 15 0; +#X connect 18 0 17 0; +#X connect 20 0 17 0; +#X connect 23 0 17 0; +#X connect 24 0 17 0; +#X connect 26 0 24 0; +#X connect 27 0 26 0; +#X connect 27 1 26 1; +#X connect 28 0 26 0; +#X connect 29 0 27 0; +#X connect 30 0 17 0; diff --git a/doc/objects/pdp_zoom.pd b/doc/objects/pdp_zoom.pd new file mode 100644 index 0000000..19ec1a7 --- /dev/null +++ b/doc/objects/pdp_zoom.pd @@ -0,0 +1,41 @@ +#N canvas 467 414 562 448 10; +#X obj 46 288 pdp_zoom; +#X floatatom 121 264 5 0 0; +#X floatatom 174 130 5 0 0; +#X msg 87 160 zoomx \$1; +#X msg 174 160 zoomy \$1; +#X floatatom 87 129 5 0 0; +#X msg 282 162 centerx \$1; +#X floatatom 282 133 5 0 0; +#X floatatom 366 133 5 0 0; +#X msg 366 162 centery \$1; +#X obj 46 40 pdp_help_input; +#X msg 46 10 start; +#X msg 95 10 stop; +#X obj 46 341 pdp_help_output; +#X text 173 265 right inlet sets zoom amount; +#X text 281 42 set zoom center; +#X text 281 58 (0 \, 0) = top left; +#X text 281 72 (1 \, 1) = bottom right; +#X text 71 79 set individual axis zoom; +#X msg 142 102 1; +#X msg 334 101 0.5; +#X msg 121 234 1; +#X connect 0 0 13 0; +#X connect 1 0 0 1; +#X connect 2 0 4 0; +#X connect 3 0 0 0; +#X connect 4 0 0 0; +#X connect 5 0 3 0; +#X connect 6 0 0 0; +#X connect 7 0 6 0; +#X connect 8 0 9 0; +#X connect 9 0 0 0; +#X connect 10 0 0 0; +#X connect 11 0 10 0; +#X connect 12 0 10 0; +#X connect 19 0 2 0; +#X connect 19 0 5 0; +#X connect 20 0 7 0; +#X connect 20 0 8 0; +#X connect 21 0 1 0; diff --git a/doc/objects/pdp_zrot.pd b/doc/objects/pdp_zrot.pd new file mode 100644 index 0000000..f3937a0 --- /dev/null +++ b/doc/objects/pdp_zrot.pd @@ -0,0 +1,47 @@ +#N canvas 467 414 562 448 10; +#X floatatom 257 275 5 0 0; +#X floatatom 174 130 5 0 0; +#X msg 87 160 zoomx \$1; +#X msg 174 160 zoomy \$1; +#X floatatom 87 129 5 0 0; +#X msg 282 162 centerx \$1; +#X floatatom 282 133 5 0 0; +#X floatatom 366 133 5 0 0; +#X msg 366 162 centery \$1; +#X obj 46 40 pdp_help_input; +#X msg 46 10 start; +#X msg 95 10 stop; +#X obj 46 401 pdp_help_output; +#X text 281 58 (0 \, 0) = top left; +#X text 281 72 (1 \, 1) = bottom right; +#X text 71 79 set individual axis zoom; +#X msg 142 102 1; +#X msg 334 101 0.5; +#X msg 257 245 1; +#X obj 46 363 pdp_zrot; +#X text 309 276 second inlet sets zoom amount; +#X floatatom 257 333 5 0 0; +#X msg 257 303 0; +#X text 309 334 third inlet sets rotation angle; +#X text 281 42 set zoom/rotation center; +#X text 192 6 pdp_zrot: zoom and rotation; +#X connect 0 0 19 1; +#X connect 1 0 3 0; +#X connect 2 0 19 0; +#X connect 3 0 19 0; +#X connect 4 0 2 0; +#X connect 5 0 19 0; +#X connect 6 0 5 0; +#X connect 7 0 8 0; +#X connect 8 0 19 0; +#X connect 9 0 19 0; +#X connect 10 0 9 0; +#X connect 11 0 9 0; +#X connect 16 0 1 0; +#X connect 16 0 4 0; +#X connect 17 0 6 0; +#X connect 17 0 7 0; +#X connect 18 0 0 0; +#X connect 19 0 12 0; +#X connect 21 0 19 2; +#X connect 22 0 21 0; diff --git a/doc/objects/pdp_zthresh.pd b/doc/objects/pdp_zthresh.pd new file mode 100644 index 0000000..df5209b --- /dev/null +++ b/doc/objects/pdp_zthresh.pd @@ -0,0 +1,21 @@ +#N canvas 504 211 500 438 10; +#X msg 77 38 start; +#X msg 124 38 stop; +#X obj 77 70 pdp_help_input; +#X obj 77 340 pdp_help_output; +#X obj 77 163 pdp_gain; +#X floatatom 128 135 5 0 0; +#X msg 128 109 0.5; +#X obj 77 296 pdp_gain; +#X msg 128 268 1; +#X text 233 230 zero threshold ( < 0 -> 0 ); +#X obj 77 231 pdp_zthresh; +#X connect 0 0 2 0; +#X connect 1 0 2 0; +#X connect 2 0 4 0; +#X connect 4 0 10 0; +#X connect 5 0 4 1; +#X connect 6 0 5 0; +#X connect 7 0 3 0; +#X connect 8 0 7 1; +#X connect 10 0 7 0; diff --git a/include/Makefile b/include/Makefile new file mode 100644 index 0000000..1aba02c --- /dev/null +++ b/include/Makefile @@ -0,0 +1,6 @@ +current: + + +clean: + rm -f *~ + diff --git a/include/pdp.h b/include/pdp.h new file mode 100644 index 0000000..ed57b24 --- /dev/null +++ b/include/pdp.h @@ -0,0 +1,158 @@ +/* + * Pure Data Packet header file. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#ifndef PDP_H +#define PDP_H + + +/* header and subheader size in bytes */ + +#include <string.h> +#include <stdlib.h> + +#include "pdp_pd.h" + +/* config stuff */ +#include "pdp_config.h" + +/* debug stuff */ +#include "pdp_debug.h" + +/* some typedefs */ +#include "pdp_types.h" + +/* pdp's symbol handling */ +#include "pdp_symbol.h" + +/* the list object */ +#include "pdp_list.h" + +/* memory management */ +#include "pdp_mem.h" + +/* console messages */ +#include "pdp_post.h" + + +/* PDP_IMAGE COMPONENTS */ + +/* header and methods for the built in image packet type */ +#include "pdp_image.h" + +/* low level image processing and high level dispatching routines */ +#include "pdp_imageproc.h" + +/* low level image conversion routines */ +#include "pdp_llconv.h" + +/* low level image resampling routines */ +#include "pdp_resample.h" + + + +/* PDP_BITMAP COMPONENTS */ + +/* header and methods for the built in bitmap packet type */ +#include "pdp_bitmap.h" + + + +/* PDP_MATRIX COMPONENTS */ +#include "pdp_matrix.h" + + + + +/* PDP SYSTEM COMPONENTS */ + +/* packet pool stuff */ +#include "pdp_packet.h" + +/* processing queue object */ +#include "pdp_queue.h" + +/* several communication helper methods (pd specific) */ +#include "pdp_comm.h" + +/* type handling subsystem */ +#include "pdp_type.h" + +/* dpd command stuff */ +#include "pdp_dpd_command.h" + + +/* BACKWARDS COMPAT STUFF */ +#include "pdp_compat.h" + + + + +#endif + +/* + + PDP CORE API OVERVIEW + + pdp_packet_* : packet methods, first argument is packet id + + new: construct a raw packet (depreciated) + new_*: construct packet of specific type/subtype/... + mark_unused: release + mark_passing: conditional release (release on first copy ro/rw) + copy_ro: readonly (shared) copy + copy_rw: private copy + clone_rw: private copy (copies only meta data, not the content) + header: get the raw header (t_pdp *) + data: get the raw data (void *) + pass_if_valid: send a packet to pd outlet, if it is valid + replace_if_valid delete packet and replace with new one, if new is valid + copy_ro_or_drop: copy readonly, or don't copy if dest slot is full + send drop notify + copy_rw_or_drop: same, but private copy + get_description: retrieve type info + convert_ro: same as copy_ro, but with an automatic conversion matching a type template + convert_rw: same as convert_ro, but producing a private copy + + pdp_pool_* : packet pool methods + + collect_garbage: manually free all unused resources in packet pool + + pdp_queue_* : processing queue methods + + add: add a process method + callback + finish: wait until a specific task is done + wait: wait until processing queue is done + + pdp_control_* : central pdp control hub methods + + notify_drop: notify that a packet has been dropped + + pdp_type_* : packet type mediator methods + + description_match: check if two type templates match + register_conversion: register a type conversion program + + + + NOTE: it is advised to derive your module from the pdp base class defined in pdp_base.h + instead of communicating directly with the pdp core + +*/ diff --git a/include/pdp_ascii.h b/include/pdp_ascii.h new file mode 100644 index 0000000..1fde9b4 --- /dev/null +++ b/include/pdp_ascii.h @@ -0,0 +1,39 @@ +/* + * Pure Data Packet header file. ascii packet type. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +#ifndef PDP_H +#define PDP_H + +/* ascii data packet */ +typedef struct +{ + unsigned int encoding; /* image encoding (data format) */ + unsigned int width; /* image width in pixels */ + unsigned int height; /* image height in pixels */ +} t_ascii; + + +/* ascii encodings */ +#define PDP_ASCII_BW 1 /* 8 bit per character black and white.*/ +#define PDP_ASCII_IBM 2 /* 16 bit per character colour (8 bit character, 8 bit colour, like good old text framebuffers.*/ +#define PDP_ASCII_RGB 3 /* 64 bit per character colour (8 bit character, 3x8 bit RGB */ + +#endif diff --git a/include/pdp_base.h b/include/pdp_base.h new file mode 100644 index 0000000..2839f37 --- /dev/null +++ b/include/pdp_base.h @@ -0,0 +1,136 @@ +/* + * Pure Data Packet base class header file. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 file contains the specification of the pdp base class. It is derived + from t_object, the basic pd object (like any other pd extern). Have a look + at pdp_add, pdp_gain and pdp_noise to see how to use this. + +*/ + + +#define MAX_NB_PDP_BASE_INLETS 4 +#define MAX_NB_PDP_BASE_OUTLETS 4 + +#include "pdp_pd.h" +#include "pdp_symbol.h" +#include "pdp_types.h" +#include "pdp_queue.h" +#include "pdp_comm.h" +#include "pdp_compat.h" +#include "pdp_packet.h" + +typedef void (*t_pdp_method)(void *); +typedef void* (*t_pdp_newmethod)(void *); + + +typedef struct +{ + t_object x_obj; + + int b_inlets; // the number of pdp inlets + int b_outlets; // the number of pdp outlets + + // registers to store incoming packets + int b_packet[MAX_NB_PDP_BASE_INLETS]; + int b_packet_next[MAX_NB_PDP_BASE_INLETS]; + t_pdp_symbol *b_type_template[MAX_NB_PDP_BASE_INLETS]; + + int b_queue_id; // task id in process queue (for callback cancelling) + //int b_dropped; // indicate if a packet was dropped during register_rw cycle + + // wil the default (left) active inlet accept pdp messages ? + int b_active_inlet_enabled; + int b_active_inlet_readonly; + + // the process callbacks + t_pdp_method b_process_method; // called in pdp thread + t_pdp_method b_preproc_method; // called before thread (for packet alloc and checking) + t_pdp_method b_postproc_method; // called after thread (for outlet stuff other than default active packet->out0) + + // packet outlets + t_outlet *b_outlet[MAX_NB_PDP_BASE_OUTLETS]; + + u32 b_channel_mask; // channel mask + + int b_thread_enabled; // thread enable switch + + t_pdp_procqueue *b_q; // queue object + +} t_pdp_base; + + + +/* setup base class. call this in your derived class setup method */ +void pdp_base_setup(t_class *c); + + +/* base class constructor/destructor. call this in your base class constructor/destructor */ +void pdp_base_init(void *x); +void pdp_base_free(void *x); + + +/* register processing callbacks */ +void pdp_base_set_process_method(void *x, t_pdp_method m); //process callback (called from pdp thread) +void pdp_base_set_preproc_method(void *x, t_pdp_method m); //pre-process callback (called before process from pd thread) +void pdp_base_set_postproc_method(void *x, t_pdp_method m); //post-process callback (called after process from pd thread) + + +/* configure inlets/outlets */ +void pdp_base_add_pdp_inlet(void *x); +t_outlet *pdp_base_add_pdp_outlet(void *x); +void pdp_base_disable_active_inlet(void *x); //use this for pdp generators +void pdp_base_readonly_active_inlet(void *x); //use this for pdp converters ("out of place" processing) +void pdp_base_add_gen_inlet(void *x, t_symbol *from, t_symbol *to); // generic inlet + + +/* bang method */ +void pdp_base_bang(void *x); + + +/* move delayed passive packets in place */ +void pdp_base_movepassive(void *x); + + + +/* packet manipulation methods + 0 active inlet (left) if enabled + >0 additional pdp inlets created with pdp_base_add_pdp_inlet */ +int pdp_base_get_packet(void *x, int inlet); // get the packet from an inlet +int pdp_base_move_packet(void *x, int inlet); // same as get, but it removes the reference in the base class +void pdp_base_set_packet(void *x, int inlet, int packet); // set (replace) the active packet (will be sent to outlet) + + +/* getters for base class data */ +u32 pdp_base_get_chanmask(void *x); +t_object *pdp_base_get_object(void *x); + + +/* thread control */ +void pdp_base_disable_thread(void *x); + +/* type control */ +void pdp_base_set_type_template(void *x, int inlet, t_pdp_symbol *type_template); + +/* queue control */ +void pdp_base_queue_wait(void *x); +void pdp_base_set_queue(void *x, t_pdp_procqueue *q); +t_pdp_procqueue *pdp_base_get_queue(void *x); diff --git a/include/pdp_bitmap.h b/include/pdp_bitmap.h new file mode 100644 index 0000000..3fddc25 --- /dev/null +++ b/include/pdp_bitmap.h @@ -0,0 +1,96 @@ +/* + * Pure Data Packet system implementation. 8 bit image packet interface + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 file contains methods for the image packets + pdp_packet_new_* methods are several image packet constructors + + It also contains some pdp_type_ methods, for type checking + and conversion. + +*/ + +#ifndef PDP_BITMAP_H +#define PDP_BITMAP_H + + + +/* bitmap data packet */ +typedef struct _bitmap +{ + /* standard images */ + unsigned int encoding; /* image encoding (fourcc data format) */ + unsigned int width; /* image width in pixels */ + unsigned int height; /* image height in pixels */ + unsigned int bpp; /* bits per pixel (0 == standard) */ + +} t_bitmap; + + + +/* supported encodings (fourcc) */ + +/* special */ +#define PDP_BITMAP_RGB 0x32424752 +#define PDP_BITMAP_RGBA 0x41424752 +#define PDP_BITMAP_GREY 0x59455247 + +/* packet yuv */ +#define PDP_BITMAP_YUY2 0x32595559 +#define PDP_BITMAP_UYVY 0x59565955 + +/* planar yuv */ +#define PDP_BITMAP_I420 0x30323449 +#define PDP_BITMAP_YV12 0x32315659 + + +/* all symbols are C style */ +#ifdef __cplusplus +extern "C" +{ +#endif + + + +/* bitmap constructors*/ +int pdp_packet_new_bitmap_yv12(u32 width, u32 height); +int pdp_packet_new_bitmap_grey(u32 width, u32 height); +int pdp_packet_new_bitmap_rgb(u32 width, u32 height); +int pdp_packet_new_bitmap_rgba(u32 width, u32 height); +int pdp_packet_new_bitmap(int type, u32 width, u32 height); + +/* utility methids */ +void pdp_packet_bitmap_flip_top_bottom(int packet); + + +/* get description */ +t_pdp_symbol *pdp_packet_bitmap_get_description(int packet); + +/* get subheader */ +t_bitmap *pdp_packet_bitmap_info(int packet); + +bool pdp_packet_bitmap_isvalid(int packet); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/pdp_comm.h b/include/pdp_comm.h new file mode 100644 index 0000000..bd6cab8 --- /dev/null +++ b/include/pdp_comm.h @@ -0,0 +1,120 @@ +/* + * Pure Data Packet system implementation. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 file contains misc communication methods */ + +#ifndef PDP_COMM_H +#define PDP_COMM_H + +#include "pdp_symbol.h" +#include "pdp_list.h" + +/* all symbols are C style */ +#ifdef __cplusplus +extern "C" +{ +#endif + + + +/* pdp's pd symbols for communication + don't use these directly!! + use the macros instead, in case + this is proven to be too much of a hack.. */ + +extern t_symbol s_pdp; +extern t_symbol s_register_ro; +extern t_symbol s_register_rw; +extern t_symbol s_process; +extern t_symbol s_dpd; +extern t_symbol s_inspect; +extern t_symbol s_accumulate; +extern t_symbol s_chanmask; + + +#define S_PDP &s_pdp +#define S_REGISTER_RO &s_register_ro +#define S_REGISTER_RW &s_register_rw +#define S_PROCESS &s_process +#define S_DPD &s_dpd +#define S_INSPECT &s_inspect +#define S_ACCUMULATE &s_accumulate +#define S_CHANMASK &s_chanmask + + +/* utility methods */ + + + +/* if packet is valid, mark it unused and send it to an outlet */ +void pdp_packet_pass_if_valid(t_outlet *outlet, int *packet); + +/* if source packet is valid, release dest packet and move src->dest */ +void pdp_packet_replace_if_valid(int *dpacket, int *spacket); + +/* copy_ro if dest packet if invalid, else drop source + (don't copy) + send drop notif to pdp system + returns 1 if dropped, 0 if copied */ +int pdp_packet_copy_ro_or_drop(int *dpacket, int spacket); +int pdp_packet_convert_ro_or_drop(int *dpacket, int spacket, t_pdp_symbol *type_template); + +/* copy_rw if dest packit is invalid, else drop source + (don't copy) + send drop notif to pdp system + returns 1 if dropped, zero if copied */ +int pdp_packet_copy_rw_or_drop(int *dpacket, int spacket); +int pdp_packet_convert_rw_or_drop(int *dpacket, int spacket, t_pdp_symbol *type_template); + + +/* pd and pdp conversion stuff */ +void pd_atom_to_pdp_atom(t_atom *pdatom, t_pdp_atom *pdpatom); + + +/* send pdp lists and atoms */ +void outlet_pdp_atom(t_outlet *out, struct _pdp_atom *a); +void outlet_pdp_list(t_outlet *out, struct _pdp_list *l); + + + +/* send a packet to an outlet: it is only legal to call this on a "passing packet" + or a "read only packet". + this means it is illegal to change a packet after you have passed it to others, + since this would mess up all read only references to the packet. +*/ + +/* this seems like a nice place to hide a comment on the notion of read/write in pdp + which packets are writable? all packets with exactly 1 user. this includes all packets + aquired with pdp_packet_*_rw or a constructor, and all packets that are not registered + after being sent out by outlet_pdp. + which packets are readable? all packets */ + +void outlet_pdp(t_outlet *out, int packetid); + +/* send an accumulation (context) packet to an outlet. this is for usage in the dpd + base class. */ +void outlet_dpd(t_outlet *out, int packetid); + + +#ifdef __cplusplus +} +#endif + + + +#endif diff --git a/include/pdp_compat.h b/include/pdp_compat.h new file mode 100644 index 0000000..2bc948f --- /dev/null +++ b/include/pdp_compat.h @@ -0,0 +1,17 @@ + +/* + please don't use any of these. for backwards compatibility only +*/ + + +#ifndef PDP_COMPAT_H +#define PDP_COMPAT_H + + + + +void pdp_pass_if_valid(t_outlet *outlet, int *packet); +void pdp_replace_if_valid(int *dpacket, int *spacket); + + +#endif diff --git a/include/pdp_config.h b/include/pdp_config.h new file mode 100644 index 0000000..74274e2 --- /dev/null +++ b/include/pdp_config.h @@ -0,0 +1,89 @@ +/* include/pdp_config.h. Generated by configure. */ +/* include/pdp_config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the <inttypes.h> header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `gslcblas' library (-lgslcblas). */ +#define HAVE_LIBGSLCBLAS 1 + +/* Define to 1 if you have the `m' library (-lm). */ +#define HAVE_LIBM 1 + +/* Define to 1 if you have the <memory.h> header file. */ +#define HAVE_MEMORY_H 1 + +/* build pdp_glx */ +#define HAVE_PDP_GLX 1 + +/* gsl support */ +#define HAVE_PDP_GSL 1 + +/* build png support */ +#define HAVE_PDP_PNG 1 + +/* build pdp_qt */ +#define HAVE_PDP_QT 1 + +/* readline needed for console support */ +/* #undef HAVE_PDP_READLINE */ + +/* build pdp_sdl */ +/* #undef HAVE_PDP_SDL */ + +/* build pdp_v4l */ +/* #undef HAVE_PDP_V4L */ + +/* experimental vforth dsp engine */ +/* #undef HAVE_PDP_VFORTH */ + +/* build X11 support */ +#define HAVE_PDP_X 1 + +/* build pdp_xv */ +#define HAVE_PDP_XV 1 + +/* enable forced pwc v4l support */ +/* #undef HAVE_PWCV4L */ + +/* Define to 1 if you have the <stdint.h> header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "" + +/* "disable debugging support" */ +#define PDP_DEBUG 0 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 diff --git a/include/pdp_config.h.in b/include/pdp_config.h.in new file mode 100644 index 0000000..1ecfb3a --- /dev/null +++ b/include/pdp_config.h.in @@ -0,0 +1,88 @@ +/* include/pdp_config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `gslcblas' library (-lgslcblas). */ +#undef HAVE_LIBGSLCBLAS + +/* Define to 1 if you have the `m' library (-lm). */ +#undef HAVE_LIBM + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* build pdp_glx */ +#undef HAVE_PDP_GLX + +/* gsl support */ +#undef HAVE_PDP_GSL + +/* build png support */ +#undef HAVE_PDP_PNG + +/* build pdp_qt */ +#undef HAVE_PDP_QT + +/* readline needed for console support */ +#undef HAVE_PDP_READLINE + +/* build pdp_sdl */ +#undef HAVE_PDP_SDL + +/* build pdp_v4l */ +#undef HAVE_PDP_V4L + +/* experimental vforth dsp engine */ +#undef HAVE_PDP_VFORTH + +/* build X11 support */ +#undef HAVE_PDP_X + +/* build pdp_xv */ +#undef HAVE_PDP_XV + +/* enable forced pwc v4l support */ +#undef HAVE_PWCV4L + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* "disable debugging support" */ +#undef PDP_DEBUG + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS diff --git a/include/pdp_control.h b/include/pdp_control.h new file mode 100644 index 0000000..c23dc1f --- /dev/null +++ b/include/pdp_control.h @@ -0,0 +1,12 @@ +#ifndef __PDP_CONTROL_H__ +#define __PDP_CONTROL_H__ + +#include "pdp_pd.h" + +struct _pdp_control; +typedef void (t_pdp_control_method_notify)(struct _pdp_control *x); + +void pdp_control_notify_broadcast(t_pdp_control_method_notify *notify); +void pdp_control_addmethod(t_method m, t_symbol *s); + +#endif diff --git a/include/pdp_debug.h b/include/pdp_debug.h new file mode 100644 index 0000000..a5e48fc --- /dev/null +++ b/include/pdp_debug.h @@ -0,0 +1,16 @@ +#ifndef __PDP_DEBUG_H_ +#define __PDP_DEBUG_H_ + +#include "pdp_config.h" // needed for PDP_DEBUG define + +void pdp_assert_hook (char *condition, char *file, int line); + + + +#if PDP_DEBUG +#define PDP_ASSERT(x) if (!(x)) {pdp_assert_hook(#x, __FILE__, __LINE__);} +#else +#define PDP_ASSERT(x) +#endif + +#endif //__PDP_DEBUG_H_ diff --git a/include/pdp_dpd_base.h b/include/pdp_dpd_base.h new file mode 100644 index 0000000..0d20e29 --- /dev/null +++ b/include/pdp_dpd_base.h @@ -0,0 +1,141 @@ +/* + * Pure Data Packet header file. DPD base class + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +/* dpd base class for context based processors (for pd-fying standard stack based serial languages) + not all of pdp is used here, but the class is derived from the pdp base class to enable mixing + standard pdp (data flow packet processing) and dpd (context based serial languages) + + dpd is short for "upside down pdp". the name stems from the observation + of opengl code in pd (like in gem) having an upside down feel when looking + through dataflow eyes. i.e.: the target (window context) is on top, while + the objects (geos) are at the bottom connected by a chain of geometric transforms + + the principles of dpd are simple: + + * there is only one main packet, received on the left inlet. + * this packet is called the "context" and is produced by and returned to a top context source/sink + * additional pd messages and pdp packets can be received on the cold inlets + * as opposed to pdp, no copies are made of this context packet, all operations on it are accumulative. + * the protocol is different because fanout is prohibited (so no ro/rw registering) + * the only exception for fanout are inspectors, which have precedence over normal processors + * all processors and inspectors for a single context type must use the pdp thread, to preserve execution order + + +*/ + + + +#include "pdp_base.h" + +#define PDP_DPD_MAX_CONTEXT_OUTLETS 4 + +typedef struct pdp_dpd_base_struct +{ + t_pdp_base b_base; /* pdp base class */ + + int b_nb_context_outlets; + t_outlet *b_context_outlet[PDP_DPD_MAX_CONTEXT_OUTLETS]; /* dpd outlets */ + int b_outlet_enable[PDP_DPD_MAX_CONTEXT_OUTLETS]; /* dpd outlets */ + t_pdp_method b_accum_method[PDP_DPD_MAX_CONTEXT_OUTLETS]; /* accumulation methods for each outlet */ + t_pdp_method b_accum_callback[PDP_DPD_MAX_CONTEXT_OUTLETS]; /* pd callback methods for each outlet */ + //int b_accum_queue_id[PDP_DPD_MAX_CONTEXT_OUTLETS]; /* accumulator queue id's */ + + t_pdp_method b_inspector_method; /* pdp thread inspector callback */ + t_pdp_method b_inspector_callback; /* main thread inspector callback */ + //int b_inspector_queue_id; + + t_pdp_method b_cleanup_method; /* queued after propagation is done */ + t_pdp_method b_cleanup_callback; /* queued after propagation is done */ + //int b_cleanup_queue_id; + + t_pdp_method b_complete_notify; /* method called after packet output is done */ + t_pdp_newmethod b_command_factory_method; /* command factory method */ + + + int b_context_packet; /* the current context packet */ + + int b_dpd_active_inlet_disabled; + + +} t_pdp_dpd_base; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* bang method (propagate context to outlets & register callbacks) + mainly for context source/sinks + it is not registered as a pd message by default ! */ +void pdp_dpd_base_bang(void *x); + +/* get/set the context packet */ +int pdp_dpd_base_get_context_packet(void *x); +void pdp_dpd_base_set_context_packet(void *x, int p); +int pdp_dpd_base_move_context_packet(void *x); + +/* add a context outlet and it's corresponding accumulation (process) and callback method */ +t_outlet *pdp_dpd_base_add_outlet(void *x, t_pdp_method accum_method, t_pdp_method accum_callback); + +/* add a cleanup callback (called after all propagation is finished) for sources/sinks */ +void pdp_dpd_base_add_cleanup(void *x, t_pdp_method cleanup_method, t_pdp_method accum_callback); + +/* add an inspector callback */ +void pdp_dpd_base_add_inspector(void *x, t_pdp_method inspector_method); + + +/* destructor */ +void pdp_dpd_base_free(void *x); + +/* init method */ +void pdp_dpd_base_init(void *x); + +/* disable dpd active inlet */ +void pdp_dpd_base_disable_active_inlet(void *x); + +/* enable/disable outlet */ +void pdp_dpd_base_enable_outlet(void *x, int outlet, int toggle); + +/* register notify method (called from the end of pdp_dpd_base_bang) */ +void pdp_dpd_base_register_complete_notify(void *x, t_pdp_method method); + +/* register a command init (factory) method + this method should return a command object to place in the queue */ +void pdp_dpd_base_register_command_factory_method(void *x, t_pdp_newmethod command_factory_method); + +/* class setup method */ +void pdp_dpd_base_setup(t_class *class); + +/* add a command to the process queue */ +void pdp_dpd_base_queue_command(void *x, void *c, t_pdp_method process, + t_pdp_method callback, int *id); + + +/* get/set the queue instance (thread) used for scheduling */ +#define pdp_dpd_base_set_queue pdp_base_set_queue +#define pdp_dpd_base_get_queue pdp_base_get_queue +#define pdp_dpd_base_queue_wait pdp_base_queue_wait + + + +#ifdef __cplusplus +} +#endif diff --git a/include/pdp_dpd_command.h b/include/pdp_dpd_command.h new file mode 100644 index 0000000..1cfcf8a --- /dev/null +++ b/include/pdp_dpd_command.h @@ -0,0 +1,79 @@ + +/* + * Pure Data Packet header file. DPD command class + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 implements a dpd command 'factory and recycling center' */ + +/* a small note on commands & dpd + + dpd uses a different synchronization model than pdp. + + in pdp, objects only pass once the process method in the process thread + has finished. + + in dpd a context packet propagates a context trough an tree of objects, + depth first, following the pd messages. it is possible to send a list of + contexts trough a tree before the actual processing starts. therefore, + each time a context passes trough an object, a new command object (or memento) + needs to be created that saves the state of the rendering context. the command + factory class can be used to create these commands. + + the dpd base class queues a command object and calls the registered method + on the object instead of the dpd object. so a command object is in fact + a delegate of the dpd object in question. + +*/ + + +#ifndef PDP_DPD_COMMAND +#define PDP_DPD_COMMAND + +#include "pdp_types.h" + + +/* COMMAND BASE CLASS */ +typedef struct _pdp_dpd_command +{ + struct _pdp_dpd_command *next; + u32 used; + +} t_pdp_dpd_command; + + +/* COMMAND LIST (COMMAND FACTORY) CLASS */ +typedef struct _pdp_dpd_commandfactory +{ + u32 nb_commands; + u32 command_size; + t_pdp_dpd_command *command; +} t_pdp_dpd_commandfactory; + + +/* COMMAND LIST METHODS */ +void pdp_dpd_commandfactory_init(t_pdp_dpd_commandfactory *x, u32 size); +void pdp_dpd_commandfactory_free(t_pdp_dpd_commandfactory *x); +t_pdp_dpd_command *pdp_dpd_commandfactory_get_new_command(t_pdp_dpd_commandfactory *x); + + +/* COMMAND METHODS */ +void pdp_dpd_command_suicide(void *); + + +#endif diff --git a/include/pdp_image.h b/include/pdp_image.h new file mode 100644 index 0000000..3dabfb1 --- /dev/null +++ b/include/pdp_image.h @@ -0,0 +1,95 @@ +/* + * Pure Data Packet system implementation. Image packet interface + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 file contains methods for the image packets + pdp_packet_new_* methods are several image packet constructors + + It also contains some pdp_type_ methods, for type checking + and conversion. + +*/ + +#ifndef PDP_IMAGE_H +#define PDP_IMAGE_H + +#include "pdp_symbol.h" +#include "pdp_types.h" + +/* image subheader */ +typedef struct _image +{ + /* standard images */ + unsigned int encoding; /* image encoding (data format) */ + unsigned int width; /* image width in pixels */ + unsigned int height; /* image height in pixels */ + unsigned int depth; /* number of colour planes if PDP_IMAGE_MCHP */ + unsigned int chanmask; /* channel bitmask to mask out inactive channels (0 == not used) */ + +} t_image; + + +/* image encodings */ +#define PDP_IMAGE_YV12 1 /* 24bbp: 16 bit Y plane followed by 16 bit 2x2 subsampled V and U planes.*/ +#define PDP_IMAGE_GREY 2 /* 16bbp: 16 bit Y plane */ +#define PDP_IMAGE_MCHP 4 /* generic 16bit multi channel planar (16 bit 3D tensor) */ + +/* slice synchro information */ +#define PDP_IMAGE_SLICE_FIRST (1<<0) +#define PDP_IMAGE_SLICE_LAST (1<<1) +#define PDP_IMAGE_SLICE_BODY (1<<2) + + + +/* all symbols are C style */ +#ifdef __cplusplus +extern "C" +{ +#endif + + + + +/* validate and compat check */ +bool pdp_packet_image_isvalid(int packet); +bool pdp_packet_image_compat(int packet0, int packet1); + +/* short cuts to create specific packets */ +int pdp_packet_new_image(u32 encoding, u32 width, u32 height); +int pdp_packet_new_image_YCrCb(u32 width, u32 height); +int pdp_packet_new_image_grey(u32 width, u32 height); +int pdp_packet_new_image_mchp(u32 width, u32 height, u32 depth); + +#define pdp_packet_new_image_multi pdp_packet_new_image_mchp + +/* get info */ +t_pdp_symbol *pdp_packet_image_get_description(int packet); +t_image *pdp_packet_image_info(int packet); + +/* set props */ +void pdp_packet_image_set_chanmask(int packet, unsigned int chanmask); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/pdp_imagebase.h b/include/pdp_imagebase.h new file mode 100644 index 0000000..6d6b902 --- /dev/null +++ b/include/pdp_imagebase.h @@ -0,0 +1,51 @@ +/* + * Pure Data Packet image processor base class header file. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 file contains the specification of the pdp base class. It is derived + from t_object, the basic pd object (like any other pd extern). Have a look + at pdp_add, pdp_gain and pdp_noise to see how to use this. + +*/ + + +#include "pdp_base.h" + + +typedef struct +{ + t_pdp_base x_obj; + u32 b_channel_mask; // channel mask + +} t_pdp_imagebase; + + + +/* setup base class. call this in your derived class setup method */ +void pdp_imagebase_setup(t_class *c); + + +/* base class constructor/destructor. call this in your base class constructor/destructor */ +void pdp_imagebase_init(void *x); +void pdp_imagebase_free(void *x); + +/* getters for image base class data */ +u32 pdp_imagebase_get_chanmask(void *x); diff --git a/include/pdp_imageproc.h b/include/pdp_imageproc.h new file mode 100644 index 0000000..8cc0baa --- /dev/null +++ b/include/pdp_imageproc.h @@ -0,0 +1,226 @@ + +/* + * Pure Data Packet. Header file for image processing routines (used in modules). + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 is a c wrapper around platform specific (mmx) code */ + +#include "pdp_types.h" + +#ifndef PDP_IMAGEPROC_H +#define PDP_IMAGEPROC_H + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* the basic allocation unit, for stack alignment */ +typedef long long t_pdp_imageproc_stackword; + +/* convert byte size to nb of stack words */ +#define PDP_IMAGEPROC_NB_STACKWORDS(x) (((x-1)/sizeof(t_pdp_imageproc_stackword))+1) + + +/* the packet types should be the same for the dispatchers. packet0 is the dominant packet */ + +/* image processing dispatchers */ +void pdp_imageproc_dispatch_1buf(void (*process_routine)(void*, u32, u32, s16*), void *x, u32 chanmask, int packet0); +void pdp_imageproc_dispatch_2buf(void (*process_routine)(void*, u32, u32, s16*, s16 *), void *x, u32 chanmask, int packet0, int packet1); +void pdp_imageproc_dispatch_3buf(void (*process_routine)(void*, u32, u32, s16*, s16 *, s16*), void *x, u32 chanmask, int packet0, int packet1, int packet2); + + + + +/* get legal image dimensions */ +/* this is a fix for the dimension problem */ +/* some imageproc implementations require the dims to be a multiple of some square */ +u32 pdp_imageproc_legalwidth(int i); +u32 pdp_imageproc_legalheight(int i); +u32 pdp_imageproc_legalwidth_round_down(int i); +u32 pdp_imageproc_legalheight_round_down(int i); + + + +/****************************** 16 bit signed (pixel) routines ***************************************/ + + +// mix 2 images +void *pdp_imageproc_mix_new(void); +int pdp_imageproc_mix_nb_stackwords(void); +void pdp_imageproc_mix_delete(void *x); +void pdp_imageproc_mix_setleftgain(void *x, float gain); +void pdp_imageproc_mix_setrightgain(void *x, float gain); +void pdp_imageproc_mix_process(void *x, u32 width, u32 height, s16 *image, s16 *image2); + +// random mix 2 images +// note: random number generator can be platform specific +// however, it should be seeded. (same seed produces the same result) +// threshold = 0 -> left image +// threshold = 1 -> right image + +void *pdp_imageproc_randmix_new(void); +int pdp_imageproc_randmix_nb_stackwords(void); +void pdp_imageproc_randmix_delete(void *x); +void pdp_imageproc_randmix_setthreshold(void *x, float threshold); +void pdp_imageproc_randmix_setseed(void *x, float seed); +void pdp_imageproc_randmix_process(void *x, u32 width, u32 height, s16 *image, s16 *image2); + + +// produce a random image +// note: random number generator can be platform specific +// however, it should be seeded. (same seed produces the same result) +void *pdp_imageproc_random_new(void); +void pdp_imageproc_random_delete(void *x); +void pdp_imageproc_random_setseed(void *x, float seed); +void pdp_imageproc_random_process(void *x, u32 width, u32 height, s16 *image); + + +// produce a plasma image +// note: random number generator can be platform specific +// however, it should be seeded. (same seed produces the same result) +void *pdp_imageproc_plasma_new(void); +void pdp_imageproc_plasma_delete(void *x); +void pdp_imageproc_plasma_setseed(void *x, float seed); +void pdp_imageproc_plasma_setturbulence(void *x, float seed); +void pdp_imageproc_plasma_process(void *x, u32 width, u32 height, s16 *image); + + +// apply a gain to an image +void *pdp_imageproc_gain_new(void); +void pdp_imageproc_gain_delete(void *x); +void pdp_imageproc_gain_setgain(void *x, float gain); +void pdp_imageproc_gain_process(void *x, u32 width, u32 height, s16 *image); + + + +// add two images +void pdp_imageproc_add_process(void *x, u32 width, u32 height, s16 *image, s16 *image2); + +// mul two images +void pdp_imageproc_mul_process(void *x, u32 width, u32 height, s16 *image, s16 *image2); + + +// 3x1 or 1x3 in place convolution +// orientation +#define PDP_IMAGEPROC_CONV_HORIZONTAL 0 +#define PDP_IMAGEPROC_CONV_VERTICAL 1 +void *pdp_imageproc_conv_new(void); +void pdp_imageproc_conv_delete(void *x); +void pdp_imageproc_conv_setmin1(void *x, float val); +void pdp_imageproc_conv_setzero(void *x, float val); +void pdp_imageproc_conv_setplus1(void *x, float val); +void pdp_imageproc_conv_setbordercolor(void *x, float intensity); +void pdp_imageproc_conv_setorientation(void *x, u32 val); +void pdp_imageproc_conv_setnbpasses(void *x, u32 val); +void pdp_imageproc_conv_process(void *x, u32 width, u32 height, s16 *image); + + +// colour rotation for 2 colour planes ($$$TODO: change interface) +// matrix is column encoded +void *pdp_imageproc_crot2d_new(void); +void pdp_imageproc_crot2d_delete(void *x); +void pdp_imageproc_crot2d_setmatrix(void *x, float *matrix); +void pdp_imageproc_crot2d_process(void *x, s16 *image, u32 width, u32 height); + +// colour rotation for 3 colour planes ($$$TODO: change interface) +void *pdp_imageproc_crot3d_new(void); +void pdp_imageproc_crot3d_delete(void *x); +void pdp_imageproc_crot3d_setmatrix(void *x, float *matrix); +void pdp_imageproc_crot3d_process(void *x, s16 *image, u32 width, u32 height); + + + + +// biquad space + +// directions +#define PDP_IMAGEPROC_BIQUAD_TOP2BOTTOM (1<<0) +#define PDP_IMAGEPROC_BIQUAD_BOTTOM2TOP (1<<1) +#define PDP_IMAGEPROC_BIQUAD_LEFT2RIGHT (1<<2) +#define PDP_IMAGEPROC_BIQUAD_RIGHT2LEFT (1<<3) +void *pdp_imageproc_bq_new(void); +void pdp_imageproc_bq_delete(void *x); +void pdp_imageproc_bq_setcoef(void *x, float *coef); // a0,a1,a2,b0,b1,b2 +void pdp_imageproc_bq_setnbpasses(void *x, u32 nbpasses); +void pdp_imageproc_bq_setdirection(void *x, u32 direction); +void pdp_imageproc_bq_process(void *x, u32 width, u32 height, s16* image); + + +// biquad time +//void *pdp_imageproc_bqt_new(void); +//void pdp_imageproc_bqt_delete(void *x); +//void pdp_imageproc_bqt_setcoef(void *x, float *coef); // a0,a1,a2,b0,b1,b2 +void pdp_imageproc_bqt_process(void *x, u32 width, u32 height, s16 *image, s16 *state0, s16 *state1); + + + +// zoom object +void *pdp_imageproc_resample_affinemap_new(void); +void pdp_imageproc_resample_affinemap_delete(void *x); +void pdp_imageproc_resample_affinemap_setcenterx(void *x, float f); +void pdp_imageproc_resample_affinemap_setcentery(void *x, float f); +void pdp_imageproc_resample_affinemap_setzoomx(void *x, float f); +void pdp_imageproc_resample_affinemap_setzoomy(void *x, float f); +void pdp_imageproc_resample_affinemap_setangle(void *x, float f); +void pdp_imageproc_resample_affinemap_process(void *x, u32 width, u32 height, s16 *srcimage, s16 *dstimage); + + + +//chebyshev poly +void *pdp_imageproc_cheby_new(int order); +void pdp_imageproc_cheby_delete(void *x); +void pdp_imageproc_cheby_setcoef(void *x, u32 n, float f); +void pdp_imageproc_cheby_setnbpasses(void *x, u32 n); +void pdp_imageproc_cheby_process(void *x, u32 width, u32 height, s16 *image); + + +//logic ops +void pdp_imageproc_xor_process(void *x, u32 width, u32 height, s16 *image, s16 *image2); +void pdp_imageproc_or_process(void *x, u32 width, u32 height, s16 *image, s16 *image2); +void pdp_imageproc_and_process(void *x, u32 width, u32 height, s16 *image, s16 *image2); +void pdp_imageproc_mask_process(void *x, u32 width, u32 height, s16 *image); +void pdp_imageproc_not_process(void *x, u32 width, u32 height, s16 *image); +void pdp_imageproc_hardthresh_process(void *x, u32 width, u32 height, s16 *image); +void pdp_imageproc_softthresh_process(void *x, u32 width, u32 height, s16 *image); + + +//other stateles operators +void pdp_imageproc_abs_process(void *x, u32 width, u32 height, s16 *image); +void pdp_imageproc_zthresh_process(void *x, u32 width, u32 height, s16 *image); +void pdp_imageproc_plasma_process(void *x, u32 width, u32 height, s16 *image); +void pdp_imageproc_ispositive_process(void *x, u32 width, u32 height, s16 *image); +void pdp_imageproc_sign_process(void *x, u32 width, u32 height, s16 *image); +void pdp_imageproc_flip_lr_process(void *dummy, u32 width, u32 height, s16 *image); +void pdp_imageproc_flip_tb_process(void *dummy, u32 width, u32 height, s16 *image); + +//set to zero +void pdp_imageproc_zero_process(void *x, u32 width, u32 height, s16 *image); +void pdp_imageproc_constant_process(void *x, u32 width, u32 height, s16 *image); + + + +#ifdef __cplusplus +} +#endif + + + +#endif //PDP_IMAGEPROC_H diff --git a/include/pdp_internals.h b/include/pdp_internals.h new file mode 100644 index 0000000..924d5eb --- /dev/null +++ b/include/pdp_internals.h @@ -0,0 +1,59 @@ + +/* + * Pure Data Packet internal header file. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 file contains prototypes for "private" pdp methods. + DON'T CALL THESE FROM OUTSIDE OF PDP! unless you really + know what you are doing. + */ + + + +#ifndef PDP_INTERNALS_H +#define PDP_INTERNALS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* INTERNAL SYSTEM METHODS */ + +/* set/unset main pdp thread usage */ +void pdp_queue_use_thread(int t); + + +/* INTERNAL PACKET METHODS */ + +/* create a new packet, reuse if possible. + ONLY USE THIS IN A TYPE SPECIFIC CONSTRUCTOR! */ +int pdp_packet_new(unsigned int datatype, unsigned int datasize); + + + + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/include/pdp_list.h b/include/pdp_list.h new file mode 100644 index 0000000..2f7b8f5 --- /dev/null +++ b/include/pdp_list.h @@ -0,0 +1,240 @@ + +/* + * Pure Data Packet header file. List class + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +/* the pdp list is composed of atoms. + the default atom is a pointer. + lists can be recursed into trees. + + note: all functions that return t_pdp_word and don't take a type argument + obviously don't perform any type checking. if you have heterogenous lists, + you should use atom iterators or direct access. + + functions starting with "pdp_tree" recurse through sublists. + functions starting with "pdp_list" stay at the top level. + +*/ + + + +#ifndef PDP_LIST_H +#define PDP_LIST_H + +struct _pdp_list; +struct _pdp_atom; + +/* THE LIST OBJECT */ + +typedef enum { + /* generic atoms */ + a_undef = 0, + a_pointer, + a_float, + a_int, + a_symbol, + a_packet, + a_list, + a_atom_pointer, + + /* forth atoms */ + a_forthword, /* forth word operating on a stack */ + a_vmword, /* forth word operating on a virtual machine */ + a_vmmacro /* forth word operating on vm, manipilating current def */ +} t_pdp_word_type; + +typedef union _pdp_word +{ + void* w_pointer; + float w_float; + int w_int; + struct _pdp_symbol* w_symbol; + int w_packet; + struct _pdp_list* w_list; + struct _pdp_atom* w_atom_pointer; + +} t_pdp_word; + +/* a list element */ +typedef struct _pdp_atom +{ + struct _pdp_atom *next; + t_pdp_word w; + t_pdp_word_type t; +} t_pdp_atom; + +/* a list container */ +typedef struct _pdp_list +{ + int elements; + t_pdp_atom *first; + t_pdp_atom *last; + +} t_pdp_list; + + +/* CONVENTION: trees stacks and lists. + + * all operations with "list" in them operate on flat lists. all the + items contained in the list are either pure atoms (floats, ints, or symbols) + or references (packets, pointers, lists) + + * all operations with "tree" in them, operate on recursive lists (trees) + all sublists of the list (tree) are owned by the parent list, so you can't + build trees from references to other lists. + + * stacks are trees (the forth can have tree's on a stack, or have recursive stacks) + (WAS: stacks are by definition flat lists, so they can not contains sublists) + +*/ + +typedef void (*t_pdp_atom_method)(t_pdp_atom *); +typedef void (*t_pdp_word_method)(t_pdp_word); +typedef void (*t_pdp_pword_method)(t_pdp_word *); +typedef void (*t_pdp_free_method)(void *); + +/* creation / destruction */ +t_pdp_atom* pdp_atom_new (void); +void pdp_atom_free (t_pdp_atom *); +t_pdp_list* pdp_list_new (int elements); +void pdp_list_free (t_pdp_list *l); +void pdp_list_clear (t_pdp_list *l); +void pdp_tree_free (t_pdp_list *l); +void pdp_tree_clear (t_pdp_list *l); + + + +/* call a free method on all pointers in a tree */ +void pdp_tree_strip_pointers (t_pdp_list *l, t_pdp_free_method f); + +/* strip all packets from a tree. i.e. call pdp_packet_mark_unused on them */ +void pdp_tree_strip_packets (t_pdp_list *l); + +/* copy a tree, and copy all packets readonly */ +t_pdp_list *pdp_tree_copy_ro(t_pdp_list *l); + +t_pdp_list* pdp_tree_from_cstring(char *chardef, char **nextchar); + +/* check type syntax of list */ +int pdp_tree_check_syntax(t_pdp_list *list, t_pdp_list *syntax); +t_pdp_atom *pdp_atom_from_cstring(char *chardef, char **nextchar); +//void pdp_atom_from_cstring(t_pdp_atom *a, char *string); + + +/* traversal routines (map functions) */ +/* use these in conjunction with gcc local functions + if there's ever a portability problem: add a void* data argument to implement closures */ +void pdp_list_apply (t_pdp_list *l, t_pdp_atom_method am); +void pdp_tree_apply (t_pdp_list *l, t_pdp_atom_method am); +void pdp_list_apply_word_method (t_pdp_list *l, t_pdp_word_type t, t_pdp_word_method wm); +void pdp_tree_apply_word_method (t_pdp_list *l, t_pdp_word_type t, t_pdp_word_method wm); +void pdp_list_apply_pword_method (t_pdp_list *l, t_pdp_word_type t, t_pdp_pword_method pwm); +void pdp_tree_apply_pword_method (t_pdp_list *l, t_pdp_word_type t, t_pdp_pword_method pwm); + + +/* copy: (reverse) copies a list. */ +/* list copy is flat. pointers and packets are copied. so you need to + ensure reference consistency yourself. */ + +t_pdp_list* pdp_list_copy (t_pdp_list *l); +t_pdp_list* pdp_list_copy_reverse (t_pdp_list *l); +t_pdp_list* pdp_tree_copy (t_pdp_list *l); +t_pdp_list* pdp_tree_copy_reverse (t_pdp_list *l); + + +/* cat: this makes a copy of the second list and adds it at the end of the first one */ +void pdp_list_cat (t_pdp_list *l, t_pdp_list *tail); + +/* information */ +int pdp_list_contains (t_pdp_list *l, t_pdp_word_type t, t_pdp_word w); +int pdp_list_size (t_pdp_list *l); +void pdp_list_print (t_pdp_list *l); +void pdp_atom_print (t_pdp_atom *a); + +/* access */ +void pdp_list_add (t_pdp_list *l, t_pdp_word_type t, t_pdp_word w); +void pdp_list_add_back (t_pdp_list *l, t_pdp_word_type t, t_pdp_word w); +void pdp_list_add_to_set (t_pdp_list *l, t_pdp_word_type t, t_pdp_word w); +void pdp_list_remove (t_pdp_list *l, t_pdp_word_type t, t_pdp_word w); + +void pdp_list_add_atom(t_pdp_list *l, t_pdp_atom *a); +void pdp_list_add_back_atom(t_pdp_list *l, t_pdp_atom *a); + +/* these don't do error checking. out of bound == error */ +t_pdp_atom *pdp_list_pop_atom (t_pdp_list *l); +t_pdp_word pdp_list_pop (t_pdp_list *l); +t_pdp_word pdp_list_index (t_pdp_list *l, int index); +void pdp_list_pop_push (t_pdp_list *source, t_pdp_list *dest); + +/* some aliases */ +#define pdp_list_add_front pdp_list_add +#define pdp_list_push pdp_list_add +#define pdp_list_queue pdp_list_add_end +#define pdp_list_unqueue pdp_list_pop + +/* util */ +void pdp_list_reverse(t_pdp_list *l); + +/* generic atom iterator */ +#define PDP_ATOM_IN(list,atom) for (atom = list->first ; atom ; atom = atom->next) + +/* fast single type iterators */ + +/* generic */ +#define PDP_WORD_IN(list, atom, word, type) for (atom=list->first ;atom && ((word = atom -> w . type) || 1); atom=atom->next) + +/* type specific */ +#define PDP_POINTER_IN(list, atom, x) PDP_WORD_IN(list, atom, x, w_pointer) +#define PDP_INT_IN(list, atom, x) PDP_WORD_IN(list, atom, x, w_int) +#define PDP_FLOAT_IN(list, atom, x) PDP_WORD_IN(list, atom, x, w_float) +#define PDP_SYMBOL_IN(list, atom, x) PDP_WORD_IN(list, atom, x, w_symbol) +#define PDP_PACKET_IN(list, atom, x) PDP_WORD_IN(list, atom, x, w_packet) +#define PDP_LIST_IN(list, atom, x) PDP_WORD_IN(list, atom, x, w_list) + + +/* some macros for the pointer type */ + +#define pdp_list_add_pointer(l,p) pdp_list_add(l, a_pointer, ((t_pdp_word)((void *)(p)))) +#define pdp_list_add_back_pointer(l,p) pdp_list_add_back(l, a_pointer, ((t_pdp_word)((void *)(p)))) +#define pdp_list_add_pointer_to_set(l,p) pdp_list_add_to_set(l, a_pointer, ((t_pdp_word)((void *)(p)))) +#define pdp_list_remove_pointer(l,p) pdp_list_remove(l, a_pointer, ((t_pdp_word)((void *)(p)))) +#define pdp_list_contains_pointer(l,p) pdp_list_contains(l, a_pointer, ((t_pdp_word)((void *)(p)))) + +/* atom access */ +#define PDP_LIST_ATOM_0(x) ((x)->first) +#define PDP_LIST_ATOM_1(x) ((x)->first->next) +#define PDP_LIST_ATOM_2(x) ((x)->first->next->next) +#define PDP_LIST_ATOM_3(x) ((x)->first->next->next->next) +#define PDP_LIST_ATOM_4(x) ((x)->first->next->next->next->next) + +/* array like setters */ +static inline void pdp_atom_set(t_pdp_atom *a, t_pdp_word_type t, t_pdp_word w) {a->t = t; a->w = w;} +static inline void pdp_list_set_0(t_pdp_list *l, t_pdp_word_type t, t_pdp_word w) {pdp_atom_set(l->first, t, w);} +static inline void pdp_list_set_1(t_pdp_list *l, t_pdp_word_type t, t_pdp_word w) {pdp_atom_set(l->first->next, t, w);} +static inline void pdp_list_set_2(t_pdp_list *l, t_pdp_word_type t, t_pdp_word w) {pdp_atom_set(l->first->next->next, t, w);} + + +/* evaluator (tiny lisp) */ + + + +typedef t_pdp_list* (*t_pdp_list_evaluator_function)(t_pdp_list *); + + +#endif diff --git a/include/pdp_list_macros.h b/include/pdp_list_macros.h new file mode 100644 index 0000000..cb1f49f --- /dev/null +++ b/include/pdp_list_macros.h @@ -0,0 +1,27 @@ +#ifndef __PDP_LIST_MACROS__ +#define __PDP_LIST_MACROS__ + +/* some additional (short named) list macros mainly for manipulationg + argument lists. needs to be included locally. */ + +/* reading a list */ +#define FIRST(l) ((l)->first) +#define SIZE(l) ((l)->elements) + +#define NEXT(a) ((a)->next) +#define N(a) (a = a->next) + +#define FLOAT(a) ((a)->t == a_float ? (a)->w.w_float : 0.0f) +#define PACKET(a) ((a)->t == a_packet ? (a)->w.w_packet : -1) +#define INT(a) ((a)->t == a_int ? (a)->w.w_packet : 0) + + +/* creating a list, and adding stuff to the end (queueing) */ +#define LIST(n) pdp_list_new(n) +#define LFREE(l) pdp_list_free(l) +#define QFLOAT(l, x) pdp_list_add_back(l, a_float, ((t_pdp_word)(float)(x))) +#define QINT(l, x) pdp_list_add_back(l, a_int, ((t_pdp_word)(int)(x))) +#define QPACKET(l, x) pdp_list_add_back(l, a_packet,((t_pdp_word)(int)(x))) + + +#endif diff --git a/include/pdp_llconv.h b/include/pdp_llconv.h new file mode 100644 index 0000000..5e22d3a --- /dev/null +++ b/include/pdp_llconv.h @@ -0,0 +1,81 @@ +/* + * Pure Data Packet system implementation. : low level format conversion code + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 file contains low level conversion code + it is a wrapper around some machine code routines padded + with some extra c code */ + +/* don't rely too much on the calling conventions here + this is mainly to tuck away "ugly" parts of the code + that come up in several places */ + +#ifndef PDP_LLCONV_H +#define PDP_LLCONV_H + + +/* all symbols are C style */ +#ifdef __cplusplus +extern "C" +{ +#endif + + + +/* raw image formats (RIF) descriptions used for low level conversion routines + format: RIF_[component names and order]_[data arganization]_[data type] + + component names: R(red), G(green), B(blue), Y(chroma), V(chroma red), U(chroma blue) + component type: [S/U][nb bits] ex: S16, U8 + data organization: [P/P[samplefrequency]] ex: P(packed) P411(planar, 2nd and 3rd 2x2 subsampled) + + +*/ + +enum RIF { + RIF_YVU__P411_U8, + RIF_YUV__P411_U8, + RIF_YVU__P411_S16, + RIF_YVU__P444_S16, + RIF_YUYV_P____U8, + RIF_RGB__P____U8, + RIF_RGBA_P____U8, + RIF_RGB__P444_S16, + RIF_GREY______S16, + RIF_GREY______U8, + RIF_BGR__P____U8, + RIF_BGRA_P____U8 + +}; + +/* pdp_llconv is NOT thread safe !*/ +/* gain = 1.0 means maximal */ +/* low level convert 2 images */ +void pdp_llconv(void *src, int stype, void *dest, int dtype, int w, int h); + + + + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/include/pdp_matrix.h b/include/pdp_matrix.h new file mode 100644 index 0000000..22a33bb --- /dev/null +++ b/include/pdp_matrix.h @@ -0,0 +1,94 @@ +/* + * Pure Data Packet system implementation. matrix packet interface + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +#ifndef PDP_MATRIX_H +#define PDP_MATRIX_H + +#include <stdio.h> +#include <gsl/gsl_block.h> +#include <gsl/gsl_vector.h> +#include <gsl/gsl_matrix.h> +#include <gsl/gsl_blas.h> +#include <gsl/gsl_linalg.h> + +#include "pdp_types.h" + +#define gsl_rows size1 +#define gsl_columns size2 + +typedef struct _matrix +{ + /* meta data */ + u32 type; /* float/double real/complex */ + u32 rows; + u32 columns; + + /* gsl structures: these will be cast to the correct type on use */ + gsl_block block; /* gsl block meta data */ + gsl_vector vector; /* gsl vector meta data */ + gsl_matrix matrix; /* gsl matrix meta data */ + gsl_permutation perm; /* permutation data for storing an LU decomposition */ + int signum; /* sign of permutation matrix */ + + +} t_matrix; + +#define PDP_MATRIX 7 + +#define PDP_MATRIX_TYPE_RFLOAT 1 +#define PDP_MATRIX_TYPE_CFLOAT 2 +#define PDP_MATRIX_TYPE_RDOUBLE 3 +#define PDP_MATRIX_TYPE_CDOUBLE 4 + +int pdp_packet_matrix_isvalid(int p); +int pdp_packet_matrix_isvector(int p); +int pdp_packet_matrix_ismatrix(int p); + +int pdp_packet_new_matrix(u32 rows, u32 columns, u32 type); +int pdp_packet_new_matrix_product_result(CBLAS_TRANSPOSE_t TransA, CBLAS_TRANSPOSE_t TransB, int pA, int pB); +void pdp_packet_matrix_setzero(int p); + + +/* getters: returns 0 if type is incorrect */ +void *pdp_packet_matrix_get_gsl_matrix(int p, u32 type); +void *pdp_packet_matrix_get_gsl_vector(int p, u32 type); +int pdp_packet_matrix_get_type(int p); + + +/* type transparent matrix operations */ + +/* blas wrappers */ + +/* C += scale op(A) op(B) */ +int pdp_packet_matrix_blas_mm(CBLAS_TRANSPOSE_t TransA, CBLAS_TRANSPOSE_t TransB, + int pA, int pB, int pC, + float scale_r, float scale_i); +/* c += scale op(A) b */ +int pdp_packet_matrix_blas_mv(CBLAS_TRANSPOSE_t TransA, + int pA, int pb, int pc, + float scale_r, float scale_i); + +/* other gsl wrappers */ +int pdp_packet_matrix_LU(int p_matrix); +int pdp_packet_matrix_LU_to_inverse(int p_matrix); +int pdp_packet_matrix_LU_solve(int p_matrix, int p_vector); + + +#endif diff --git a/include/pdp_mem.h b/include/pdp_mem.h new file mode 100644 index 0000000..3301655 --- /dev/null +++ b/include/pdp_mem.h @@ -0,0 +1,46 @@ +/* + * Pure Data Packet header file: memory allocation + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +#ifndef _PDP_MEM_H_ +#define _PDP_MEM_H_ + +#include <pthread.h> + +/* a wrapper around malloc and free to keep track of pdp's memory usage */ +void *pdp_alloc(int size); +void pdp_dealloc(void *stuff); + + +/* fast allocator object (for lists and atoms) */ +#define PDP_FASTALLOC_BLOCK_ELEMENTS 4096 +typedef struct _pdp_fastalloc +{ + unsigned int atom_size; + unsigned int block_elements; + pthread_mutex_t mut; + struct _fastalloc *freelist; + +} t_pdp_fastalloc; + +void *pdp_fastalloc_new_atom(t_pdp_fastalloc *x); +void pdp_fastalloc_save_atom(t_pdp_fastalloc *x, void *atom); +t_pdp_fastalloc *pdp_fastalloc_new(unsigned int size); + +#endif diff --git a/include/pdp_mmx.h b/include/pdp_mmx.h new file mode 100644 index 0000000..8181ff0 --- /dev/null +++ b/include/pdp_mmx.h @@ -0,0 +1,171 @@ + +/* + * Pure Data Packet. Header file for mmx routines. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +#ifndef PDP_MMX_H +#define PDP_MMX_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/****************************** 16 bit signed (pixel) routines ***************************************/ + +/* pack: gain is 8.8 fixed point */ +void pixel_pack_s16u8_y(short int *input_pixels, + unsigned char *output_pixels, + int nb_pixels_div_8); + +void pixel_pack_s16u8_uv(short int *input_pixels, + unsigned char *output_pixels, + int nb_pixels_div_8); + + +/* unpack: gain is not used -> full scale unpack */ +void pixel_unpack_u8s16_y(unsigned char *input_pixels, + short int *output_pixels, + int nb_pixels_div_8); + +void pixel_unpack_u8s16_uv(unsigned char *input_pixels, + short int *output_pixels, + int nb_pixels_div_8); + + +/* gain */ +/* gain = integer */ +/* shift is down shift count */ +void pixel_gain_s16(short int *image, + int nb_4pixel_vectors, + short int gain[4], + unsigned long long *shift); + + +/* mix: left = gain_left * left + gain_right * right / gains are s.15 fixed point */ +void pixel_mix_s16(short int *left, + short int *right, + int nb_4pixel_vectors, + short int gain_left[4], + short int gain_right[4]); + +void pixel_randmix_s16(short int *left, + short int *right, + int nb_4pixel_vectors, + short int random_seed[4], + short int threshold[4]); + +void pixel_rand_s16(short int *image, + int nb_4pixel_vectors, + short int random_seed[4]); + +void pixel_add_s16(short int *left, + short int *right, + int nb_4pixel_vectors); + +void pixel_mul_s16(short int *left, + short int *right, + int nb_4pixel_vectors); + + +/* affine transfo */ +void pixel_affine_s16(short int *buf, + int nb_4pixel_vectors, + short int gain[4], + short int offset[4]); + +/* conv */ +void pixel_conv_hor_s16(short int *pixel_array, + int nb_4_pixel_vectors, + short int border[4], + short int mask[12]); + +void pixel_conv_ver_s16(short int *pixel_array, + int nb_4_pixel_vectors, + int row_byte_size, + short int border[4], + short int mask[12]); + +/* biquad */ + +void pixel_biquad_vertb_s16(short int *pixel_array, + int nb_4x4_pixblocks, + int linewidth, + short int coef[20], + short int state[8]); + +void pixel_biquad_verbt_s16(short int *pixel_array, + int nb_4x4_pixblocks, + int linewidth, + short int coef[20], + short int state[8]); + + +void pixel_biquad_horlr_s16(short int *pixel_array, + int nb_4x4_pixblocks, + int linewidth, + short int coef[20], + short int state[8]); + +void pixel_biquad_horrl_s16(short int *pixel_array, + int nb_4x4_pixblocks, + int linewidth, + short int coef[20], + short int state[8]); + +void pixel_biquad_time_s16(short int *pixel_array, + short int *state_array1, + short int *state_array2, + short int *coefs, + int nb_4_pix_vectors); + +/********************************** PLANAR COLOUR OPERATIONS ***************************************/ + +/* color rotation for 3 colour planes */ +void pixel_crot3d_s16(short int *pixel_array, + int nb_4pixel_vectors_per_plane, + short int *row_encoded_vector_matrix); + + +/* color rotation for 2 colour planes */ +void pixel_crot2d_s16(short int *pixel_array, + int nb_4pixel_vectors_per_plane, + short int *row_encoded_vector_matrix); + + +/********************************** RESAMPLE OPERATIONS *******************************************/ + +// affine transformation (called linear map, but that's flou terminology) +void pixel_resample_linmap_s16(void *x); + + + +/********************************** POLYNOMIAL OPERATIONS *****************************************/ +// chebychev polynomial +void pixel_cheby_s16_3plus(short int *buf, int nb_8pixel_vectors, int orderplusone, short int *coefs); + + + +#ifdef __cplusplus +} +#endif + + +#endif //PDP_MMX_H diff --git a/include/pdp_net.h b/include/pdp_net.h new file mode 100644 index 0000000..ddc3f7f --- /dev/null +++ b/include/pdp_net.h @@ -0,0 +1,197 @@ +#ifndef __PDP_UDP_H_ +#define __PDP_UDP_H_ + +/* + * Pure Data Packet header: UDP protocol for raw packets + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 file contains the specification of the pdp UDP transport protocol. + It is a very basic binary protocol, not very fool proof. + + The protocol: + + A header packet is transmitted first. This contains mime type information, + and the size of and number of packets to be received. + + The connection id: + + Currently it is just a random number from the libc rand() function + this should be accurate enough. + + +*/ + +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <pthread.h> +#include <netdb.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +/* some defs */ +#define MAX_UDP_PACKET 1472 +#define RESEND_MAX_CHUNKS ((MAX_UDP_PACKET - sizeof(t_pdp_udp_header))/sizeof(unsigned int)) + +#define PDP_UDP_VERSION 1 + +/* a pdp udp packet is prepended with this header */ + +typedef struct _pdp_udp_header +{ + char signature[4]; /* must be "PDP" */; + unsigned int version; /* protocol version */ + unsigned int connection_id; /* the 'connection' id */ + unsigned int sequence_number; /* sequence number. negative: control packet: body contains meta info */ + +} t_pdp_udp_header; + +/* the data part for a new connection */ + +#define PDP_UDP_NEW -1 /* start a new transmission */ +typedef struct _pdp_udp_new +{ + unsigned int data_size; /* the size of the packets */ + unsigned int nb_chunks; /* number of chunks in pdp to be transmitted */ + unsigned int chunk_size; /* the maximum chunk size */ + char type[0]; /* the packet type */ + + // the tail part is the mime type, for creation and reassembly +} t_pdp_udp_newpacket; + +#define PDP_UDP_DONE -2 /* transmission is done */ + +#define PDP_UDP_RESEND -3 /* request retransmission of certain chunks. empty: transmission ok */ +#define PDP_UDP_ACKNEW -4 /* acknowledge reception of new packet header */ + + +/* receiver and sender classes (transport layer) */ + +#define PDP_UDP_BUFSIZE 0xF000 + +/* RECEIVER */ +typedef struct _pdp_udp_receiver +{ + + // buffer for receiving + t_pdp_udp_header x_header; //pdp over udp header + char x_buf[PDP_UDP_BUFSIZE]; //send buffer + unsigned int x_zero_terminator; // to prevent runaway strings + unsigned int x_buf_size; //size of the received data in the buffer (excluding the header) + + // buffer for sending + t_pdp_udp_header x_resend_header; // header of the resend packet + unsigned int x_resend_chunks[RESEND_MAX_CHUNKS]; // body contains the chunks to resend + unsigned int x_resend_udp_packet_size; + + // transmission info + unsigned int x_connection_id; + unsigned int x_nb_chunks; + unsigned int x_chunk_size; + unsigned int *x_chunk_list; + char *x_data_type; + unsigned int x_data_size; + void *x_data; + struct sockaddr_in x_source_socket; + int x_sslen; + int x_receive_finished; + int x_packet_transferred; + + int x_socket; //socket used for sending + struct sockaddr_in x_sa; //address struct + +} t_pdp_udp_receiver; + +/* setup */ +t_pdp_udp_receiver *pdp_udp_receiver_new(int port); +void pdp_udp_receiver_free(t_pdp_udp_receiver *x); + +/* reset connection (wait for new packet) */ +void pdp_udp_receiver_reset(t_pdp_udp_receiver *x); + +/* receive, returns 1 on success, 0 on timeout, -1 on error */ +int pdp_udp_receiver_receive(t_pdp_udp_receiver *x, unsigned int timeout_ms); + +/* get meta & data */ +char *pdp_udp_receiver_type(t_pdp_udp_receiver *x); +unsigned int pdp_udp_receiver_size(t_pdp_udp_receiver *x); +void *pdp_udp_receiver_data(t_pdp_udp_receiver *x); + + + +/* SENDER */ +typedef struct _pdp_udp_sender +{ + // desired udp packet size + unsigned int x_udp_payload_size; + + // current packet && communication info + unsigned int x_connection_id; + char *x_data_type; + void *x_data; + unsigned int x_data_size; + unsigned int x_chunk_size; + unsigned int *x_chunk_list; + unsigned int x_nb_chunks; + unsigned int x_chunk_list_size; + + // connection data + int x_socket; //socket used for sending + struct sockaddr_in x_sa; //address struct + unsigned int x_sleepgrain_us; //pause between sends (the poor man's flow control) (0 == no sleep) + unsigned int x_sleep_count; + unsigned int x_sleep_period; + unsigned int x_timeout_us; + + // temp buffer for sending + t_pdp_udp_header x_header; + char x_buf[PDP_UDP_BUFSIZE]; + unsigned int x_buf_size; + + // temp buffer for receiving + t_pdp_udp_header x_resend_header; + unsigned int x_resend_chunks[RESEND_MAX_CHUNKS]; + unsigned int x_resend_items; + + +} t_pdp_udp_sender; + +/* some flow control variables */ +void pdp_udp_sender_timeout_us(t_pdp_udp_sender *x, unsigned int timeout_us); +void pdp_udp_sender_sleepgrain_us(t_pdp_udp_sender *x, unsigned int sleepgrain_us); +void pdp_udp_sender_sleepperiod(t_pdp_udp_sender *x, unsigned int sleepperiod); +void pdp_udp_sender_udp_packet_size(t_pdp_udp_sender *x, unsigned int udp_packet_size); + +/* setup */ +t_pdp_udp_sender *pdp_udp_sender_new(void); +void pdp_udp_sender_free(t_pdp_udp_sender *x); + +/* connect */ +void pdp_udp_sender_connect(t_pdp_udp_sender *x, char *host, unsigned int port); + +/* send, returns 1 on success, 0 on error */ +int pdp_udp_sender_send(t_pdp_udp_sender *x, char* type, unsigned int size, void *data); + + + +#endif diff --git a/include/pdp_packet.h b/include/pdp_packet.h new file mode 100644 index 0000000..f944095 --- /dev/null +++ b/include/pdp_packet.h @@ -0,0 +1,214 @@ +/* + * Pure Data Packet system implementation: Packet Manager Interface + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 file contains the pdp packet manager interface specification. + + It is an implementation of the "Object Pool" pattern with lazy instantiation + and lazy destruction. + + The pool is a growable array. It can only grow larger. Packets are represented + by an integer, which is an index in this array. + + The standard "pure" packets (the ones which use a flat memory buffer) have recovery + for resource depletion (main memory). If an out of memory condition is met + on allocation of a new package, the garbage collector kicks in and frees unused + packets until the out of memory condition is solved. Since an out of memory + condition can be fatal for other parts of the program, pdp also supports a + memory limit, to ensure some kind of safety margin. + + The "not so pure" packets should resolve resource conflicts in their own factory method, + since the constructor is responsible for allocating external resources. The standard + way to do this is to allocate a packet, free it's resources and allocate a new packet + until the resource allocation succeeds. Especially for these kinds of packets, the + pdp pool supports an explicit reuse method. This returns a valid packet if it can reuse + one (based on the high level type description). + + Packets that don't have memory managing methods defined in the packet class + (Standard packets) are treated as a header concatenated with a flat memory buffer, and + can be copied and cloned without problems. So, if a packet contains pointers to other + data or code, it can't be a pure packet. + + The interface to the packet manager contains the following managing methods: + + * pdp_packet_new: create a new packet or reuse a previous one + * pdp_packet_mark_unused: release a packet + * pdp_packet_copy_ro: register a packet for read only use + * pdp_packet_copy_rw: register a packet for read/write use (this creates a copy if necessary) + * pdp_packet_clone_rw: create a new packet using a template, but don't copy the data + + And two methods for raw data access + + * pdp_packet_header: retreive the header of the packet + * pdp_packet_data: retreive the data buffer of the packet (only for static packets) + + All the methods declared in this header are supposed to be thread safe, so you + can call them from the pd and pdp thread. + +*/ + +#ifndef PDP_PACKET_H +#define PDP_PACKET_H + +#include "pdp_symbol.h" +#include "pdp_types.h" + +// this is legacy stuff: images are basic types +#include "pdp_image.h" +#include "pdp_bitmap.h" + + +#define PDP_HEADER_SIZE 256 + + + +/* all symbols are C-style */ +#ifdef __cplusplus +extern "C" +{ +#endif + + + +typedef int (*t_pdp_factory_method)(t_pdp_symbol *); //returns bool success + +/* packet class header */ +typedef struct _pdp_class +{ + /* packet manips: non-pure data packets (using external resources) must define these */ + t_pdp_packet_method1 wakeup; /* called before returning a reused packet (rc:0->1) */ + t_pdp_packet_method2 copy; /* copy data from source packet to destination packet */ + t_pdp_packet_method1 cleanup; /* free packet's resources (destructor) */ + t_pdp_packet_method1 sleep; /* mark_unused notify: called when refcount reaches zero */ + t_pdp_symbol *type; /* type template for packet class */ + t_pdp_factory_method create; /* the constructor: create a packet with uninitialized data */ +}t_pdp_class; + + +/* TODO: + implement garbage collection for fobs. + (fobs are forth object dictionaries, but for the gc these count as lists) +*/ + +#define PDP_GC_COLOUR_GREY 0 /* 0 == default: object is reachable */ +#define PDP_GC_COLOUR_WHITE 1 +#define PDP_GC_COLOUR_BLACK 2 + + +/* packet object header */ +struct _pdp +{ + /* meta info */ + unsigned int type; /* main datatype of this object */ + t_pdp_symbol *desc; /* high level type description (sort of a mime type) */ + unsigned int size; /* datasize including header */ + unsigned int flags; /* packet flags */ + + /* reference count */ + unsigned int users; /* nb users of this object, readonly if > 1 */ + + /* class object */ + t_pdp_class *theclass; /* if zero, the packet is a pure packet (just data, no member functions) */ + + u32 pad[10]; /* LATER: reserve bytes to provide compatibility with future extensions */ + + union /* each packet type has a unique subheader */ + { + t_raw raw; /* raw subheader (for extensions unkown to pdp core system) */ + struct _image image; /* (nonstandard internal) 16 bit signed planar bitmap image format */ + struct _bitmap bitmap; /* (standard) bitmap image (fourcc coded) */ + //t_ca ca; /* cellular automaton state data */ + //t_ascii ascii; /* ascii packet */ + } info; + +}; + + +/* pdp data packet type id */ +#define PDP_IMAGE 1 /* 16bit signed planar scanline encoded image packet */ +//RESERVED: #define PDP_CA 2 /* 1bit toroidial shifted scanline encoded cellular automaton */ +//RESERVED: #define PDP_ASCII 3 /* ascii packet */ +//RESERVED: #define PDP_TEXTURE 4 /* opengl texture object */ +//RESERVED: #define PDP_3DCONTEXT 5 /* opengl render context */ +#define PDP_BITMAP 6 /* 8bit image packet (fourcc coded??) */ +//RESERVED: #define PDP_MATRIX 7 /* floating point/double matrix/vector packet (from gsl) */ +#define PDP_FOB 8 /* small c->forth object wrapper */ + +/* PACKET FLAGS */ +#define PDP_FLAG_DONOTCOPY (1<<0) /* don't copy the packet on register_rw, instead return an invalid packet */ + + + +/* class methods */ +t_pdp_class *pdp_class_new(t_pdp_symbol *type, t_pdp_factory_method create); + +#if 0 +void pdp_class_addmethod(t_pdp_class *c, t_pdp_symbol *name, t_pdp_attribute_method method, + struct _pdp_list *in_spec, struct _pdp_list *out_spec); +#endif + +/* packet factory method + registration */ +int pdp_factory_newpacket(t_pdp_symbol *type); + +#if 0 +/* send a message to a packet (packet polymorphy) + this returns NULL on failure, or a return list + the return list should be freed by the caller */ + +int pdp_packet_op(t_pdp_symbol *operation, struct _pdp_list *stack); +#endif + +/* debug */ +void pdp_packet_print_debug(int packet); + + +/* hard coded packet methods */ +int pdp_packet_copy_ro(int handle); /* get a read only copy */ +int pdp_packet_copy_rw(int handle); /* get a read/write copy */ +int pdp_packet_clone_rw(int handle); /* get an empty read/write packet of the same type (only copy header) */ +void pdp_packet_mark_unused(int handle); /* indicate that you're done with the packet */ +void pdp_packet_delete(int packet); /* like mark_unused, but really delete when refcount == 0 */ + +t_pdp* pdp_packet_header(int handle); /* get packet header */ +void* pdp_packet_subheader(int handle); /* get packet subheader */ +void* pdp_packet_data(int handle); /* get packet raw data */ +int pdp_packet_data_size(int handle); /* get packet raw data size */ + +int pdp_packet_compat(int packet0, int packet1); +int pdp_packet_reuse(t_pdp_symbol *description); +int pdp_packet_create(unsigned int datatype, unsigned int datasize); /* create a new packet, don't reuse */ + +int pdp_packet_writable(int packet); /* returns true if packet is writable */ +void pdp_packet_replace_with_writable(int *packet); /* replaces a packet with a writable copy */ +//void pdp_packet_mark_unused_atomic(int *handle); /* mark unused + set reference to -1 (for thread synchro) */ + + +/* pool stuff */ +int pdp_pool_collect_garbage(void); /* free all unused packets */ +void pdp_pool_set_max_mem_usage(int max); /* set max mem usage */ + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/pdp_pd.h b/include/pdp_pd.h new file mode 100644 index 0000000..e200c1e --- /dev/null +++ b/include/pdp_pd.h @@ -0,0 +1,7 @@ +/* pdp_pd.h wrapper */ + +#ifndef _M_PD_H_ +#define _M_PD_H_ +#include "m_pd.h" +#endif + diff --git a/include/pdp_png.h b/include/pdp_png.h new file mode 100644 index 0000000..5aae4c7 --- /dev/null +++ b/include/pdp_png.h @@ -0,0 +1,28 @@ +/* + * Pure Data Packet header file. png glue code. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +#ifndef __PDP_PNG_H__ +#define __PDP_PNG_H__ + +int pdp_packet_bitmap_save_png_file(int packet, char *filename); +int pdp_packet_bitmap_from_png_file(char *filename); + + +#endif diff --git a/include/pdp_post.h b/include/pdp_post.h new file mode 100644 index 0000000..05b5143 --- /dev/null +++ b/include/pdp_post.h @@ -0,0 +1,29 @@ + +/* + * Pure Data Packet header file. pdp logging. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +#ifndef _PDP_POST_H_ +#define _PDP_POST_H_ + +/* write a message to log (console) */ +void pdp_post_n(char *fmt, ...); +void pdp_post(char *fmt, ...); + +#endif diff --git a/include/pdp_queue.h b/include/pdp_queue.h new file mode 100644 index 0000000..eeffd2e --- /dev/null +++ b/include/pdp_queue.h @@ -0,0 +1,123 @@ +/* + * Pure Data Packet - processor queue interface + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +#ifndef PDP_QUEUE_H +#define PDP_QUEUE_H + +#include "pdp_pd.h" +#include <pthread.h> + +/********************* general purpose pd process queue class *********************/ + +typedef void (*t_pdpmethod)(void *client); + +/* the process queue data record */ +typedef struct process_queue_struct +{ + void *x_owner; /* the object we are dealing with */ + t_pdpmethod x_process; /* the process method */ + t_pdpmethod x_callback; /* the function to be called when finished */ + int *x_queue_id; /* place to store the queue id for task */ +} t_process_queue_item; + + +/* a pd process queue object */ +typedef struct _pd_queue +{ + /* clock members */ + t_clock *pdp_clock; + double deltime; + + /* some bookkeeping vars */ + long long ticks; + long long packets; + + /* queue members */ + t_process_queue_item *q; /* queue */ + int mask; + int head; /* last entry in queue + 1 */ + int tail; /* first entry in queque */ + int curr; /* the object currently processed in other thread */ + + /* pthread vars */ + pthread_mutex_t mut; + pthread_cond_t cond_dataready; + pthread_cond_t cond_processingdone; + pthread_t thread_id; + + /* toggle for thread usage */ + int use_thread; + +} t_pdp_procqueue; + + +/* all symbols are C-style */ +#ifdef __cplusplus +extern "C" +{ +#endif + + +/* returns 1 if full, 0 if there's space available */ +int pdp_procqueue_full(t_pdp_procqueue *q); + + +void pdp_procqueue_flush(t_pdp_procqueue *q); +void pdp_procqueue_wait(t_pdp_procqueue *q); +void pdp_procqueue_finish(t_pdp_procqueue *q, int index); +void pdp_procqueue_add(t_pdp_procqueue *q, void *owner, void *process, void *callback, int *queue_id); +void pdp_procqueue_use_thread(t_pdp_procqueue* q, int t); +void pdp_procqueue_init(t_pdp_procqueue *q, double milliseconds, int logsize); + +/********************* interface to pdp process queue singleton *********************/ + +/* processor queue methods, callable from main pd thread */ + +/* get the default queue */ +t_pdp_procqueue *pdp_queue_get_queue(void); + + + +#if 1 + +/* add a method to the processing queue */ +void pdp_queue_add(void *owner, void *process, void *callback, int *queue_id); + +/* halt main tread until processing is done */ +void pdp_queue_wait(void); + +/* halt main tread until processing is done and remove + callback from queue(for destructors) */ +void pdp_queue_finish(int queue_id); + +#endif + + +/* misc signals to pdp */ +void pdp_control_notify_drop(int packet); + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/pdp_resample.h b/include/pdp_resample.h new file mode 100644 index 0000000..8876bfa --- /dev/null +++ b/include/pdp_resample.h @@ -0,0 +1,50 @@ +/* + * Pure Data Packet header file. - image resampling prototypes + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +#ifndef PDP_RESAMPLE_H +#define PDP_RESAMPLE_H + +#include "pdp_types.h" + + +/* image resampling methods */ +void pdp_resample_scale_bilin(s16 *src_image, s16 *dst_image, s32 src_w, s32 src_h, s32 dst_w, s32 dst_h); +void pdp_resample_scale_nn(s16 *src_image, s16 *dst_image, s32 src_w, s32 src_h, s32 dst_w, s32 dst_h); + +/* USE pdp_imageproc_resample_affinemap +void pdp_resample_zoom_tiled_bilin(s16 *src_image, s16 *dst_image, s32 w, s32 h, + float zoom_x, float zoom_y, float center_x_relative, float center_y_relative); +*/ + +//void pdp_resample_zoom_tiled_nn(s16 *src_image, s16 *dst_image, s32 w, s32 h, float zoom_x, float zoom_y); + + + +/* power of 2 resamplers */ +void pdp_resample_halve(s16 *src_image, s16 *dst_image, s32 src_w, s32 src_h); +void pdp_resample_double(s16 *src_image, s16 *dst_image, s32 src_w, s32 src_h); + + + +/* core routines */ +//s32 pdp_resample_bilin(s16 *image, s32 width, s32 height, s32 virt_x, s32 virt_y); + + +#endif diff --git a/include/pdp_symbol.h b/include/pdp_symbol.h new file mode 100644 index 0000000..fe3137a --- /dev/null +++ b/include/pdp_symbol.h @@ -0,0 +1,136 @@ +/* + * Pure Data Packet system implementation. : symbol and namespace stuff + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +#ifndef _PDP_SYMBOL_ +#define _PDP_SYMBOL_ + + +/* pdp's symbols are derived from pd's symbols + there is one symbol hash. each symbol has + a meaning in several name spaces. + + * forth words + * type description lists (for accelerating type matching) + + +*/ + +#include "pdp_list.h" + + + + +/* the pdp symbol type */ +typedef struct _pdp_symbol +{ + /* next */ + struct _pdp_symbol *s_next; + + /* the symbol name */ + char *s_name; + + /* forth symbol->atom */ + struct _pdp_atom s_forth; + + /* packet handling cache */ + struct _pdp_list *s_type; // a parsed type description: a/b/c -> (a,b,c) + struct _pdp_list *s_reusefifo; // packet pool fifo for this type + + +} t_pdp_symbol; + + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* namespace stuff */ +int pdp_symbol_set_typelist(t_pdp_symbol *s, struct _pdp_list *typelist); + +/* get symbol from char */ +t_pdp_symbol *pdp_gensym(char *s); + +/* iterate over all symbols */ +typedef void (*t_pdp_symbol_iterator)(t_pdp_symbol *s); +void pdp_symbol_apply_all(t_pdp_symbol_iterator ir); + +// don't use these directly, use the macros +extern t_pdp_symbol _pdp_sym_wildcard; +extern t_pdp_symbol _pdp_sym_float; +extern t_pdp_symbol _pdp_sym_int; +extern t_pdp_symbol _pdp_sym_symbol; +extern t_pdp_symbol _pdp_sym_packet; +extern t_pdp_symbol _pdp_sym_pointer; +extern t_pdp_symbol _pdp_sym_list; +extern t_pdp_symbol _pdp_sym_invalid; +extern t_pdp_symbol _pdp_sym_question_mark; +extern t_pdp_symbol _pdp_sym_atom; +extern t_pdp_symbol _pdp_sym_null; +extern t_pdp_symbol _pdp_sym_quote_start; +extern t_pdp_symbol _pdp_sym_quote_end; +extern t_pdp_symbol _pdp_sym_return; +extern t_pdp_symbol _pdp_sym_nreturn; +extern t_pdp_symbol _pdp_sym_defstart; +extern t_pdp_symbol _pdp_sym_defend; +extern t_pdp_symbol _pdp_sym_if; +extern t_pdp_symbol _pdp_sym_then; +extern t_pdp_symbol _pdp_sym_local; +extern t_pdp_symbol _pdp_sym_forth; +extern t_pdp_symbol _pdp_sym_call; +extern t_pdp_symbol _pdp_sym_push; +extern t_pdp_symbol _pdp_sym_pop; + + +#ifdef __cplusplus +} +#endif + +// these symbols are used a lot in critical parts +// optimize later + +#define PDP_SYM_WILDCARD &_pdp_sym_wildcard +#define PDP_SYM_FLOAT &_pdp_sym_float +#define PDP_SYM_INT &_pdp_sym_int +#define PDP_SYM_SYMBOL &_pdp_sym_symbol +#define PDP_SYM_PACKET &_pdp_sym_packet +#define PDP_SYM_POINTER &_pdp_sym_pointer +#define PDP_SYM_LIST &_pdp_sym_list +#define PDP_SYM_INVALID &_pdp_sym_invalid +#define PDP_SYM_QUESTION_MARK &_pdp_sym_question_mark +#define PDP_SYM_ATOM &_pdp_sym_atom +#define PDP_SYM_NULL &_pdp_sym_null +#define PDP_SYM_QUOTE_START &_pdp_sym_quote_start +#define PDP_SYM_QUOTE_END &_pdp_sym_quote_end +#define PDP_SYM_RETURN &_pdp_sym_return +#define PDP_SYM_NRETURN &_pdp_sym_nreturn +#define PDP_SYM_DEF_START &_pdp_sym_defstart +#define PDP_SYM_DEF_END &_pdp_sym_defend +#define PDP_SYM_IF &_pdp_sym_if +#define PDP_SYM_THEN &_pdp_sym_then +#define PDP_SYM_LOCAL &_pdp_sym_local +#define PDP_SYM_FORTH &_pdp_sym_forth +#define PDP_SYM_CALL &_pdp_sym_call +#define PDP_SYM_PUSH &_pdp_sym_push +#define PDP_SYM_POP &_pdp_sym_pop + +#endif + diff --git a/include/pdp_type.h b/include/pdp_type.h new file mode 100644 index 0000000..85d6ea7 --- /dev/null +++ b/include/pdp_type.h @@ -0,0 +1,180 @@ +/* + * Pure Data Packet system implementation. Type handling interface + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +/* COMMENTS + +Since version 0.11 all packets have an (optional) high level type description. +This can be thought of as their mime type. It has several uses: + +* automatic type conversion +* better reuse strategy for non pure packets +* debugging + +The description is text-encoded, in the following form: + +type/subtype/subsubtype/.. + +This is implemented using t_pdp_symbol. + +Type descriptors can have wildcards. This is to give some freedom to a desired +type conversion. The following are all compatible: + +*/ + +// image/grey/320x240 +// image/*/320x240 +// image/*/* + +/* + +From a user pov, the type conversion is centralized. A single object (pdp_convert) +can do most of the conversions. + +Type conversion implementation has to be done decentralized. It is subdivided into +two steps: inter-type and intra-type conversions. + +Intra-type is the full responsability of each type implementation and can be handled +in a decentralized way (at linkage the type central intra-converter is registered +at the pdp framework. + +Inter-type conversion is harder to do decentralized, therefore each new type should +provide some conversions to the basic built in types. (internal image, bitmap or matrix +types. + +The point of this whole business is to + +* enable automatic conversion from anything to a desired type for operators that combine objects. + i.e. pdp_add but receive incompatible objects. +* enable manual anything to anything conversion using a pdp_convert object, i.e. have a consistent + packet conversion api for users. + + +The solution is type conversion programs. A program's behaviour is specified as follows: + +* the program is registered with a source and destination (result) template +* it is passed a packet and a destination template +* it can assume the source packet complies to the program's registerd source template +* it should convert the packet to a packet that will comply to it's registered destination template +* if for some reason a conversion fails, an invalid packet (handle == -1) should be returned + +about type templates: + +* they are hierarchical, with subtypes separated by a '/' character +* they can contain a wildcard '*', meaning that a certain level in the type hierarchy is: + - a don't care value, when the wildcard is used + -> as a destination template in a requested conversion + -> as a source template in a conversion program's specification + - uspecified, when the wildcard is used + -> as a destination template in a conversion program's specification + + + +NOTE: + + a wildcard can't be used in a source template for a conversion request + this assymetry requires there be 2 kinds of template matching mechanisms: + + - source type description (without wildcards) to conversion program source template matching + - destination type description (with wildcards) to conversion program destination template matching + + since a packet's type description cannot have wildcards, a symmetric matching (both sides have + wildcards) can be used for matching. + +*/ + + + +/* + +implementation: + +there are 2 lists with conversion progams: +* the global list, containing all registered programs. +* the cached list, containing all recently used registered programs, or combinations thereof + +if there is no cached, perfectly matching rule, a new one will be created, and added to +the head of the conversion list. + +all conversion methods should keep their hands off the source packet. it is treated as readonly. +this is to ensure a more flexible operation (i.e. be able to put the conversion at the register_ro +level) + + +TODO: add a breadth first search algorithm to do multiple stage conversion. + +*/ + +#ifndef PDP_TYPE_H +#define PDP_TYPE_H + +#include "pdp_symbol.h" +#include "pdp_list.h" + +/* the conversion method accepts a packet (which is freed) and a destination wildcard + and produces a new packet, or the invalid packet if the conversion failed */ +typedef int (*t_pdp_conversion_method)(int, t_pdp_symbol *); + +/* a conversion program is alist of conversion methods */ +typedef t_pdp_list t_pdp_conversion_program; + +/* a conversion has source and dest wildcards, and a conversion program */ +typedef struct _pdp_conversion +{ + t_pdp_symbol *src_pattern; // source type pattern + t_pdp_symbol *dst_pattern; // destination type pattern + t_pdp_conversion_program *program; // the conversion program for this conversion +} t_pdp_conversion; + +/* all symbols are C style */ +#ifdef __cplusplus +extern "C" +{ +#endif + +/* pdp_packet methods */ +t_pdp_symbol *pdp_packet_get_description(int packet); +int pdp_packet_convert_ro(int packet, t_pdp_symbol *dest_pattern); +int pdp_packet_convert_rw(int packet, t_pdp_symbol *dest_pattern); + + +/* pdp_conversion_program methods */ +void pdp_conversion_program_free(t_pdp_conversion_program *program); +t_pdp_conversion_program *pdp_conversion_program_new(t_pdp_conversion_method method, ...); +t_pdp_conversion_program *pdp_conversion_program_copy(t_pdp_conversion_program *program); +void pdp_conversion_program_add(t_pdp_conversion_program *program, t_pdp_conversion_program *tail); + +/* pdp_type (central type object) methods */ +int pdp_type_description_match(t_pdp_symbol *description, t_pdp_symbol *pattern); +void pdp_type_register_conversion (t_pdp_symbol *src_pattern, t_pdp_symbol *dst_pattern, t_pdp_conversion_program *program); +void pdp_type_register_cached_conversion (t_pdp_symbol *src_pattern, t_pdp_symbol *dst_pattern, t_pdp_conversion_program *program); + + //t_pdp_symbol *pdp_type_gendesc(char *desc); //generate a type description (with description list attached) +t_pdp_list *pdp_type_to_list(t_pdp_symbol *type); + +/* pdp's (threadsafe) symbol */ +t_pdp_symbol *pdp_gensym(char *s); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/pdp_type.h_old b/include/pdp_type.h_old new file mode 100644 index 0000000..d588e7f --- /dev/null +++ b/include/pdp_type.h_old @@ -0,0 +1,180 @@ +/* + * Pure Data Packet system implementation. Type handling interface + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +/* COMMENTS + +Since version 0.11 all packets have an (optional) high level type description. +This can be thought of as their mime type. It has several uses: + +* automatic type conversion +* better reuse strategy for non pure packets +* debugging + +The description is text-encoded, in the following form: + +type/subtype/subsubtype/.. + +This is implemented using t_pdp_symbol. + +Type descriptors can have wildcards. This is to give some freedom to a desired +type conversion. The following are all compatible: + +*/ + +// image/grey/320x240 +// image/*/320x240 +// image/*/* + +/* + +From a user pov, the type conversion is centralized. A single object (pdp_convert) +can do most of the conversions. + +Type conversion implementation has to be done decentralized. It is subdivided into +two steps: inter-type and intra-type conversions. + +Intra-type is the full responsability of each type implementation and can be handled +in a decentralized way (at linkage the type central intra-converter is registered +at the pdp framework. + +Inter-type conversion is harder to do decentralized, therefore each new type should +provide some conversions to the basic built in types. (internal image, bitmap or matrix +types. + +The point of this whole business is to + +* enable automatic conversion from anything to a desired type for operators that combine objects. + i.e. pdp_add but receive incompatible objects. +* enable manual anything to anything conversion using a pdp_convert object, i.e. have a consistent + package conversion api for users. + + +The solution is type conversion programs. A program's behaviour is specified as follows: + +* the program is registered with a source and destination (result) template +* it is passed a packet and a destination template +* it can assume the source packet complies to the program's registerd source template +* it should convert the packet to a packet that will comply to it's registered destination template +* if for some reason a conversion fails, an invalid packet (handle == -1) should be returned + +about type templates: + +* they are hierarchical, with subtypes separated by a '/' character +* they can contain a wildcard '*', meaning that a certain level in the type hierarchy is: + - a don't care value, when the wildcard is used + -> as a destination template in a requested conversion + -> as a source template in a conversion program's specification + - uspecified, when the wildcard is used + -> as a destination template in a conversion program's specification + + + +NOTE: + + a wildcard can't be used in a source template for a conversion request + this assymetry requires there be 2 kinds of template matching mechanisms: + + - source type description (without wildcards) to conversion program source template matching + - destination type description (with wildcards) to conversion program destination template matching + + since a packet's type description cannot have wildcards, a symmetric matching (both sides have + wildcards) can be used for matching. + +*/ + + + +/* + +implementation: + +there are 2 lists with conversion progams: +* the global list, containing all registered programs. +* the cached list, containing all recently used registered programs, or combinations thereof + +if there is no cached, perfectly matching rule, a new one will be created, and added to +the head of the conversion list. + +all conversion methods should keep their hand's off the source packet. it is treated as readonly. +this is to ensure a more flexible operation (i.e. be able to put the conversion at the register_ro +level) this will need a bit more logic in running the conversion program though.. + + +*/ + +#ifndef PDP_TYPE_H +#define PDP_TYPE_H + +/* the conversion method accepts a packet (which is freed) and a destination wildcard + and produces a new packet, or the invalid packet if the conversion failed */ +typedef int (*t_pdp_conversion_method)(int, t_pdp_symbol *); + +/* a conversion program is alist of conversion methods */ +typedef struct _pdp_conversion_program +{ + t_pdp_conversion_method method; // conversion method + struct _pdp_conversion_program *next; // next method in program +} t_pdp_conversion_program; + +/* a conversion has source and dest wildcards, and a conversion program */ +typedef struct _pdp_conversion +{ + t_pdp_symbol *src_pattern; // source type pattern + t_pdp_symbol *dst_pattern; // destination type pattern + t_pdp_conversion_program *program; // the conversion program for this conversion + struct _pdp_conversion *next; // next conversion program record +} t_pdp_conversion; + +/* all symbols are C style */ +#ifdef __cplusplus +extern "C" +{ +#endif + +/* pdp_packet methods */ +t_pdp_symbol *pdp_packet_get_description(int packet); +int pdp_packet_convert_ro(int packet, t_pdp_symbol *dest_pattern); +int pdp_packet_convert_rw(int packet, t_pdp_symbol *dest_pattern); + + +/* pdp_conversion_program methods */ +void pdp_conversion_program_free(t_pdp_conversion_program *program); +t_pdp_conversion_program *pdp_conversion_program_new(t_pdp_conversion_method method, ...); +t_pdp_conversion_program *pdp_conversion_program_copy(t_pdp_conversion_program *program); +void pdp_conversion_program_add(t_pdp_conversion_program *program, t_pdp_conversion_program *tail); + +/* pdp_type (central type object) methods */ +int pdp_type_description_match(t_pdp_symbol *description, t_pdp_symbol *pattern); +void pdp_type_register_conversion (t_pdp_symbol *src_pattern, t_pdp_symbol *dst_pattern, t_pdp_conversion_program *program); +void pdp_type_register_cached_conversion (t_pdp_symbol *src_pattern, t_pdp_symbol *dst_pattern, t_pdp_conversion_program *program); + + //t_pdp_symbol *pdp_type_gendesc(char *desc); //generate a type description (with description list attached) +t_pdp_list *pdp_type_to_list(t_pdp_symbol *type); + +/* pdp's (threadsafe) symbol */ +t_pdp_symbol *pdp_gensym(char *s); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/pdp_types.h b/include/pdp_types.h new file mode 100644 index 0000000..b021dd7 --- /dev/null +++ b/include/pdp_types.h @@ -0,0 +1,57 @@ + +/* + * Pure Data Packet header file. Scalar type definitions. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +/* some typedefs and utility classes */ + +#ifndef PDP_TYPES_H +#define PDP_TYPES_H + +typedef signed char s8; +typedef signed short s16; +typedef signed long s32; +typedef signed long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; +typedef unsigned long long u64; + + +#ifndef __cplusplus +typedef int bool; +#define true 1; +#define false 0; +#endif + + +typedef struct _pdp t_pdp; +typedef void (*t_pdp_packet_method1)(t_pdp *); /* dst */ +typedef void (*t_pdp_packet_method2)(t_pdp *, t_pdp *); /* dst, src */ + + + + +/* generic packet subheader */ +//typedef unsigned char t_raw[PDP_SUBHEADER_SIZE]; +typedef unsigned int t_raw; + + +#endif diff --git a/include/pdp_xvideo.h b/include/pdp_xvideo.h new file mode 100644 index 0000000..c395605 --- /dev/null +++ b/include/pdp_xvideo.h @@ -0,0 +1,78 @@ + +/* + * Pure Data Packet header file: xwindow glue code + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +// x stuff +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <X11/extensions/Xv.h> +#include <X11/extensions/Xvlib.h> + +// image formats for communication with the X Server +#define FOURCC_YV12 0x32315659 /* YV12 YUV420P */ +#define FOURCC_YUV2 0x32595559 /* YUV2 YUV422 */ +#define FOURCC_I420 0x30323449 /* I420 Intel Indeo 4 */ + + + +/* xvideo class */ +typedef struct _pdp_xvideo +{ + + t_pdp_xdisplay *xdpy; + t_pdp_xwindow *xwin; + //Display *dpy; + //int screen; + //Window win; + + + + int xv_format; + int xv_port; + + XvImage *xvi; + unsigned char *data; + unsigned int width; + unsigned int height; + int last_encoding; + + int initialized; + +} t_pdp_xvideo; + + +/* cons */ +void pdp_xvideo_init(t_pdp_xvideo *x); +t_pdp_xvideo *pdp_xvideo_new(void); + +/* des */ +void pdp_xvideo_cleanup(t_pdp_xvideo* x); +void pdp_xvideo_free(t_pdp_xvideo* x); + + +/* open an xv port (and create XvImage) */ +int pdp_xvideo_open_on_display(t_pdp_xvideo *x, t_pdp_xdisplay *d); + +/* close xv port (and delete XvImage */ +void pdp_xvideo_close(t_pdp_xvideo* x); + +/* display a packet */ +void pdp_xvideo_display_packet(t_pdp_xvideo *x, t_pdp_xwindow *w, int packet); diff --git a/include/pdp_xwindow.h b/include/pdp_xwindow.h new file mode 100644 index 0000000..1787062 --- /dev/null +++ b/include/pdp_xwindow.h @@ -0,0 +1,122 @@ + +/* + * Pure Data Packet header file: xwindow glue code + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +// x stuff +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include "pdp_list.h" +#include "pdp_mem.h" + +/* x display class */ +typedef struct _pdp_xdisplay +{ + Display *dpy; // the display connection + int screen; // the screen + t_pdp_list *windowlist; // all windows belonging to this connection + // this contains (id, eventlist) + + int dragbutton; + +} t_pdp_xdisplay; + + +/* cons */ +t_pdp_xdisplay *pdp_xdisplay_new(char *dpy_string); + +/* des */ +void pdp_xdisplay_free(t_pdp_xdisplay *d); + +struct _pdp_xwindow; + +void pdp_xdisplay_register_window(t_pdp_xdisplay *d, struct _pdp_xwindow *w); +void pdp_xdisplay_unregister_window(t_pdp_xdisplay *d, struct _pdp_xwindow *w); + +/* x window class */ +typedef struct _pdp_xwindow +{ + //Display *dpy; + //int screen; + t_pdp_xdisplay *xdisplay; // the display object + Window win; // window reference + GC gc; // graphics context + Atom WM_DELETE_WINDOW; + + + int winwidth; // dim states + int winheight; + int winxoffset; + int winyoffset; + + int initialized; + int autocreate; + + char lastbut; // last button pressed (for drag) + + //t_symbol *dragbutton; + + float cursor; + +} t_pdp_xwindow; + +/* cons */ +void pdp_xwindow_init(t_pdp_xwindow *b); +t_pdp_xwindow *pdp_xwindow_new(void); + +/* des */ +void pdp_xwindow_cleanup(t_pdp_xwindow *b); +void pdp_xwindow_free(t_pdp_xwindow *b); + +/* move the pointer */ +void pdp_xwindow_warppointer(t_pdp_xwindow *xwin, int x, int y); + + +/* fullscreen message */ +void pdp_xwindow_fullscreen(t_pdp_xwindow *xwin); + +/* resize window */ +void pdp_xwindow_resize(t_pdp_xwindow *b, int width, int height); + +/* resize window */ +void pdp_xwindow_moveresize(t_pdp_xwindow *b, int xoffset, int yoffset, int width, int height); + +/* fill a tile of the screen */ +void pdp_xwindow_tile(t_pdp_xwindow *xwin, int x_tiles, int y_tiles, int i, int j); + +/* move window */ +void pdp_xwindow_move(t_pdp_xwindow *xwin, int xoffset, int yoffset); + +/* receive events */ +t_pdp_list *pdp_xwindow_get_eventlist(t_pdp_xwindow *xwin); + +/* enable/disable cursor */ +void pdp_xwindow_cursor(t_pdp_xwindow *b, int flag); + +/* create xwindow. return code != NULL on succes */ +int pdp_xwindow_create_on_display(t_pdp_xwindow *b, t_pdp_xdisplay *d); + +/* close window */ +void pdp_xwindow_close(t_pdp_xwindow *b); + +/* set title */ +void pdp_xwindow_title(t_pdp_xwindow *xwin, char *title); + + diff --git a/include/pwc-ioctl.h b/include/pwc-ioctl.h new file mode 100644 index 0000000..4977036 --- /dev/null +++ b/include/pwc-ioctl.h @@ -0,0 +1,176 @@ +#ifndef PWC_IOCTL_H +#define PWC_IOCTL_H + +/* (C) 2001-2002 Nemosoft Unv. webcam@smcc.demon.nl + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* This is pwc-ioctl.h belonging to PWC 8.6 */ + +/* + Changes + 2001/08/03 Alvarado Added ioctl constants to access methods for + changing white balance and red/blue gains + */ + +/* These are private ioctl() commands, specific for the Philips webcams. + They contain functions not found in other webcams, and settings not + specified in the Video4Linux API. + + The #define names are built up like follows: + VIDIOC VIDeo IOCtl prefix + PWC Philps WebCam + G optional: Get + S optional: Set + ... the function + */ + + + + +/* The frame rate is encoded in the video_window.flags parameter using + the upper 16 bits, since some flags are defined nowadays. The following + defines provide a mask and shift to filter out this value. + + In 'Snapshot' mode the camera freezes its automatic exposure and colour + balance controls. + */ +#define PWC_FPS_SHIFT 16 +#define PWC_FPS_MASK 0x00FF0000 +#define PWC_FPS_FRMASK 0x003F0000 +#define PWC_FPS_SNAPSHOT 0x00400000 + + + +struct pwc_probe +{ + char name[32]; + int type; +}; + + +/* pwc_whitebalance.mode values */ +#define PWC_WB_INDOOR 0 +#define PWC_WB_OUTDOOR 1 +#define PWC_WB_FL 2 +#define PWC_WB_MANUAL 3 +#define PWC_WB_AUTO 4 + +/* Used with VIDIOCPWC[SG]AWB (Auto White Balance). + Set mode to one of the PWC_WB_* values above. + *red and *blue are the respective gains of these colour components inside + the camera; range 0..65535 + When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; + otherwise undefined. + 'read_red' and 'read_blue' are read-only. +*/ + +struct pwc_whitebalance +{ + int mode; + int manual_red, manual_blue; /* R/W */ + int read_red, read_blue; /* R/O */ +}; + +/* + 'control_speed' and 'control_delay' are used in automatic whitebalance mode, + and tell the camera how fast it should react to changes in lighting, and + with how much delay. Valid values are 0..65535. +*/ +struct pwc_wb_speed +{ + int control_speed; + int control_delay; + +}; + +/* Used with VIDIOCPWC[SG]LED */ +struct pwc_leds +{ + int led_on; /* Led on-time; range = 0..25000 */ + int led_off; /* Led off-time; range = 0..25000 */ +}; + + + + /* Restore user settings */ +#define VIDIOCPWCRUSER _IO('v', 192) + /* Save user settings */ +#define VIDIOCPWCSUSER _IO('v', 193) + /* Restore factory settings */ +#define VIDIOCPWCFACTORY _IO('v', 194) + + /* You can manipulate the compression factor. A compression preference of 0 + means use uncompressed modes when available; 1 is low compression, 2 is + medium and 3 is high compression preferred. Of course, the higher the + compression, the lower the bandwidth used but more chance of artefacts + in the image. The driver automatically chooses a higher compression when + the preferred mode is not available. + */ + /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */ +#define VIDIOCPWCSCQUAL _IOW('v', 195, int) + /* Get preferred compression quality */ +#define VIDIOCPWCGCQUAL _IOR('v', 195, int) + + + /* This is a probe function; since so many devices are supported, it + becomes difficult to include all the names in programs that want to + check for the enhanced Philips stuff. So in stead, try this PROBE; + it returns a structure with the original name, and the corresponding + Philips type. + To use, fill the structure with zeroes, call PROBE and if that succeeds, + compare the name with that returned from VIDIOCGCAP; they should be the + same. If so, you can be assured it is a Philips (OEM) cam and the type + is valid. + */ +#define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe) + + /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */ +#define VIDIOCPWCSAGC _IOW('v', 200, int) + /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */ +#define VIDIOCPWCGAGC _IOR('v', 200, int) + /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */ +#define VIDIOCPWCSSHUTTER _IOW('v', 201, int) + + /* Color compensation (Auto White Balance) */ +#define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance) +#define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance) + + /* Auto WB speed */ +#define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed) +#define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed) + + /* LEDs on/off/blink; int range 0..65535 */ +#define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds) +#define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds) + + /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */ +#define VIDIOCPWCSCONTOUR _IOW('v', 206, int) +#define VIDIOCPWCGCONTOUR _IOR('v', 206, int) + + /* Backlight compensation; 0 = off, otherwise on */ +#define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int) +#define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int) + + /* Flickerless mode; = 0 off, otherwise on */ +#define VIDIOCPWCSFLICKER _IOW('v', 208, int) +#define VIDIOCPWCGFLICKER _IOR('v', 208, int) + + /* Dynamic noise reduction; 0 off, 3 = high noise reduction */ +#define VIDIOCPWCSDYNNOISE _IOW('v', 209, int) +#define VIDIOCPWCGDYNNOISE _IOR('v', 209, int) + +#endif diff --git a/modules/Makefile b/modules/Makefile new file mode 100644 index 0000000..dfafb76 --- /dev/null +++ b/modules/Makefile @@ -0,0 +1,20 @@ +# build subdirs +current: + make -C generic + make -C image_basic + make -C image_io + make -C image_special + make -C matrix_basic + make -C test + + +clean: + make -C generic clean + make -C image_basic clean + make -C image_io clean + make -C image_special clean + make -C matrix_basic clean + make -C test clean + rm -f *~ + rm -f *.o + diff --git a/modules/README b/modules/README new file mode 100644 index 0000000..54f816c --- /dev/null +++ b/modules/README @@ -0,0 +1,30 @@ +This file describes the protocol used for communicating packets. +See include/pdp.h and the sources in this directory for more info. + +There are 3 kinds of pdp messages: + +[pdp register_ro <packet_id>] +[pdp register_rw <packet_id>] +[pdp process] + +Together they form the pdp protocol. An object can receive a packet +by catching the 3 kinds of messages: + +When a register_ro message is received, the object can call +pdp_packet_copy_ro(packet) to reserve a read only copy for itself. + +The same goes for handling the register_rw message. You can +reserve a read/write copy by using pdp_packet_copy_rw(packet) + +When a process message is received, the object is allowed to start +processing the packet data end send the resulting packet(s) out. + +To send out a packet, use the pdp_packet_pass_if_valid(outlet, &packet) +method. It passes a packet, and sets the reference to -1 (the undefined +packet id). + + +If you want to write pdp externs, consider using the pdp_base object +to derive your object from. Have a look at pdp_add, pdp_gain, pdp_noise +to see how to do this. + diff --git a/modules/generic/Makefile b/modules/generic/Makefile new file mode 100644 index 0000000..035f970 --- /dev/null +++ b/modules/generic/Makefile @@ -0,0 +1,15 @@ +current: all_modules + +include ../../Makefile.config + +PDP_MOD = pdp_reg.o pdp_del.o pdp_snap.o pdp_trigger.o \ + pdp_route.o pdp_inspect.o pdp_loop.o pdp_description.o pdp_convert.o \ + pdp_udp_send.o pdp_udp_receive.o pdp_rawin.o pdp_rawout.o + +# build generic modules +all_modules: $(PDP_MOD) + +clean: + rm -f *~ + rm -f *.o + diff --git a/modules/generic/README b/modules/generic/README new file mode 100644 index 0000000..2c8bff0 --- /dev/null +++ b/modules/generic/README @@ -0,0 +1,2 @@ +This directory contains generic packet processors (i.e. containers). +Should work with any packet type. diff --git a/modules/generic/pdp_convert.c b/modules/generic/pdp_convert.c new file mode 100644 index 0000000..cc7dd8c --- /dev/null +++ b/modules/generic/pdp_convert.c @@ -0,0 +1,104 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" + + +typedef struct pdp_convert_struct +{ + t_object x_obj; + t_symbol *x_type_mask; + t_outlet *x_outlet0; + int x_packet0; + +} t_pdp_convert; + + + +static void pdp_convert_type_mask(t_pdp_convert *x, t_symbol *s) +{ + x->x_type_mask = s; +} + +static void pdp_convert_input_0(t_pdp_convert *x, t_symbol *s, t_floatarg f) +{ + int p = (int)f; + int passes, i; + + if (s== gensym("register_ro")){ + pdp_packet_mark_unused(x->x_packet0); + if (x->x_type_mask->s_name[0]) + x->x_packet0 = pdp_packet_convert_ro(p, pdp_gensym(x->x_type_mask->s_name)); + else + x->x_packet0 = pdp_packet_copy_ro(p); + } + + + if ((s == gensym("process")) && (-1 != x->x_packet0)){ + pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet0); + } +} + + +t_class *pdp_convert_class; + + + +void pdp_convert_free(t_pdp_convert *x) +{ + pdp_packet_mark_unused(x->x_packet0); +} + +void *pdp_convert_new(t_symbol *s) +{ + t_pdp_convert *x = (t_pdp_convert *)pd_new(pdp_convert_class); + + x->x_type_mask = s; + x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + x->x_packet0 = -1; + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_convert_setup(void) +{ + + + pdp_convert_class = class_new(gensym("pdp_convert"), (t_newmethod)pdp_convert_new, + (t_method)pdp_convert_free, sizeof(t_pdp_convert), 0, A_DEFSYMBOL, A_NULL); + + + class_addmethod(pdp_convert_class, (t_method)pdp_convert_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addsymbol(pdp_convert_class, (t_method)pdp_convert_type_mask); + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/generic/pdp_del.c b/modules/generic/pdp_del.c new file mode 100644 index 0000000..4b51023 --- /dev/null +++ b/modules/generic/pdp_del.c @@ -0,0 +1,193 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" + + +typedef struct pdp_del_struct +{ + t_object x_obj; + t_float x_f; + + t_outlet *x_outlet0; + + t_outlet **x_outlet; + + int *x_packet; + int x_order; + int x_head; + int x_delay; +} t_pdp_del; + + + + + +static void pdp_del_input_0(t_pdp_del *x, t_symbol *s, t_floatarg f) +{ + int in; + int out; + int packet; + + /* if this is a register_ro message or register_rw message, register with packet factory */ + /* if this is a process message, start the processing + propagate stuff to outputs */ + + if (s == gensym("register_ro")){ + in = (x->x_head % x->x_order); + //post("pdp_del: marking unused packed id=%d on loc %d", x->x_packet[0], in); + pdp_packet_mark_unused(x->x_packet[in]); + packet = pdp_packet_copy_ro((int)f); + + + // TODO TODO TODO !!!! + + //pdp_packet_print_debug((int)f); + + + + + x->x_packet[in] = packet; + //post("pdp_del: writing packed id=%d on loc %d", packet, in); + } + else if (s == gensym("process")){ + out = (((x->x_head + x->x_delay)) % x->x_order); + packet = x->x_packet[out]; + pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet[out]); + +/* + if (-1 != packet){ + //post("pdp_del: packet %d has id %d", out, packet); + pdp_packet_mark_unused(packet); + outlet_pdp(x->x_outlet0, packet); + x->x_packet[out] = -1; + } + + + else { + //post("pdp_del: packet %d is empty", out); + } +*/ + + x->x_head = (x->x_head + x->x_order - 1) % x->x_order; + } + + +} + + + + + +static void pdp_del_delay(t_pdp_del *x, t_floatarg fdel) +{ + int del = (int)fdel; + if (del < 0) del = 0; + if (del >= x->x_order) del = x->x_order - 1; + + x->x_delay = del; + +} + +static void pdp_del_reset(t_pdp_del *x) +{ + int i; + for (i=0; i<x->x_order; i++) { + pdp_packet_mark_unused(x->x_packet[i]); + x->x_packet[i] = -1; + } + x->x_head = 0; + +} + +static void pdp_del_debug(t_pdp_del *x) +{ + int i; + post ("order %d", x->x_order); + post ("delay %d", x->x_delay); + post ("head %d", x->x_head); + for (i=0; i<x->x_order; i++) { + post("%d ", x->x_packet[i]); + } +} + +static void pdp_del_free(t_pdp_del *x) +{ + pdp_del_reset(x); + pdp_dealloc (x->x_packet); +} + +t_class *pdp_del_class; + + + +void *pdp_del_new(t_floatarg forder, t_floatarg fdel) +{ + int order = (int)forder; + int del; + int logorder; + int i; + t_pdp_del *x = (t_pdp_del *)pd_new(pdp_del_class); + + del = order; + order++; + + if (del < 0) del = 0; + if (order <= 2) order = 2; + + //post("pdp_del: order = %d", order); + + x->x_order = order; + x->x_packet = (int *)pdp_alloc(sizeof(int)*order); + for(i=0; i<order; i++) x->x_packet[i] = -1; + x->x_delay = del; + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("delay")); + x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_del_setup(void) +{ + + + pdp_del_class = class_new(gensym("pdp_del"), (t_newmethod)pdp_del_new, + (t_method)pdp_del_free, sizeof(t_pdp_del), 0, A_DEFFLOAT, A_NULL); + + class_addmethod(pdp_del_class, (t_method)pdp_del_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_del_class, (t_method)pdp_del_delay, gensym("delay"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_del_class, (t_method)pdp_del_reset, gensym("reset"), A_NULL); + + class_addmethod(pdp_del_class, (t_method)pdp_del_debug, gensym("_debug"), A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/generic/pdp_description.c b/modules/generic/pdp_description.c new file mode 100644 index 0000000..4f2ff13 --- /dev/null +++ b/modules/generic/pdp_description.c @@ -0,0 +1,98 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" + + + +typedef struct pdp_description_struct +{ + t_object x_obj; + t_outlet *x_outlet; + +} t_pdp_description; + + + + +static void pdp_description_input_pdp(t_pdp_description *x, t_symbol *s, t_floatarg f) +{ + int p = (int)f; + t_symbol *rro = S_REGISTER_RO; + + if (rro == s){ + outlet_symbol(x->x_outlet, gensym(pdp_packet_get_description(p)->s_name)); + } +} + +static void pdp_description_input_dpd(t_pdp_description *x, t_symbol *s, t_floatarg f) +{ + int p = (int)f; + t_symbol *ins = S_INSPECT; + + if (ins == s){ + outlet_symbol(x->x_outlet, gensym(pdp_packet_get_description(p)->s_name)); + } +} + + +static void pdp_description_free(t_pdp_description *x) +{ + +} + +t_class *pdp_description_class; + + + +static void *pdp_description_new(t_symbol *s, int argc, t_atom *argv) +{ + t_pdp_description *x = (t_pdp_description *)pd_new(pdp_description_class); + + x->x_outlet = outlet_new(&x->x_obj, &s_symbol); + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_description_setup(void) +{ + + + pdp_description_class = class_new(gensym("pdp_description"), (t_newmethod)pdp_description_new, + (t_method)pdp_description_free, sizeof(t_pdp_description), 0, A_NULL); + + class_addmethod(pdp_description_class, (t_method)pdp_description_input_pdp, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_description_class, (t_method)pdp_description_input_dpd, gensym("dpd"), A_SYMBOL, A_DEFFLOAT, A_NULL); + + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/generic/pdp_inspect.c b/modules/generic/pdp_inspect.c new file mode 100644 index 0000000..b669475 --- /dev/null +++ b/modules/generic/pdp_inspect.c @@ -0,0 +1,124 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" + +/* adapted from the pd trigger object */ + +#define TR_BANG 0 +#define TR_FLOAT 1 +#define TR_SYMBOL 2 +#define TR_POINTER 3 +#define TR_LIST 4 +#define TR_ANYTHING 5 +#define TR_PDP 6 + +/* + +$$$TODO: emplement so that it behaves like the standard trigger object + +i.e. [trigger bang pdp pdp bang pdp] + +register_ro and register_rw messages pass right trough, +since they're not action events, only configure events. +a bang is made equivalent to a process event. + +*/ + +typedef struct pdp_inspect_struct +{ + t_object x_obj; + t_float x_f; + + t_outlet *x_outlet; + +} t_pdp_inspect; + + + + +static void pdp_inspect_input_0(t_pdp_inspect *x, t_symbol *s, t_floatarg f) +{ + t_atom atom[2]; + t_symbol *pdp = gensym("pdp"); + t_symbol *prc = gensym("process"); + t_symbol *rro = gensym("register_ro"); + int i; + + + /* if there is a reg_ro, shortcut the right outlet */ + if (s == rro){ + SETSYMBOL(atom+0, s); + SETFLOAT(atom+1, f); + outlet_anything(x->x_outlet, pdp, 2, atom); + SETSYMBOL(atom+0, prc); + outlet_anything(x->x_outlet, pdp, 1, atom); + } + + +} + + + +static void pdp_inspect_free(t_pdp_inspect *x) +{ + +} + +t_class *pdp_inspect_class; + + + +static void *pdp_inspect_new(void) +{ + t_pdp_inspect *x = (t_pdp_inspect *)pd_new(pdp_inspect_class); + + + x->x_outlet = outlet_new(&x->x_obj, &s_anything); + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_inspect_setup(void) +{ + + + pdp_inspect_class = class_new(gensym("pdp_inspect_ro"), (t_newmethod)pdp_inspect_new, + (t_method)pdp_inspect_free, sizeof(t_pdp_inspect), 0, A_GIMME, A_NULL); + + class_addcreator((t_newmethod)pdp_inspect_new, gensym("pdp_t"), A_GIMME, 0); + + class_addmethod(pdp_inspect_class, (t_method)pdp_inspect_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/generic/pdp_loop.c b/modules/generic/pdp_loop.c new file mode 100644 index 0000000..259eb8f --- /dev/null +++ b/modules/generic/pdp_loop.c @@ -0,0 +1,296 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +/* + + pdp_loop: a looping packet delay line + messages: + record x: start recording at position x (default = 0) + stop: stop recording + float: output packet at position + bang: output next packet + rewind: rewind + loop: set looping mode + +*/ + + +#include "pdp.h" +#include "pdp_internals.h" + + +typedef struct pdp_loop_struct +{ + t_object x_obj; + t_float x_f; + + t_outlet *x_outlet0; + t_outlet *x_outlet1; + + int *x_packet; + int x_order; /* size of the packet loop */ + int x_play_head; /* next position to play back */ + int x_record_head; /* next position to record to */ + + int x_loop; + int x_recording_frames; /* nb frames left to record */ + //int x_recording_shot; /* single frame recording is on */ +} t_pdp_loop; + + + + + +static void pdp_loop_input_0(t_pdp_loop *x, t_symbol *s, t_floatarg f) +{ + int in; + int out; + int packet; + + + /* if recording is off, ignore packet */ + if ((!x->x_recording_frames)) return; + + /* store a packet on register ro */ + if (s == gensym("register_ro")){ + + /* delete old & store new */ + in = x->x_record_head; //% x->x_order; + pdp_packet_mark_unused(x->x_packet[in]); + packet = pdp_packet_copy_ro((int)f); + x->x_packet[in] = packet; + + /* advance head & decrease record counter */ + x->x_recording_frames--; + x->x_record_head++; + + /* turn off recording if we are at the end */ + if (x->x_record_head == x->x_order) x->x_recording_frames = 0; + } +} + + +static void pdp_loop_bang(t_pdp_loop *x){ + int out; + int packet; + + out = x->x_play_head; + + /* don't play if we're at the end of the sequence and looping is disabled */ + if ((!x->x_loop) && (out >= x->x_order)) return; + + /* wrap index */ + out %= x->x_order; + + /* output the current packet */ + packet = x->x_packet[out]; + outlet_float(x->x_outlet1, (float)out); // output location + if (-1 != packet) outlet_pdp(x->x_outlet0, packet); // output packet + + /* advance playback head */ + x->x_play_head++; + +} + + + + + + +static void pdp_loop_reset(t_pdp_loop *x) +{ + int i; + for (i=0; i<x->x_order; i++) { + pdp_packet_mark_unused(x->x_packet[i]); + x->x_packet[i] = -1; + } + x->x_play_head = 0; + x->x_record_head = 0; + +} + +static void pdp_loop_record(t_pdp_loop *x, t_floatarg fstart, t_floatarg fdur) +{ + int istart = (int)fstart; + int idur = (int)fdur; + istart %= x->x_order; + if (istart<0) istart+= x->x_order; + if (idur <= 0) idur = x->x_order - istart; + + x->x_record_head = istart; + x->x_recording_frames = idur; +} + +static void pdp_loop_store(t_pdp_loop *x, t_floatarg f) +{ + int i = (int)f; + i %= x->x_order; + if (i<0) i+= x->x_order; + + x->x_record_head = i; + x->x_recording_frames = 1; +} + +static void pdp_loop_seek(t_pdp_loop *x, t_floatarg f) +{ + int i = (int)f; + i %= x->x_order; + if (i<0) i+= x->x_order; + + x->x_play_head = i; +} + +static void pdp_loop_seek_hot(t_pdp_loop *x, t_floatarg f) +{ + pdp_loop_seek(x, f); + pdp_loop_bang(x); +} + + +static void pdp_loop_stop(t_pdp_loop *x) +{ + x->x_recording_frames = 0; +} + +static void pdp_loop_loop(t_pdp_loop *x, t_floatarg f) +{ + if (f == 0.0f) x->x_loop = 0; + if (f == 1.0f) x->x_loop = 1; + +} +static void pdp_loop_free(t_pdp_loop *x) +{ + pdp_loop_reset(x); + pdp_dealloc (x->x_packet); +} + +static int pdp_loop_realsize(float f) +{ + int order = (int)f; + if (order <= 2) order = 2; + return order; +} + + +static void pdp_loop_resize(t_pdp_loop *x, t_floatarg f) +{ + int i; + int order = pdp_loop_realsize(f); + int *newloop; + + /* if size didn't change, do nothing */ + if (x->x_order == order) return; + + /* create new array */ + newloop = (int *)pdp_alloc(sizeof(int) * order); + + + /* extend it */ + if (x->x_order < order){ + + /* copy old packets */ + for (i=0; i<x->x_order; i++) newloop[i] = x->x_packet[i]; + + /* loop extend the rest */ + for (i=x->x_order; i<order; i++) newloop[i] = pdp_packet_copy_ro(x->x_packet[i % x->x_order]); + + } + + /* or shrink it */ + else { + /* copy part of old packets */ + for (i=0; i<order; i++) newloop[i] = x->x_packet[i]; + + /* delete the other part of old packets */ + for (i=order; i<x->x_order; i++) pdp_packet_mark_unused(x->x_packet[i]); + + /* adjust heads */ + x->x_play_head %= order; + x->x_record_head %= order; + + } + + /* delete old line & store new */ + pdp_dealloc (x->x_packet); + x->x_packet = newloop; + x->x_order = order; + + +} + + +t_class *pdp_loop_class; + + + +void *pdp_loop_new(t_floatarg f) +{ + int i; + int order = pdp_loop_realsize(f); + t_pdp_loop *x = (t_pdp_loop *)pd_new(pdp_loop_class); + + x->x_order = order; + x->x_packet = (int *)pdp_alloc(sizeof(int)*order); + for(i=0; i<order; i++) x->x_packet[i] = -1; + + x->x_play_head = 0; + x->x_record_head = 0; + x->x_recording_frames = 0; + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("seek")); + x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + x->x_outlet1 = outlet_new(&x->x_obj, &s_anything); + + x->x_loop = 1; + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_loop_setup(void) +{ + + + pdp_loop_class = class_new(gensym("pdp_loop"), (t_newmethod)pdp_loop_new, + (t_method)pdp_loop_free, sizeof(t_pdp_loop), 0, A_DEFFLOAT, A_NULL); + + class_addmethod(pdp_loop_class, (t_method)pdp_loop_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_loop_class, (t_method)pdp_loop_record, gensym("record"), A_DEFFLOAT, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_loop_class, (t_method)pdp_loop_store, gensym("store"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_loop_class, (t_method)pdp_loop_reset, gensym("reset"), A_NULL); + class_addmethod(pdp_loop_class, (t_method)pdp_loop_bang, gensym("bang"), A_NULL); + class_addmethod(pdp_loop_class, (t_method)pdp_loop_stop, gensym("stop"), A_NULL); + class_addmethod(pdp_loop_class, (t_method)pdp_loop_seek, gensym("seek"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_loop_class, (t_method)pdp_loop_resize, gensym("size"), A_FLOAT, A_NULL); + class_addmethod(pdp_loop_class, (t_method)pdp_loop_loop, gensym("loop"), A_FLOAT, A_NULL); + class_addfloat(pdp_loop_class, (t_method)pdp_loop_seek_hot); + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/generic/pdp_rawin.c b/modules/generic/pdp_rawin.c new file mode 100644 index 0000000..28ef8fb --- /dev/null +++ b/modules/generic/pdp_rawin.c @@ -0,0 +1,299 @@ +/* + * Pure Data Packet module. packet forth console + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <time.h> +#include <fcntl.h> +#include "pdp_pd.h" +#include "pdp_debug.h" +#include "pdp_list.h" +#include "pdp_comm.h" +#include "pdp_post.h" +#include "pdp_packet.h" + + +#define PERIOD 1.0f +#define D if (1) + + + + +/* raw input from a unix pipe */ + +typedef struct rawin_struct +{ + /* pd */ + t_object x_obj; + t_outlet *x_outlet; + t_outlet *x_sync_outlet; + t_clock *x_clock; + + /* comm */ + t_pdp_list *x_queue; // packet queue + + /* thread */ + pthread_mutex_t x_mut; + pthread_attr_t x_attr; + pthread_t x_thread; + + /* sync */ + int x_giveup; // 1-> terminate reader thread + int x_active; // 1-> reader thread is launched + int x_done; // 1-> reader thread has exited + + /* config */ + t_symbol *x_pipe; + t_pdp_symbol *x_type; + +} t_rawin; + + +static inline void lock(t_rawin *x){pthread_mutex_lock(&x->x_mut);} +static inline void unlock(t_rawin *x){pthread_mutex_unlock(&x->x_mut);} + +static void rawin_close(t_rawin *x); +static void tick(t_rawin *x) +{ + /* send all packets in queue to outlet */ + lock(x); + while (x->x_queue->elements){ + outlet_pdp_atom(x->x_outlet, x->x_queue->first); + pdp_list_pop(x->x_queue); // pop stale reference + } + unlock(x); + clock_delay(x->x_clock, PERIOD); + + /* check if thread is done */ + if (x->x_done) rawin_close(x); + +} + +static void move_current_to_queue(t_rawin *x, int packet) +{ + lock(x); + pdp_list_add_back(x->x_queue, a_packet, (t_pdp_word)packet); + unlock(x); +} + +static void *rawin_thread(void *y) +{ + int pipe; + int packet = -1; + t_rawin *x = (t_rawin *)y; + int period_sec; + int period_usec; + + + //D pdp_post("pipe: %s", x->x_pipe->s_name); + //D pdp_post("type: %s", x->x_type->s_name); + + /* open pipe */ + if (-1 == (pipe = open(x->x_pipe->s_name, O_RDONLY|O_NONBLOCK))){ + perror(x->x_pipe->s_name); + goto exit; + } + + /* main loop (packets) */ + while(1){ + void *data = 0; + int left = -1; + + /* create packet */ + if (-1 != packet){ + pdp_post("WARNING: deleting stale packet"); + pdp_packet_mark_unused(packet); + } + packet = pdp_factory_newpacket(x->x_type); + if (-1 == packet){ + pdp_post("ERROR: can't create packet. type = %s", x->x_type->s_name); + goto exit; + } + + /* fill packet */ + data = pdp_packet_data(packet); + left = pdp_packet_data_size(packet); + // D pdp_post("packet %d, data %x, size %d", packet, data, left); + + /* inner loop: pipe reads */ + while(left){ + + fd_set inset; + struct timeval tv = {0,10000}; + + /* check if we need to stop */ + if (x->x_giveup){ + pdp_packet_mark_unused(packet); + goto close; + } + /* select, with timeout */ + FD_ZERO(&inset); + FD_SET(pipe, &inset); + if (-1 == select(pipe+1, &inset, NULL,NULL, &tv)){ + pdp_post("select error"); + goto close; + } + + /* if ready, read, else retry */ + if (FD_ISSET(pipe, &inset)){ + int bytes = read(pipe, data, left); + if (!bytes){ + /* if no bytes are read, pipe is closed */ + goto close; + } + data += bytes; + left -= bytes; + } + } + + /* move to queue */ + move_current_to_queue(x, packet); + packet = -1; + + + + } + + close: + /* close pipe */ + close(pipe); + + + exit: + x->x_done = 1; + return 0; +} + + + +static void rawin_type(t_rawin *x, t_symbol *type) +{ + x->x_type = pdp_gensym(type->s_name); +} + +static void rawin_open(t_rawin *x, t_symbol *pipe) +{ + /* save pipe name if not empty */ + if (pipe->s_name[0]) {x->x_pipe = pipe;} + + if (x->x_active) { + pdp_post("already open"); + return; + } + /* start thread */ + x->x_giveup = 0; + x->x_done = 0; + pthread_create(&x->x_thread, &x->x_attr, rawin_thread , x); + x->x_active = 1; +} + +static void rawin_close(t_rawin *x) +{ + + if (!x->x_active) return; + + /* stop thread: set giveup + wait */ + x->x_giveup = 1; + pthread_join(x->x_thread, NULL); + x->x_active = 0; + + /* notify */ + outlet_bang(x->x_sync_outlet); + pdp_post("connection to %s closed", x->x_pipe->s_name); + + + + + +} + +static void rawin_free(t_rawin *x) +{ + rawin_close(x); + clock_free(x->x_clock); + pdp_tree_strip_packets(x->x_queue); + pdp_tree_free(x->x_queue); +} + +t_class *rawin_class; + + +static void *rawin_new(t_symbol *pipe, t_symbol *type) +{ + t_rawin *x; + + pdp_post("%s %s", pipe->s_name, type->s_name); + + /* allocate & init */ + x = (t_rawin *)pd_new(rawin_class); + x->x_outlet = outlet_new(&x->x_obj, &s_anything); + x->x_sync_outlet = outlet_new(&x->x_obj, &s_anything); + x->x_clock = clock_new(x, (t_method)tick); + x->x_queue = pdp_list_new(0); + x->x_active = 0; + x->x_giveup = 0; + x->x_done = 0; + x->x_type = pdp_gensym("image/YCrCb/320x240"); //default + x->x_pipe = gensym("/tmp/pdpraw"); // default + pthread_attr_init(&x->x_attr); + pthread_mutex_init(&x->x_mut, NULL); + clock_delay(x->x_clock, PERIOD); + + /* args */ + rawin_type(x, type); + if (pipe->s_name[0]) x->x_pipe = pipe; + + return (void *)x; + +} + + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_rawin_setup(void) +{ + int i; + + /* create a standard pd class: [pdp_rawin pipe type] */ + rawin_class = class_new(gensym("pdp_rawin"), (t_newmethod)rawin_new, + (t_method)rawin_free, sizeof(t_rawin), 0, A_DEFSYMBOL, A_DEFSYMBOL, A_NULL); + + /* add global message handler */ + class_addmethod(rawin_class, (t_method)rawin_type, gensym("type"), A_SYMBOL, A_NULL); + class_addmethod(rawin_class, (t_method)rawin_open, gensym("open"), A_DEFSYMBOL, A_NULL); + class_addmethod(rawin_class, (t_method)rawin_close, gensym("close"), A_NULL); + + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/generic/pdp_rawout.c b/modules/generic/pdp_rawout.c new file mode 100644 index 0000000..e1e9edf --- /dev/null +++ b/modules/generic/pdp_rawout.c @@ -0,0 +1,320 @@ +/* + * Pure Data Packet module. packet forth console + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <time.h> +#include <fcntl.h> +#include <errno.h> +#include <signal.h> +#include "pdp_pd.h" +#include "pdp_debug.h" +#include "pdp_list.h" +#include "pdp_comm.h" +#include "pdp_post.h" +#include "pdp_packet.h" + + +#define D if (1) +#define MAX_QUEUESIZE 4 +#define PIPE_BLOCKSIZE 4096 + + + + +/* raw input from a unix pipe */ + +typedef struct rawout_struct +{ + /* pd */ + t_object x_obj; + //t_outlet *x_outlet; + t_outlet *x_sync_outlet; + + /* comm */ + t_pdp_list *x_queue; // packet queue + + /* thread */ + pthread_mutex_t x_mut; + pthread_attr_t x_attr; + pthread_t x_thread; + + /* sync */ + int x_giveup; // 1-> terminate writer thread + int x_active; // 1-> writer thread is launched + int x_done; // 1-> writer thread has exited + + /* config */ + t_symbol *x_pipe; + t_pdp_symbol *x_type; + +} t_rawout; + + +static inline void lock(t_rawout *x){pthread_mutex_lock(&x->x_mut);} +static inline void unlock(t_rawout *x){pthread_mutex_unlock(&x->x_mut);} + +static void rawout_close(t_rawout *x); +static void pdp_in(t_rawout *x, t_symbol *s, t_float f) +{ + /* save packet to pdp queue, if size is smaller than maxsize */ + if (s == S_REGISTER_RO){ + if (x->x_queue->elements < MAX_QUEUESIZE){ + int p = (int)f; + p = pdp_packet_copy_ro(p); + if (p != -1){ + lock(x); + pdp_list_add_back(x->x_queue, a_packet, (t_pdp_word)p); + unlock(x); + } + } + else { + pdp_post("pdp_rawout: dropping packet: (queue full)", MAX_QUEUESIZE); + } + + } + + /* check if thread is done */ + if (x->x_done) rawout_close(x); + +} + + + +static void *rawout_thread(void *y) +{ + int pipe; + int packet = -1; + t_rawout *x = (t_rawout *)y; + int period_sec; + int period_usec; + sigset_t sigvec; /* signal handling */ + + /* ignore pipe signal */ + sigemptyset(&sigvec); + sigaddset(&sigvec,SIGPIPE); + pthread_sigmask(SIG_BLOCK, &sigvec, 0); + + //D pdp_post("pipe: %s", x->x_pipe->s_name); + //D pdp_post("type: %s", x->x_type->s_name); + + /* open pipe */ + if (-1 == (pipe = open(x->x_pipe->s_name, O_WRONLY|O_NONBLOCK))){ + perror(x->x_pipe->s_name); + goto exit; + } + + /* main loop (packets) */ + while(1){ + void *data = 0; + int left = -1; + + /* try again if queue is empty */ + if (!x->x_queue->elements){ + /* check if we need to stop */ + if (x->x_giveup){ + goto close; + } + else { + usleep(1000.0f); // sleep before polling again + continue; + } + } + /* get packet from queue */ + lock(x); + packet = pdp_list_pop(x->x_queue).w_packet; + unlock(x); + + /* send packet */ + data = pdp_packet_data(packet); + left = pdp_packet_data_size(packet); + + /* inner loop: pipe reads */ + while(left){ + + fd_set outset; + struct timeval tv = {0,10000}; + + /* check if we need to stop */ + if (x->x_giveup){ + pdp_packet_mark_unused(packet); + goto close; + } + + /* select, with timeout */ + FD_ZERO(&outset); + FD_SET(pipe, &outset); + if (-1 == select(pipe+1, NULL, &outset, NULL, &tv)){ + pdp_post("select error"); + goto close; + } + + /* if ready, read, else retry */ + if (FD_ISSET(pipe, &outset)){ + int bytes = write(pipe, data, left); + /* handle errors */ + if (bytes <= 0){ + perror(x->x_pipe->s_name); + if (bytes != EAGAIN) goto close; + } + /* or update pointers */ + else{ + data += bytes; + left -= bytes; + //pdp_post("left %d", left); + } + } + else { + //pdp_post("retrying write"); + } + } + + /* discard packet */ + pdp_packet_mark_unused(packet); + + + } + + close: + /* close pipe */ + close(pipe); + + + exit: + x->x_done = 1; + return 0; +} + + + +static void rawout_type(t_rawout *x, t_symbol *type) +{ + x->x_type = pdp_gensym(type->s_name); +} + +static void rawout_open(t_rawout *x, t_symbol *pipe) +{ + /* save pipe name if not empty */ + if (pipe->s_name[0]) {x->x_pipe = pipe;} + + if (x->x_active) { + pdp_post("already open"); + return; + } + /* start thread */ + x->x_giveup = 0; + x->x_done = 0; + pthread_create(&x->x_thread, &x->x_attr, rawout_thread , x); + x->x_active = 1; +} + +static void rawout_close(t_rawout *x) +{ + + if (!x->x_active) return; + + /* stop thread: set giveup + wait */ + x->x_giveup = 1; + pthread_join(x->x_thread, NULL); + x->x_active = 0; + + /* notify */ + outlet_bang(x->x_sync_outlet); + pdp_post("connection to %s closed", x->x_pipe->s_name); + + + + + +} + +static void rawout_free(t_rawout *x) +{ + rawout_close(x); + pdp_tree_strip_packets(x->x_queue); + pdp_tree_free(x->x_queue); +} + +t_class *rawout_class; + + +static void *rawout_new(t_symbol *pipe, t_symbol *type) +{ + t_rawout *x; + + pdp_post("%s %s", pipe->s_name, type->s_name); + + /* allocate & init */ + x = (t_rawout *)pd_new(rawout_class); + //x->x_outlet = outlet_new(&x->x_obj, &s_anything); + x->x_sync_outlet = outlet_new(&x->x_obj, &s_anything); + x->x_queue = pdp_list_new(0); + x->x_active = 0; + x->x_giveup = 0; + x->x_done = 0; + x->x_type = pdp_gensym("image/YCrCb/320x240"); //default + x->x_pipe = gensym("/tmp/pdpraw"); // default + pthread_attr_init(&x->x_attr); + pthread_mutex_init(&x->x_mut, NULL); + + /* args */ + rawout_type(x, type); + if (pipe->s_name[0]) x->x_pipe = pipe; + + return (void *)x; + +} + + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_rawout_setup(void) +{ + int i; + + /* create a standard pd class: [pdp_rawout pipe type] */ + rawout_class = class_new(gensym("pdp_rawout"), (t_newmethod)rawout_new, + (t_method)rawout_free, sizeof(t_rawout), 0, A_DEFSYMBOL, A_DEFSYMBOL, A_NULL); + + /* add global message handler */ + class_addmethod(rawout_class, (t_method)pdp_in, + gensym("pdp"), A_SYMBOL, A_FLOAT, A_NULL); + + class_addmethod(rawout_class, (t_method)rawout_type, gensym("type"), A_SYMBOL, A_NULL); + class_addmethod(rawout_class, (t_method)rawout_open, gensym("open"), A_DEFSYMBOL, A_NULL); + class_addmethod(rawout_class, (t_method)rawout_close, gensym("close"), A_NULL); + + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/generic/pdp_reg.c b/modules/generic/pdp_reg.c new file mode 100644 index 0000000..2ad15a6 --- /dev/null +++ b/modules/generic/pdp_reg.c @@ -0,0 +1,170 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_png.h" +#include "pdp_internals.h" + + +typedef struct pdp_reg_struct +{ + t_object x_obj; + t_float x_f; + + t_outlet *x_outlet0; + + int x_packet0; + +} t_pdp_reg; + + +static void pdp_reg_load_png(t_pdp_reg *x, t_symbol *s) +{ + int packet; + //post("sym: %s", s->s_name); + packet = pdp_packet_bitmap_from_png_file(s->s_name); + if (-1 == packet){ + post("pdp_reg: error loading png file %s", s->s_name); + } + else{ + pdp_packet_mark_unused(x->x_packet0); + x->x_packet0 = packet; + } + +} + +static void pdp_reg_save_png(t_pdp_reg *x, t_symbol *s) +{ + int newpacket = pdp_packet_convert_ro(x->x_packet0, pdp_gensym("bitmap/*/*")); + + if (-1 == newpacket){ + post("pdp_reg: nothing to save"); + return; + } + + if (!(pdp_packet_bitmap_save_png_file(newpacket, s->s_name))){ + post("pdp_reg: error saving png file %s", s->s_name); + } + + pdp_packet_mark_unused(newpacket); + +} + + +static void pdp_reg_bang(t_pdp_reg *x) +{ + + if (-1 != x->x_packet0) outlet_pdp(x->x_outlet0, x->x_packet0); + +} + + + +static void pdp_reg_input_0(t_pdp_reg *x, t_symbol *s, t_floatarg f) +{ + + /* if this is a register_ro message or register_rw message, register with packet factory */ + + /* if this is a process message, start the processing + propagate stuff to outputs */ + + if (s == gensym("register_ro")){ + pdp_packet_mark_unused(x->x_packet0); + x->x_packet0 = pdp_packet_copy_ro((int)f); + //post("in0ro: requested %d, got %d", (int)f, x->x_packet0); + } + else if (s == gensym("process")){ + pdp_reg_bang(x); + + } + + +} + + +static void pdp_reg_input_1(t_pdp_reg *x, t_symbol *s, t_floatarg f) +{ + + /* if this is a register_ro message or register_rw message, register with packet factory */ + + /* if this is a process message, start the processing + propagate stuff to outputs */ + + if (s == gensym("register_ro")){ + pdp_packet_mark_unused(x->x_packet0); + x->x_packet0 = pdp_packet_copy_ro((int)f); + //post("in0ro: requested %d, got %d", (int)f, x->x_packet0); + } + +} + + + +static void pdp_reg_free(t_pdp_reg *x) +{ + pdp_packet_mark_unused(x->x_packet0); + +} + +t_class *pdp_reg_class; + + + +void *pdp_reg_new(void) +{ + t_pdp_reg *x = (t_pdp_reg *)pd_new(pdp_reg_class); + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1")); + + x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + + x->x_packet0 = -1; + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_reg_setup(void) +{ + + + pdp_reg_class = class_new(gensym("pdp_reg"), (t_newmethod)pdp_reg_new, + (t_method)pdp_reg_free, sizeof(t_pdp_reg), 0, A_NULL); + + + class_addmethod(pdp_reg_class, (t_method)pdp_reg_bang, gensym("bang"), A_NULL); + + class_addmethod(pdp_reg_class, (t_method)pdp_reg_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_reg_class, (t_method)pdp_reg_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL); + + class_addmethod(pdp_reg_class, (t_method)pdp_reg_save_png, gensym("save_png"), A_SYMBOL, A_NULL); + class_addmethod(pdp_reg_class, (t_method)pdp_reg_load_png, gensym("load_png"), A_SYMBOL, A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/generic/pdp_route.c b/modules/generic/pdp_route.c new file mode 100644 index 0000000..c410d1f --- /dev/null +++ b/modules/generic/pdp_route.c @@ -0,0 +1,146 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_internals.h" + +// dynamic ???? +#define PDP_ROUTE_MAX_NB_OUTLETS 100 + +typedef struct pdp_route_struct +{ + t_object x_obj; + t_float x_f; + + t_outlet *x_outlet[PDP_ROUTE_MAX_NB_OUTLETS]; + + int x_nb_outlets; + int x_route; + int x_route_next; + + +} t_pdp_route; + + +static void pdp_route_input_0(t_pdp_route *x, t_symbol *s, t_floatarg f) +{ + t_atom atom[2]; + t_symbol *pdp = gensym("pdp"); + + + /* trigger on register_ro */ + if (s == gensym("register_ro")){ + x->x_route = x->x_route_next; + } + + /* propagate the pdp message */ + SETSYMBOL(atom+0, s); + SETFLOAT(atom+1, f); + outlet_anything(x->x_outlet[x->x_route], pdp, 2, atom); + +} + +static void pdp_route_input_0_dpd(t_pdp_route *x, t_symbol *s, t_floatarg f) +{ + + /* trigger on accumulate */ + if (s == gensym("accumulate")){ + x->x_route = x->x_route_next; + } + + /* propagate the dpd message */ + outlet_dpd(x->x_outlet[x->x_route], (int)f); + +} + + + +static void pdp_route_route(t_pdp_route *x, t_floatarg f) +{ + int route = (int)f; + + if (route < 0) route = 0; + if (route >= x->x_nb_outlets) route = x->x_nb_outlets - 1; + + x->x_route_next = route; + +} + + + +static void pdp_route_free(t_pdp_route *x) +{ + +} + +t_class *pdp_route_class; + + + +void *pdp_route_new(t_floatarg f) +{ + int nboutlets = (int)f; + int i; + + t_pdp_route *x = (t_pdp_route *)pd_new(pdp_route_class); + + + if (nboutlets < 2) nboutlets = 2; + if (nboutlets >= PDP_ROUTE_MAX_NB_OUTLETS) nboutlets = PDP_ROUTE_MAX_NB_OUTLETS - 1; + + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("route")); + + x->x_nb_outlets = nboutlets; + x->x_route = 0; + x->x_route_next = 0; + + for (i=0; i<nboutlets; i++) + x->x_outlet[i] = outlet_new(&x->x_obj, &s_anything); + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_route_setup(void) +{ + + + pdp_route_class = class_new(gensym("pdp_route"), (t_newmethod)pdp_route_new, + (t_method)pdp_route_free, sizeof(t_pdp_route), 0, A_DEFFLOAT, A_NULL); + + + class_addmethod(pdp_route_class, (t_method)pdp_route_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_route_class, (t_method)pdp_route_input_0_dpd, gensym("dpd"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_route_class, (t_method)pdp_route_route, gensym("route"), A_DEFFLOAT, A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/generic/pdp_snap.c b/modules/generic/pdp_snap.c new file mode 100644 index 0000000..73ec26c --- /dev/null +++ b/modules/generic/pdp_snap.c @@ -0,0 +1,120 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_internals.h" + +typedef struct pdp_snap_struct +{ + t_object x_obj; + t_float x_f; + + t_outlet *x_outlet0; + + int x_packet0; + bool x_snapnext; + +} t_pdp_snap; + + +static void pdp_snap_bang(t_pdp_snap *x) +{ + + if (-1 != x->x_packet0) + outlet_pdp(x->x_outlet0, x->x_packet0); + +} + + + + +static void pdp_snap_input_1(t_pdp_snap *x, t_symbol *s, t_floatarg f) +{ + + /* if this is a register_ro message or register_rw message, register with packet factory */ + + /* if this is a process message, start the processing + propagate stuff to outputs */ + + if (s == gensym("register_ro")){ + if(x->x_snapnext) { + pdp_packet_mark_unused(x->x_packet0); + x->x_packet0 = pdp_packet_copy_ro((int)f); + x->x_snapnext = false; + } + } + +} + +static void pdp_snap_snap(t_pdp_snap *x) +{ + x->x_snapnext = true; +} + +static void pdp_snap_free(t_pdp_snap *x) +{ + pdp_packet_mark_unused(x->x_packet0); + +} + +t_class *pdp_snap_class; + + + +void *pdp_snap_new(void) +{ + t_pdp_snap *x = (t_pdp_snap *)pd_new(pdp_snap_class); + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1")); + + x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + + x->x_packet0 = -1; + x->x_snapnext = false; + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_snap_setup(void) +{ + + + pdp_snap_class = class_new(gensym("pdp_snap"), (t_newmethod)pdp_snap_new, + (t_method)pdp_snap_free, sizeof(t_pdp_snap), 0, A_NULL); + + + class_addmethod(pdp_snap_class, (t_method)pdp_snap_bang, gensym("bang"), A_NULL); + class_addmethod(pdp_snap_class, (t_method)pdp_snap_snap, gensym("snap"), A_NULL); + + class_addmethod(pdp_snap_class, (t_method)pdp_snap_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/generic/pdp_trigger.c b/modules/generic/pdp_trigger.c new file mode 100644 index 0000000..597125c --- /dev/null +++ b/modules/generic/pdp_trigger.c @@ -0,0 +1,192 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_internals.h" + +/* adapted from the pd trigger object */ + +#define TR_BANG 0 +#define TR_FLOAT 1 +#define TR_SYMBOL 2 +#define TR_POINTER 3 +#define TR_LIST 4 +#define TR_ANYTHING 5 +#define TR_PDP 6 + +/* + +$$$TODO: emplement so that it behaves like the standard trigger object + +i.e. [trigger bang pdp pdp bang pdp] + +register_ro and register_rw messages pass right trough, +since they're not action events, only configure events. +a bang is made equivalent to a process event. + +*/ + +typedef struct triggerout +{ + int u_type; /* outlet type from above */ + t_outlet *u_outlet; +} t_triggerout; + + +typedef struct pdp_trigger_struct +{ + t_object x_obj; + t_float x_f; + + int x_n; + t_triggerout *x_vec; + +} t_pdp_trigger; + + + + +static void pdp_trigger_input_pdp(t_pdp_trigger *x, t_symbol *s, t_floatarg f) +{ + t_atom atom[2]; + t_symbol *pdp = S_PDP; + t_symbol *prc = S_PROCESS; + t_triggerout *u; + int i; + + for (i = x->x_n, u = x->x_vec + i; u--, i--;){ + /* trigger bang outlet only when a process event is recieved */ + if ((u->u_type == TR_BANG) && (s == prc)){ + outlet_bang(u->u_outlet); + } + /* just pass the message if it is a pdp outlet */ + if ((u->u_type) == TR_PDP){ + SETSYMBOL(atom+0, s); + SETFLOAT(atom+1, f); + if (s == prc) outlet_anything(u->u_outlet, pdp, 1, atom); + else outlet_anything(u->u_outlet, pdp, 2, atom); + + } + } + +} + +static void pdp_trigger_input_dpd(t_pdp_trigger *x, t_symbol *s, t_floatarg f) +{ + t_atom atom[2]; + t_symbol *dpd = S_DPD; + t_symbol *acc = S_ACCUMULATE; + t_triggerout *u; + int i; + int p = (int)f; + + for (i = x->x_n, u = x->x_vec + i; u--, i--;){ + /* trigger outlet only when an accumulate event is recieved */ + if (s == acc){ + + /* output bang */ + if (u->u_type == TR_BANG) outlet_bang(u->u_outlet); + + /* output a complete dpd message if it is a pdp outlet */ + if ((u->u_type) == TR_PDP){ + outlet_dpd(u->u_outlet, p); + } + } + } + +} + + +static void pdp_trigger_free(t_pdp_trigger *x) +{ + pdp_dealloc(x->x_vec); +} + +t_class *pdp_trigger_class; + + + +static void *pdp_trigger_new(t_symbol *s, int argc, t_atom *argv) +{ + t_pdp_trigger *x = (t_pdp_trigger *)pd_new(pdp_trigger_class); + t_atom defarg[2], *ap; + t_triggerout *u; + int i; + + + if (!argc) + { + argv = defarg; + argc = 2; + SETSYMBOL(&defarg[0], gensym("pdp")); + SETSYMBOL(&defarg[1], gensym("bang")); + } + + x->x_n = argc; + x->x_vec = pdp_alloc(argc * sizeof(*x->x_vec)); + + for (i = 0, ap = argv, u = x->x_vec; i < argc; u++, ap++, i++) + { + t_atomtype thistype = ap->a_type; + char c; + if (thistype == TR_SYMBOL) c = ap->a_w.w_symbol->s_name[0]; + else c = 0; + if (c == 'p') + u->u_type = TR_PDP, + u->u_outlet = outlet_new(&x->x_obj, &s_anything); + else if (c == 'b') + u->u_type = TR_BANG, u->u_outlet = outlet_new(&x->x_obj, &s_bang); + else + { + pd_error(x, "pdp_trigger: %s: bad type", ap->a_w.w_symbol->s_name); + u->u_type = TR_BANG, u->u_outlet = outlet_new(&x->x_obj, &s_bang); + } + } + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_trigger_setup(void) +{ + + + pdp_trigger_class = class_new(gensym("pdp_trigger"), (t_newmethod)pdp_trigger_new, + (t_method)pdp_trigger_free, sizeof(t_pdp_trigger), 0, A_GIMME, A_NULL); + + class_addcreator((t_newmethod)pdp_trigger_new, gensym("pdp_t"), A_GIMME, 0); + + class_addmethod(pdp_trigger_class, (t_method)pdp_trigger_input_pdp, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_trigger_class, (t_method)pdp_trigger_input_dpd, gensym("dpd"), A_SYMBOL, A_DEFFLOAT, A_NULL); + + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/generic/pdp_udp_receive.c b/modules/generic/pdp_udp_receive.c new file mode 100644 index 0000000..3d42466 --- /dev/null +++ b/modules/generic/pdp_udp_receive.c @@ -0,0 +1,203 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 module sends receives an udp packet stream and converts to pdp packet */ + +#include "pdp_net.h" +#include "pdp.h" +#include "pdp_resample.h" + +#define D if(0) + +typedef struct pdp_udp_receive_struct +{ + + t_object x_obj; + t_float x_f; + + /* receiver object */ + t_pdp_udp_receiver *x_receiver; + + + /* thread vars */ + pthread_attr_t x_attr; + pthread_t x_thread; + int x_exit_thread; + + /* packet queue */ + int x_index; + int x_packet[2]; + + /* polling clock */ + t_clock *x_clock; + /* outlet */ + t_outlet *x_outlet0; + +} t_pdp_udp_receive; + + +static void clock_tick(t_pdp_udp_receive *x) +{ + /* poll for new packet */ + + pdp_pass_if_valid(x->x_outlet0, &x->x_packet[!x->x_index]); + clock_delay(x->x_clock, 1.0f); +} + + + + +static void *receive_thread(void *threaddata) +{ + t_pdp_udp_receive *x = (t_pdp_udp_receive *)threaddata; + t_pdp *pdp_header = 0; + void *pdp_data = 0; + int tmp_packet = -1; + char *type = 0; + unsigned int size = 0; + + /* listen for packets */ + while (!x->x_exit_thread){ + + + switch(pdp_udp_receiver_receive(x->x_receiver, 100)){ + case -1: + /* error */ + goto exit; + case 0: + /* timeout */ + continue; + case 1: + /* data ready */ + break; + } + + /* create a new packet */ + type = pdp_udp_receiver_type(x->x_receiver); + tmp_packet = pdp_factory_newpacket(pdp_gensym(type)); + pdp_header = pdp_packet_header(tmp_packet); + pdp_data = pdp_packet_data(tmp_packet); + + /* check if we were able to create the pdp packet */ + if (!(pdp_header && pdp_data)){ + post("pdp_netreceive: can't create packet (type %s)", type); + pdp_udp_receiver_reset(x->x_receiver); + continue; + } + + /* check size */ + size = pdp_udp_receiver_size(x->x_receiver); + if ((pdp_header->size - PDP_HEADER_SIZE) != size){ + pdp_packet_mark_unused(tmp_packet); + tmp_packet = -1; + post("pdp_netreceive: invalid packet size %d (pdp packet size = %d)", + size, pdp_header->size - PDP_HEADER_SIZE); + continue; + } + + /* copy the data */ + memcpy(pdp_data, pdp_udp_receiver_data(x->x_receiver), size); + + /* copy the packet into queue */ + x->x_index ^= 1; + pdp_packet_mark_unused(x->x_packet[x->x_index]); + x->x_packet[x->x_index] = tmp_packet; + + + } + + exit: + post("thread exiting"); + return 0; +} + + +static void pdp_udp_receive_free(t_pdp_udp_receive *x) +{ + int i; + void* retval; + x->x_exit_thread = 1; // wait for thread to finish + pthread_join(x->x_thread, &retval); + + pdp_udp_receiver_free(x->x_receiver); + + pdp_packet_mark_unused(x->x_packet[0]); + pdp_packet_mark_unused(x->x_packet[1]); + +} + +t_class *pdp_udp_receive_class; + + + +void *pdp_udp_receive_new(t_floatarg fport) +{ + int i; + int port; + struct hostent *hp; + + t_pdp_udp_receive *x = (t_pdp_udp_receive *)pd_new(pdp_udp_receive_class); + + x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + + x->x_packet[0] = -1; + x->x_packet[1] = -1; + x->x_index = 0; + + port = (fport == 0.0f) ? 7777 : fport; + x->x_receiver = pdp_udp_receiver_new(port); + + /* setup thread stuff & create thread */ + x->x_exit_thread = 0; + pthread_attr_init(&x->x_attr); + pthread_attr_setschedpolicy(&x->x_attr, SCHED_OTHER); + pthread_create(&x->x_thread, &x->x_attr, receive_thread, x); + + + /* setup the clock */ + x->x_clock = clock_new(x, (t_method)clock_tick); + clock_delay(x->x_clock, 0); + + post("pdp_netreceive: WARNING: experimental object"); + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_udp_receive_setup(void) +{ + + + pdp_udp_receive_class = class_new(gensym("pdp_netreceive"), (t_newmethod)pdp_udp_receive_new, + (t_method)pdp_udp_receive_free, sizeof(t_pdp_udp_receive), 0, A_DEFFLOAT, A_NULL); + + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/generic/pdp_udp_send.c b/modules/generic/pdp_udp_send.c new file mode 100644 index 0000000..cb55ad1 --- /dev/null +++ b/modules/generic/pdp_udp_send.c @@ -0,0 +1,336 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 module sends a pure packet out as an udp packet stream */ + +#include "pdp_net.h" +#include "pdp.h" +#include "pdp_resample.h" + +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <pthread.h> +#include <netdb.h> + +#define DD if(0) // print DROP debug info +#define D if(0) // print extra connection debug info +#define V if(0) // be verbose (parameter setting feedback) + +typedef struct pdp_udp_send_struct +{ + + t_object x_obj; + t_float x_f; + + /* sender object */ + t_pdp_udp_sender *x_sender; + + /* pthread vars */ + pthread_mutex_t x_mut; + pthread_cond_t x_cond_data_ready; + pthread_cond_t x_cond_send_done; + pthread_t x_thread; + int x_exit_thread; + + // drop info + unsigned int x_drop; + + t_outlet *x_outlet0; + + // packet queue + int x_nb_packets; + int x_read_packet; + int x_write_packet; + int *x_packet; + + +} t_pdp_udp_send; + + + + + +/* some synchro code */ + +static int _wait_for_feeder(t_pdp_udp_send *x) +{ + + /* only use locking when there is no data */ + if (x->x_packet[x->x_read_packet] == -1){ + + /* signal sending is done */ + pthread_mutex_lock(&x->x_mut); + pthread_cond_signal(&x->x_cond_send_done); + + /* wait until there is an item in the queue */ + while((x->x_packet[x->x_read_packet] == -1) && (!x->x_exit_thread)){ + pthread_cond_wait(&x->x_cond_data_ready, &x->x_mut); + } + pthread_mutex_unlock(&x->x_mut); + + /* check if we need to stop the thread */ + if (x->x_exit_thread) return 0; + + } + + return !x->x_exit_thread; +} + +static void _signal_sender(t_pdp_udp_send *x) +{ + + pthread_mutex_lock(&x->x_mut); + pthread_cond_signal(&x->x_cond_data_ready); + pthread_mutex_unlock(&x->x_mut); +} + +static void _wait_until_done(t_pdp_udp_send *x) +{ + pthread_mutex_lock(&x->x_mut); + while (x->x_packet[x->x_read_packet] != -1){ + pthread_cond_wait(&x->x_cond_send_done, &x->x_mut); + } + pthread_mutex_unlock(&x->x_mut); +} + + +static void _remove_packet_from_queue(t_pdp_udp_send *x) +{ + +} + + + + + +static void *send_thread(void *threaddata) +{ + t_pdp_udp_send *x = (t_pdp_udp_send *)threaddata; + + /* main thread loop */ + + /* get a pdp packet from queue */ + /* send header packet and make sure it has arrived */ + /* send a chunk burst */ + /* send done packet and get the resend list */ + /* repeat until send list is empty */ + + while (_wait_for_feeder(x)){ + t_pdp *header; + void *data; + + /* check if we have a valid pdp packet */ + if ((!(header = pdp_packet_header(x->x_packet[x->x_read_packet]))) + ||(!(data = pdp_packet_data(x->x_packet[x->x_read_packet]))) + ||(0 == header->desc)) goto remove; /* nothing to transmit */ + + /* send it */ + pdp_udp_sender_send(x->x_sender, + header->desc->s_name, + header->size - PDP_HEADER_SIZE, data); + + + remove: + /* remove packet from queue */ + pdp_packet_mark_unused(x->x_packet[x->x_read_packet]); + x->x_packet[x->x_read_packet] = -1; + x->x_read_packet++; + x->x_read_packet %= x->x_nb_packets; + + } + return 0; +} + + +static void pdp_udp_send_input_0(t_pdp_udp_send *x, t_symbol *s, t_floatarg f) +{ + + int p = (int)f; + int my_p; + int transferred = 0; + + if (s== gensym("register_ro")){ + + + // check if packet can be stored in the queue + // this is possible if the current write location does not contain a packet + + if (x->x_packet[x->x_write_packet] == -1){ + + // get the packet outside of the lock + my_p = pdp_packet_copy_ro(p); + + + // add to queue (do we really need to lock here?> + //pthread_mutex_lock(&x->x_mut); // LOCK + x->x_packet[x->x_write_packet] = my_p; + x->x_write_packet++; + x->x_write_packet %= x->x_nb_packets; + transferred = 1; + //pthread_mutex_unlock(&x->x_mut); // UNLOCK + } + + // signal sender if transfer succeded + if (transferred) _signal_sender(x); + + // else send a float indicating the number of drops so far + else{ + x->x_drop++; + //outlet_float(x->x_outlet0, (float)x->x_drop); + + DD post ("pdp_netsend: DROP: queue full"); + } + } +} + + + +/* some flow control hacks */ + +static void pdp_udp_send_timeout(t_pdp_udp_send *x, float f) +{ + if (f < 0.0f) f = 0.0f; + pdp_udp_sender_timeout_us(x->x_sender, 1000.0f * f); +} + + +static void pdp_udp_send_sleepgrain(t_pdp_udp_send *x, float f) +{ + if (f < 0.0f) f = 0.0f; + pdp_udp_sender_sleepgrain_us(x->x_sender, 1000.0f * f); +} + +static void pdp_udp_send_sleepperiod(t_pdp_udp_send *x, float f) +{ + if (f < 0.0f) f = 0.0f; + pdp_udp_sender_sleepperiod(x->x_sender, f); +} + + +static void pdp_udp_send_udpsize(t_pdp_udp_send *x, float f) +{ + if (f < 0.0f) f = 0.0f; + pdp_udp_sender_udp_packet_size(x->x_sender, f); +} + +static void pdp_udp_send_connect(t_pdp_udp_send *x, t_symbol *shost, t_float fport) +{ + unsigned int port; + struct hostent *hp; + + /* suspend until sending thread is finished */ + _wait_until_done(x); + + /* set target address */ + port = (fport == 0.0f) ? 7777 : fport; + if (shost == gensym("")) shost = gensym("127.0.0.1"); + + /* connect */ + pdp_udp_sender_connect(x->x_sender, shost->s_name, port); + +} + + +static void pdp_udp_send_free(t_pdp_udp_send *x) +{ + int i; + void* retval; + _wait_until_done(x); // send all remaining packets + x->x_exit_thread = 1; // .. and wait for thread to finish + _signal_sender(x); + pthread_join(x->x_thread, &retval); + + pdp_udp_sender_free(x->x_sender); + + + for (i=0; i<x->x_nb_packets; i++) pdp_packet_mark_unused(x->x_packet[i]); + pdp_dealloc(x->x_packet); + +} + +t_class *pdp_udp_send_class; + + + +void *pdp_udp_send_new(void) +{ + int i; + pthread_attr_t attr; + + t_pdp_udp_send *x = (t_pdp_udp_send *)pd_new(pdp_udp_send_class); + + x->x_sender = pdp_udp_sender_new(); + + //x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + + x->x_nb_packets = 4; + x->x_packet = malloc(sizeof(int)*x->x_nb_packets); + for (i=0; i<x->x_nb_packets; i++) x->x_packet[i] = -1; + x->x_read_packet = 0; + x->x_write_packet = 0; + + x->x_drop = 0; + + + + /* setup thread stuff & create thread */ + x->x_exit_thread = 0; + pthread_mutex_init(&x->x_mut, NULL); + pthread_cond_init(&x->x_cond_data_ready, NULL); + pthread_cond_init(&x->x_cond_send_done, NULL); + pthread_attr_init(&attr); + //pthread_attr_setschedpolicy(&attr, SCHED_OTHER); + pthread_create(&x->x_thread, &attr, send_thread, x); + post("pdp_netsend: WARNING: experimental object"); + + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_udp_send_setup(void) +{ + + pdp_udp_send_class = class_new(gensym("pdp_netsend"), (t_newmethod)pdp_udp_send_new, + (t_method)pdp_udp_send_free, sizeof(t_pdp_udp_send), 0, A_NULL); + + + class_addmethod(pdp_udp_send_class, (t_method)pdp_udp_send_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_udp_send_class, (t_method)pdp_udp_send_sleepgrain, gensym("sleepgrain"), A_FLOAT, A_NULL); + class_addmethod(pdp_udp_send_class, (t_method)pdp_udp_send_sleepperiod, gensym("sleepperiod"), A_FLOAT, A_NULL); + class_addmethod(pdp_udp_send_class, (t_method)pdp_udp_send_udpsize, gensym("udpsize"), A_FLOAT, A_NULL); + class_addmethod(pdp_udp_send_class, (t_method)pdp_udp_send_timeout, gensym("timeout"), A_FLOAT, A_NULL); + class_addmethod(pdp_udp_send_class, (t_method)pdp_udp_send_connect, gensym("connect"), A_SYMBOL, A_FLOAT, A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_basic/Makefile b/modules/image_basic/Makefile new file mode 100644 index 0000000..0a1fa45 --- /dev/null +++ b/modules/image_basic/Makefile @@ -0,0 +1,19 @@ +current: all_modules + +include ../../Makefile.config + +PDP_MOD = pdp_add.o pdp_conv.o \ + pdp_mix.o pdp_mul.o pdp_randmix.o \ + pdp_bq.o pdp_noise.o \ + pdp_gain.o pdp_zoom.o \ + pdp_constant.o \ + pdp_logic.o pdp_stateless.o pdp_plasma.o $(PDP_IMAGE_BASIC) + + +# build basic image processing modules (derived from base class) +all_modules: $(PDP_MOD) + +clean: + rm -f *~ + rm -f *.o + diff --git a/modules/image_basic/README b/modules/image_basic/README new file mode 100644 index 0000000..965d277 --- /dev/null +++ b/modules/image_basic/README @@ -0,0 +1,5 @@ +This directory contains "normal" planar 16 bit unsigned image packet processors, +derived from the t_pdp_imagebase class defined in pdp_imagebase.h + +Most modules are wrappers around monochrome bitmap processors (pdp_imageproc_*) + diff --git a/modules/image_basic/pdp_add.c b/modules/image_basic/pdp_add.c new file mode 100644 index 0000000..0366c16 --- /dev/null +++ b/modules/image_basic/pdp_add.c @@ -0,0 +1,109 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_imagebase.h" + +typedef struct pdp_add_struct +{ + /* a pdp derived class has the t_pdp_imagebase data member as first entry */ + /* it contains the pd object and the data members for the pdp_base class */ + t_pdp_imagebase x_base; + +} t_pdp_add; + + +/* the process method */ +static void pdp_add_process(t_pdp_add *x) +{ + /* get received packets */ + int p0, p1; + + /* get channel mask */ + int mask = pdp_imagebase_get_chanmask(x); + + /* this processes the packets using a pdp image processor */ + /* replace this with your own processing code */ + /* for raw packet acces: use pdp_pacjet_header() and pdp_packet_data() */ + p0 = pdp_base_get_packet(x,0); + p1 = pdp_base_get_packet(x,1); + + pdp_imageproc_dispatch_2buf(&pdp_imageproc_add_process, 0, mask, p0, p1); + + +} + + +static void pdp_add_free(t_pdp_add *x) +{ + /* free super: this is mandatory + (it stops the thread if there is one running and frees all packets) */ + pdp_imagebase_free(x); + + /* if you have allocated more packets + this is the place to free them with pdp_mark_unused */ +} + +t_class *pdp_add_class; + + +void *pdp_add_new(void) +{ + /* allocate */ + t_pdp_add *x = (t_pdp_add *)pd_new(pdp_add_class); + + /* init super: this is mandatory */ + pdp_imagebase_init(x); + + /* set the pdp processing method */ + pdp_base_set_process_method(x, (t_pdp_method)pdp_add_process); + + /* create additional cold (readonly) pdp inlets (there is already one pdp inlet) */ + pdp_base_add_pdp_inlet(x); + + /* create a pdp_outlet */ + pdp_base_add_pdp_outlet(x); + + return (void *)x; +} + + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_add_setup(void) +{ + /* create a standard pd class */ + pdp_add_class = class_new(gensym("pdp_add"), (t_newmethod)pdp_add_new, + (t_method)pdp_add_free, sizeof(t_pdp_add), 0, A_NULL); + + /* inherit pdp base class methods */ + pdp_imagebase_setup(pdp_add_class); +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_basic/pdp_bq.c b/modules/image_basic/pdp_bq.c new file mode 100644 index 0000000..088e50b --- /dev/null +++ b/modules/image_basic/pdp_bq.c @@ -0,0 +1,462 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_imagebase.h" +#include <math.h> + +/* computes a transfer function: + * + * b0 + b1 z^(-1) + b2 z^(-2) + * T(z) = -------------------------- + * 1 + a1 z^(-1) + a2 z^(-2) + * + */ + + +typedef struct pdp_bq_struct +{ + + t_pdp_imagebase x_base; //pdp_bq derives from pdp_base + + + /* state packets for bqt */ + int x_packet1; + int x_packet2; + + + unsigned int x_nbpasses; + + /* single direction */ + unsigned int x_direction; + + bool x_reset_on_formatchange; + + void *x_biquad; + + float x_coefs_a[3]; // a0, -a1, -a2 + float x_coefs_b[3]; // b0, b1, b2 + float x_state_u[2]; // u0, u1 + float x_state_u_save[2]; // u0, u1 (for reset) + +} t_pdp_bq; + + +/************************* COEFFICIENT METHODS ****************************/ + +static void pdp_bq_a0(t_pdp_bq *x, t_floatarg f){x->x_coefs_a[0] = f;} +static void pdp_bq_a1(t_pdp_bq *x, t_floatarg f){x->x_coefs_a[1] = -f;} +static void pdp_bq_a2(t_pdp_bq *x, t_floatarg f){x->x_coefs_a[2] = -f;} + +static void pdp_bq_b0(t_pdp_bq *x, t_floatarg f){x->x_coefs_b[0] = f;} +static void pdp_bq_b1(t_pdp_bq *x, t_floatarg f){x->x_coefs_b[1] = f;} +static void pdp_bq_b2(t_pdp_bq *x, t_floatarg f){x->x_coefs_b[2] = f;} + +static void pdp_bq_u0(t_pdp_bq *x, t_floatarg f){x->x_state_u_save[0] = f;} +static void pdp_bq_u1(t_pdp_bq *x, t_floatarg f){x->x_state_u_save[1] = f;} + + +static void pdp_bq_setcoefs(t_pdp_bq *x, + float a0, float a1, float a2, + float b0, float b1, float b2) +{ + pdp_bq_a0(x,a0); + pdp_bq_a1(x,a1); + pdp_bq_a2(x,a2); + pdp_bq_b0(x,b0); + pdp_bq_b1(x,b1); + pdp_bq_b2(x,b2); + pdp_imageproc_bq_setcoef(x->x_biquad, x->x_coefs_a); +} + +static void pdp_bq_setstate(t_pdp_bq *x, float u0, float u1) +{ + pdp_bq_u0(x,u0); + pdp_bq_u1(x,u1); + pdp_imageproc_bq_setcoef(x->x_biquad, x->x_coefs_a); +} + + + +/* reso lowpass */ +static void pdp_bq_lpf(t_pdp_bq *x, t_floatarg f, t_floatarg Q) +{ + float a0, a1, a2, b0, b1, b2, cs, sn, w, alpha; + w = 2.0 * M_PI * f; + cs = cos(w); + sn = sin(w); + + alpha = sn*sinh(1.0f/(2.0f*Q)); + b0 = (1.0 - cs)/2.0; + b1 = 1.0 - cs; + b2 = (1.0 - cs)/2.0; + a0 = (1.0 + alpha); + a1 = -2.0*cs; + a2 = 1.0 - alpha; + + pdp_bq_setcoefs(x, a0, a1, a2, b0, b1, b2); + +} + +/* reso highpass */ +static void pdp_bq_hpf(t_pdp_bq *x, t_floatarg f, t_floatarg Q) +{ + float a0, a1, a2, b0, b1, b2, cs, sn, w, alpha; + w = 2.0 * M_PI * f; + cs = cos(w); + sn = sin(w); + + alpha = sn*sinh(1.0f/(2.0f*Q)); + + b0 = (1.0 + cs)/2.0; + b1 = -1.0 - cs; + b2 = (1.0 + cs)/2.0; + a0 = (1.0 + alpha); + a1 = -2.0*cs; + a2 = 1.0 - alpha; + + pdp_bq_setcoefs(x, a0, a1, a2, b0, b1, b2); + +} + + +/* reso allpass */ +static void pdp_bq_apf(t_pdp_bq *x, t_floatarg f, t_floatarg Q) +{ + float a0, a1, a2, b0, b1, b2, cs, sn, w, alpha; + w = 2.0 * M_PI * f; + cs = cos(w); + sn = sin(w); + + alpha = sn*sinh(1.0f/(2.0f*Q)); + + b0 = (1.0 - alpha); + b1 = -2.0 * cs; + b2 = (1.0 + alpha); + a0 = (1.0 + alpha); + a1 = -2.0*cs; + a2 = 1.0 - alpha; + + pdp_bq_setcoefs(x, a0, a1, a2, b0, b1, b2); +} + +/* reso band stop (notch) */ +static void pdp_bq_bsf(t_pdp_bq *x, t_floatarg f, t_floatarg Q) +{ + float a0, a1, a2, b0, b1, b2, cs, sn, w, alpha; + w = 2.0 * M_PI * f; + cs = cos(w); + sn = sin(w); + + alpha = sn*sinh(1.0f/(2.0f*Q)); + + b0 = 1.0; + b1 = -2.0 * cs; + b2 = 1.0; + a0 = (1.0 + alpha); + a1 = -2.0*cs; + a2 = 1.0 - alpha; + + pdp_bq_setcoefs(x, a0, a1, a2, b0, b1, b2); + +} + +static void pdp_bq_onep(t_pdp_bq *x, t_floatarg f) +{ + float a0,a1,a2,b0,b1,b2; + + if (f>1.0f) f = 1.0f; + if (f<0.0f) f = 0.0f; + + a0 = 1.0f; + a1 = -(1.0f - f); + a2 = 0.0f; + b0 = f; + b1 = 0.0f; + b2 = 0.0f; + pdp_bq_setcoefs(x, a0, a1, a2, b0, b1, b2); +} + +static void pdp_bq_twop(t_pdp_bq *x, t_floatarg f) +{ + float f1; + float a0,a1,a2,b0,b1,b2; + + if (f>1.0) f = 1.0; + if (f<0.0) f = 0.0; + + f1 = 1.0 - f; + + a0 = 1.0f; + a1 = -2.0f*f1; + a2 = f1*f1; + b0 = f*f; + b1 = 0.0f; + b2 = 0.0f; + + pdp_bq_setcoefs(x, a0, a1, a2, b0, b1, b2); +} + + + + + +/************************* PROCESS METHODS ****************************/ + +static void pdp_bqt_process(t_pdp_bq *x) +{ + /* get received packets */ + int p0 = pdp_base_get_packet(x, 0); + + /* get channel mask */ + u32 mask = pdp_imagebase_get_chanmask(x); + + pdp_imageproc_dispatch_3buf(&pdp_imageproc_bqt_process, x->x_biquad, + mask, p0, x->x_packet1, x->x_packet2); +} + +static void pdp_bq_process(t_pdp_bq *x) +{ + /* get received packets */ + int p0 = pdp_base_get_packet(x, 0); + + /* get channel mask */ + u32 mask = pdp_imagebase_get_chanmask(x); + + pdp_imageproc_bq_setnbpasses(x->x_biquad, x->x_nbpasses); + pdp_imageproc_bq_setdirection(x->x_biquad, x->x_direction); + pdp_imageproc_dispatch_1buf(&pdp_imageproc_bq_process, x->x_biquad, mask, p0); +} + +static void pdp_bqt_reset(t_pdp_bq *x) +{ + pdp_imageproc_dispatch_1buf(&pdp_imageproc_zero_process, 0, -1, x->x_packet1); + pdp_imageproc_dispatch_1buf(&pdp_imageproc_zero_process, 0, -1, x->x_packet2); +} + + + +static void pdp_bqt_preproc(t_pdp_bq *x) +{ + /* get received packets */ + int p0 = pdp_base_get_packet(x, 0); + + /* check if state packets are compatible */ + if (!(pdp_packet_image_compat(p0, x->x_packet1) + && pdp_packet_image_compat(p0, x->x_packet1))){ + + /* if not, create new state packets by copying the input packets */ + post("pdp_bqt: created new state packets"); + pdp_packet_mark_unused(x->x_packet1); + pdp_packet_mark_unused(x->x_packet2); + x->x_packet1 = pdp_packet_clone_rw(p0); + x->x_packet2 = pdp_packet_clone_rw(p0); + + /* reset */ + if (x->x_reset_on_formatchange) pdp_bqt_reset(x); + + } +} + +/************************* CONFIG METHODS ****************************/ + + +static void pdp_bq_passes(t_pdp_bq *x, t_floatarg f) +{ + int passes = (int)f; + passes = passes < 0 ? 0 : passes; + x->x_nbpasses = passes; + +} + +static void pdp_bq_lr(t_pdp_bq *x, t_floatarg f) +{ + if (f == 1.0f) x->x_direction |= PDP_IMAGEPROC_BIQUAD_LEFT2RIGHT; + if (f == 0.0f) x->x_direction &= ~PDP_IMAGEPROC_BIQUAD_LEFT2RIGHT; +} + +static void pdp_bq_rl(t_pdp_bq *x, t_floatarg f) +{ + if (f == 1.0f) x->x_direction |= PDP_IMAGEPROC_BIQUAD_RIGHT2LEFT; + if (f == 0.0f) x->x_direction &= ~PDP_IMAGEPROC_BIQUAD_RIGHT2LEFT; +} +static void pdp_bq_tb(t_pdp_bq *x, t_floatarg f) +{ + if (f == 1.0f) x->x_direction |= PDP_IMAGEPROC_BIQUAD_TOP2BOTTOM; + if (f == 0.0f) x->x_direction &= ~PDP_IMAGEPROC_BIQUAD_TOP2BOTTOM; +} + +static void pdp_bq_bt(t_pdp_bq *x, t_floatarg f) +{ + if (f == 1.0f) x->x_direction |= PDP_IMAGEPROC_BIQUAD_BOTTOM2TOP; + if (f == 0.0f) x->x_direction &= ~PDP_IMAGEPROC_BIQUAD_BOTTOM2TOP; +} + + +static void pdp_bq_hor(t_pdp_bq *x, t_floatarg f) +{ + pdp_bq_lr(x, f); + pdp_bq_rl(x, f); +} +static void pdp_bq_ver(t_pdp_bq *x, t_floatarg f) +{ + pdp_bq_tb(x, f); + pdp_bq_bt(x, f); +} + + +/************************* DES/CONSTRUCTORS ****************************/ + +static void pdp_bq_free(t_pdp_bq *x) +{ + pdp_imagebase_free(x); + pdp_imageproc_bq_delete(x->x_biquad); + pdp_packet_mark_unused(x->x_packet1); + pdp_packet_mark_unused(x->x_packet2); + +} + + +void pdp_bq_init(t_pdp_bq *x) +{ + x->x_packet1 = -1; + x->x_packet2 = -1; + + x->x_nbpasses = 1; + x->x_reset_on_formatchange = true; + + x->x_biquad = pdp_imageproc_bq_new(); + + pdp_bq_setstate(x, 0.0f, 0.0f); + pdp_bq_onep(x, 0.1f); + +} + + + +/* class pointers */ + +t_class *pdp_bq_class; /* biquad spacial processing */ +t_class *pdp_bqt_class; /* biquad time processing */ + +void *pdp_bq_new(void) +{ + t_pdp_bq *x = (t_pdp_bq *)pd_new(pdp_bq_class); + + pdp_imagebase_init(x); + pdp_base_add_pdp_outlet(x); + + pdp_base_set_process_method(x, (t_pdp_method)pdp_bq_process); + pdp_base_add_gen_inlet(x, gensym("float"), gensym("passes")); + + pdp_bq_init(x); + return (void *)x; +} + +void *pdp_bqt_new(void) +{ + t_pdp_bq *x = (t_pdp_bq *)pd_new(pdp_bqt_class); + + pdp_imagebase_init(x); + pdp_base_add_pdp_outlet(x); + + pdp_base_set_preproc_method(x, (t_pdp_method)pdp_bqt_preproc); + pdp_base_set_process_method(x, (t_pdp_method)pdp_bqt_process); + + pdp_bq_init(x); + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + + + +/************************* CLASS CONSTRUCTORS ****************************/ + + +void pdp_bq_coefmethods_setup(t_class *c) +{ + + /* raw coefficient methods */ + class_addmethod(c, (t_method)pdp_bq_a1, gensym("a1"), A_FLOAT, A_NULL); + class_addmethod(c, (t_method)pdp_bq_a2, gensym("a2"), A_FLOAT, A_NULL); + class_addmethod(c, (t_method)pdp_bq_b0, gensym("b0"), A_FLOAT, A_NULL); + class_addmethod(c, (t_method)pdp_bq_b1, gensym("b1"), A_FLOAT, A_NULL); + class_addmethod(c, (t_method)pdp_bq_b2, gensym("b2"), A_FLOAT, A_NULL); + //class_addmethod(c, (t_method)pdp_bq_u1, gensym("u1"), A_FLOAT, A_NULL); + //class_addmethod(c, (t_method)pdp_bq_u2, gensym("u2"), A_FLOAT, A_NULL); + + /* real pole filters */ + class_addmethod(c, (t_method)pdp_bq_onep, gensym("onep"), A_FLOAT, A_NULL); + class_addmethod(c, (t_method)pdp_bq_twop, gensym("twop"), A_FLOAT, A_NULL); + + /* resonnant pole filters */ + class_addmethod(c, (t_method)pdp_bq_lpf, gensym("lpf"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(c, (t_method)pdp_bq_hpf, gensym("hpf"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(c, (t_method)pdp_bq_apf, gensym("apf"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(c, (t_method)pdp_bq_bsf, gensym("bsf"), A_FLOAT, A_FLOAT, A_NULL); +} + +void pdp_bq_setup(void) +{ + + /* setup spatial processing class */ + + pdp_bq_class = class_new(gensym("pdp_bq"), (t_newmethod)pdp_bq_new, + (t_method)pdp_bq_free, sizeof(t_pdp_bq), 0, A_NULL); + + pdp_imagebase_setup(pdp_bq_class); + pdp_bq_coefmethods_setup(pdp_bq_class); + + class_addmethod(pdp_bq_class, (t_method)pdp_bq_passes, gensym("passes"), A_FLOAT, A_NULL); + class_addmethod(pdp_bq_class, (t_method)pdp_bq_hor, gensym("hor"), A_FLOAT, A_NULL); + class_addmethod(pdp_bq_class, (t_method)pdp_bq_ver, gensym("ver"), A_FLOAT, A_NULL); + class_addmethod(pdp_bq_class, (t_method)pdp_bq_tb, gensym("tb"), A_FLOAT, A_NULL); + class_addmethod(pdp_bq_class, (t_method)pdp_bq_bt, gensym("bt"), A_FLOAT, A_NULL); + class_addmethod(pdp_bq_class, (t_method)pdp_bq_lr, gensym("lr"), A_FLOAT, A_NULL); + class_addmethod(pdp_bq_class, (t_method)pdp_bq_rl, gensym("rl"), A_FLOAT, A_NULL); + + + + /* setup time processing class */ + pdp_bqt_class = class_new(gensym("pdp_bqt"), (t_newmethod)pdp_bqt_new, + (t_method)pdp_bq_free, sizeof(t_pdp_bq), 0, A_NULL); + + pdp_imagebase_setup(pdp_bqt_class); + pdp_bq_coefmethods_setup(pdp_bqt_class); + + + /* control */ + class_addmethod(pdp_bqt_class, (t_method)pdp_bqt_reset, gensym("reset"), A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_basic/pdp_cheby.c b/modules/image_basic/pdp_cheby.c new file mode 100644 index 0000000..1bd1a16 --- /dev/null +++ b/modules/image_basic/pdp_cheby.c @@ -0,0 +1,189 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +#include <stdio.h> +#include <gsl/gsl_math.h> +#include <gsl/gsl_chebyshev.h> +#include "pdp.h" +#include "pdp_imagebase.h" + + +typedef struct pdp_cheby_struct +{ + t_pdp_imagebase x_base; + void *x_cheby; + int x_iterations; + int x_order; + gsl_cheb_series *x_cs; + gsl_function x_F; + float *x_vec; + int x_nbpoints; + +} t_pdp_cheby; + + + +static double pdp_cheby_mappingfunction(double f, void *params) +{ + t_pdp_cheby *x = (t_pdp_cheby *)params; + int index; + + /* if there's no array, return the identity function */ + if (!x->x_vec) return f; + + /* else interpolate the array */ + index = ((f + 1) * 0.5) * (x->x_nbpoints - 1); + return x->x_vec[index]; + +} + +static void pdp_cheby_coef(t_pdp_cheby *x, t_floatarg c, t_floatarg f) +{ + pdp_imageproc_cheby_setcoef(x->x_cheby, (int)c, f); +} + +static void pdp_cheby_approx(t_pdp_cheby *x, t_symbol *s) +{ + int i; + t_garray *a; + + /* check if array is valid */ + if (!(a = (t_garray *)pd_findbyclass(s, garray_class))){ + post("pdp_cheby: %s: no such array", s->s_name); + } + /* get data */ + else if (!garray_getfloatarray(a, &x->x_nbpoints, &x->x_vec)){ + post("pdp_cheby: %s: bad template", s->s_name); + + } + + else{ + + /* calculate approximation */ + gsl_cheb_init (x->x_cs, &x->x_F, -1.0, 1.0); + + /* propagate coefficients */ + for (i=0; i<=x->x_order; i++){ + pdp_cheby_coef(x, i, x->x_cs->c[i]); + } + } + + x->x_vec = 0; + return; + + +} + + +static void pdp_cheby_process(t_pdp_cheby *x) +{ + int p0 = pdp_base_get_packet(x, 0); + u32 mask = pdp_imagebase_get_chanmask(x); + pdp_imageproc_cheby_setnbpasses(x->x_cheby, x->x_iterations); + pdp_imageproc_dispatch_1buf(&pdp_imageproc_cheby_process, x->x_cheby, mask, p0); +} + + + +static void pdp_cheby_reset(t_pdp_cheby *x) +{ + int i; + for (i = 0; i <= x->x_order; i++) + pdp_imageproc_cheby_setcoef(x->x_cheby, i, 0); +} + + +static void pdp_cheby_iterations(t_pdp_cheby *x, t_floatarg f) +{ + int i = (int)f; + if (i<0) i = 0; + x->x_iterations = i; + +} +static void pdp_cheby_free(t_pdp_cheby *x) +{ + pdp_imagebase_free(x); + pdp_imageproc_cheby_delete(x->x_cheby); + gsl_cheb_free(x->x_cs); + +} + +t_class *pdp_cheby_class; + + + +void *pdp_cheby_new(t_floatarg f) +{ + t_pdp_cheby *x = (t_pdp_cheby *)pd_new(pdp_cheby_class); + int order = (int)(f); + + /* super init */ + pdp_imagebase_init(x); + + /* create i/o */ + pdp_base_add_gen_inlet(x, gensym("float"), gensym("iterations")); + pdp_base_add_pdp_outlet(x); + + /* setup callback */ + pdp_base_set_process_method(x, (t_pdp_method)pdp_cheby_process); + + /* data init */ + x->x_cheby = pdp_imageproc_cheby_new(order); + x->x_iterations = 1; + + if (order < 2) order = 2; + x->x_order = order; + + /* init gls chebychev series object */ + x->x_cs = gsl_cheb_alloc(order); + x->x_F.function = pdp_cheby_mappingfunction; + x->x_F.params = x; + x->x_vec = 0; + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_cheby_setup(void) +{ + + + pdp_cheby_class = class_new(gensym("pdp_cheby"), (t_newmethod)pdp_cheby_new, + (t_method)pdp_cheby_free, sizeof(t_pdp_cheby), 0, A_DEFFLOAT, A_NULL); + + pdp_imagebase_setup(pdp_cheby_class); + + class_addmethod(pdp_cheby_class, (t_method)pdp_cheby_coef, gensym("coef"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_cheby_class, (t_method)pdp_cheby_iterations, gensym("iterations"), A_FLOAT, A_NULL); + class_addmethod(pdp_cheby_class, (t_method)pdp_cheby_reset, gensym("reset"), A_NULL); + class_addmethod(pdp_cheby_class, (t_method)pdp_cheby_approx, gensym("approx"), A_SYMBOL, A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_basic/pdp_constant.c b/modules/image_basic/pdp_constant.c new file mode 100644 index 0000000..e5b088e --- /dev/null +++ b/modules/image_basic/pdp_constant.c @@ -0,0 +1,162 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_imagebase.h" + + +typedef struct pdp_constant_struct +{ + t_pdp_imagebase x_base; + + t_outlet *x_outlet0; + + int x_packet0; + + t_symbol *x_type; + + unsigned int x_width; + unsigned int x_height; + + void *x_constant; + +} t_pdp_constant; + + + +void pdp_constant_type(t_pdp_constant *x, t_symbol *s) +{ + x->x_type = s; +} + + +void pdp_constant_value(t_pdp_constant *x, t_floatarg f) +{ + if (f>1.0f) f = 1.0f; + if (f<-1.0f) f = -1.0f; + + x->x_constant = (void *)((s32)(0x7fff * f)); +} + + + +static void pdp_constant_process(t_pdp_constant *x) +{ + /* get channel mask */ + u32 mask = pdp_imagebase_get_chanmask(x); + + /* create new packet */ + if (x->x_type == gensym("yv12")){x->x_packet0 = pdp_packet_new_image_YCrCb(x->x_width, x->x_height);} + else if (x->x_type == gensym("grey")){x->x_packet0 = pdp_packet_new_image_grey(x->x_width, x->x_height);} + else return; + + /* this processes the packets using a pdp image processor */ + pdp_imageproc_dispatch_1buf(&pdp_imageproc_constant_process, x->x_constant, mask, x->x_packet0); + pdp_imageproc_dispatch_1buf(&pdp_imageproc_constant_process, 0, ~mask, x->x_packet0); + + return; +} + +static void pdp_constant_postproc(t_pdp_constant *x) +{ + pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet0); +} + +static void pdp_constant_bang(t_pdp_constant *x) +{ + pdp_base_bang(x); +} + +static void pdp_constant_dim(t_pdp_constant *x, t_floatarg w, t_floatarg h) +{ + x->x_width = pdp_imageproc_legalwidth((int)w); + x->x_height = pdp_imageproc_legalheight((int)h); + //post("dims %d %d", x->x_width, x->x_height); +} + + +static void pdp_constant_free(t_pdp_constant *x) +{ + pdp_imagebase_free(x); + pdp_packet_mark_unused(x->x_packet0); + +} + +t_class *pdp_constant_class; + + + +void *pdp_constant_new(void) +{ + int i; + t_pdp_constant *x = (t_pdp_constant *)pd_new(pdp_constant_class); + + /* super init */ + pdp_imagebase_init(x); + + /* in/out*/ + pdp_base_add_gen_inlet(x, gensym("float"), gensym("value")); + x->x_outlet0 = pdp_base_add_pdp_outlet(x); + + /* base callbacks */ + pdp_base_disable_active_inlet(x); + pdp_base_set_process_method(x, (t_pdp_method)pdp_constant_process); + pdp_base_set_postproc_method(x, (t_pdp_method)pdp_constant_postproc); + + /* data init */ + x->x_packet0 = -1; + pdp_constant_dim(x, 320, 240); + pdp_constant_value(x, 0.0f); + pdp_constant_type(x, gensym("yv12")); + + + return (void *)x; +} + + + +#ifdef __cplusplus +extern "C" +{ +#endif + + + +void pdp_constant_setup(void) +{ + + + pdp_constant_class = class_new(gensym("pdp_constant"), (t_newmethod)pdp_constant_new, + (t_method)pdp_constant_free, sizeof(t_pdp_constant), 0, A_NULL); + + pdp_imagebase_setup(pdp_constant_class); + + class_addmethod(pdp_constant_class, (t_method)pdp_constant_value, gensym("value"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_constant_class, (t_method)pdp_constant_type, gensym("type"), A_SYMBOL, A_NULL); + class_addmethod(pdp_constant_class, (t_method)pdp_constant_dim, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_constant_class, (t_method)pdp_constant_bang, gensym("bang"), A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_basic/pdp_conv.c b/modules/image_basic/pdp_conv.c new file mode 100644 index 0000000..dfce381 --- /dev/null +++ b/modules/image_basic/pdp_conv.c @@ -0,0 +1,212 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_imagebase.h" + + +typedef struct pdp_conv_struct +{ + t_pdp_imagebase x_base; + + + unsigned int x_nbpasses; + bool x_horizontal; + bool x_vertical; + + void *x_convolver_hor; + void *x_convolver_ver; + +} t_pdp_conv; + + + +static void pdp_conv_process(t_pdp_conv *x) +{ + int p = pdp_base_get_packet(x, 0); + u32 mask = pdp_imagebase_get_chanmask(x); + + if (x->x_vertical){ + pdp_imageproc_conv_setnbpasses(x->x_convolver_ver, x->x_nbpasses); + pdp_imageproc_dispatch_1buf(&pdp_imageproc_conv_process, x->x_convolver_ver, mask, p); + } + + if (x->x_horizontal){ + pdp_imageproc_conv_setnbpasses(x->x_convolver_hor, x->x_nbpasses); + pdp_imageproc_dispatch_1buf(&pdp_imageproc_conv_process, x->x_convolver_hor, mask, p); + } + +} + + + +static void pdp_conv_passes(t_pdp_conv *x, t_floatarg f) +{ + int passes = (int)f; + passes = passes < 0 ? 0 : passes; + x->x_nbpasses = passes; + +} +static void pdp_conv_hor(t_pdp_conv *x, t_floatarg f) +{ + int hor = (int)f; + x->x_horizontal = (hor != 0); + +} +static void pdp_conv_ver(t_pdp_conv *x, t_floatarg f) +{ + int ver = (int)f; + x->x_vertical = (ver != 0); +} +static void pdp_conv_free(t_pdp_conv *x) +{ + pdp_imagebase_free(x); + pdp_imageproc_conv_delete(x->x_convolver_hor); + pdp_imageproc_conv_delete(x->x_convolver_ver); +} + +/* setup hmask */ + +static void pdp_conv_hleft(t_pdp_conv *x, t_floatarg f) +{ + pdp_imageproc_conv_setmin1(x->x_convolver_hor, f); + +} +static void pdp_conv_hmiddle(t_pdp_conv *x, t_floatarg f) +{ + pdp_imageproc_conv_setzero(x->x_convolver_hor, f); +} +static void pdp_conv_hright(t_pdp_conv *x, t_floatarg f) +{ + pdp_imageproc_conv_setplus1(x->x_convolver_hor, f); +} + +static void pdp_conv_hmask(t_pdp_conv *x, t_floatarg l, t_floatarg m, t_floatarg r) +{ + pdp_conv_hleft(x, l); + pdp_conv_hmiddle(x, m); + pdp_conv_hright(x, r); +} + +static void pdp_conv_vtop(t_pdp_conv *x, t_floatarg f) +{ + pdp_imageproc_conv_setmin1(x->x_convolver_ver, f); +} +static void pdp_conv_vmiddle(t_pdp_conv *x, t_floatarg f) +{ + pdp_imageproc_conv_setzero(x->x_convolver_ver, f); + +} +static void pdp_conv_vbottom(t_pdp_conv *x, t_floatarg f) +{ + pdp_imageproc_conv_setplus1(x->x_convolver_ver, f); +} + +static void pdp_conv_vmask(t_pdp_conv *x, t_floatarg l, t_floatarg m, t_floatarg r) +{ + pdp_conv_vtop(x, l); + pdp_conv_vmiddle(x, m); + pdp_conv_vbottom(x, r); +} + + +static void pdp_conv_mask(t_pdp_conv *x, t_floatarg l, t_floatarg m, t_floatarg r) +{ + pdp_conv_hmask(x, l, m, r); + pdp_conv_vmask(x, l, m, r); +} + +t_class *pdp_conv_class; + + + +void *pdp_conv_new(void) +{ + t_pdp_conv *x = (t_pdp_conv *)pd_new(pdp_conv_class); + + /* super init */ + pdp_imagebase_init(x); + + /* inlets & outlets */ + pdp_base_add_gen_inlet(x, gensym("float"), gensym("passes")); + pdp_base_add_pdp_outlet(x); + + /* register */ + pdp_base_set_process_method(x, (t_pdp_method)pdp_conv_process); + + x->x_nbpasses = 1; + x->x_horizontal = true; + x->x_vertical = true; + + x->x_convolver_hor = pdp_imageproc_conv_new(); + x->x_convolver_ver = pdp_imageproc_conv_new(); + + pdp_imageproc_conv_setbordercolor(x->x_convolver_hor, 0); + pdp_imageproc_conv_setbordercolor(x->x_convolver_ver, 0); + + pdp_imageproc_conv_setorientation(x->x_convolver_hor, PDP_IMAGEPROC_CONV_HORIZONTAL); + pdp_imageproc_conv_setorientation(x->x_convolver_ver, PDP_IMAGEPROC_CONV_VERTICAL); + + pdp_conv_mask(x, .25,.5,.25); + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_conv_setup(void) +{ + + + pdp_conv_class = class_new(gensym("pdp_conv"), (t_newmethod)pdp_conv_new, + (t_method)pdp_conv_free, sizeof(t_pdp_conv), 0, A_NULL); + + pdp_imagebase_setup(pdp_conv_class); + + class_addmethod(pdp_conv_class, (t_method)pdp_conv_passes, gensym("passes"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_conv_class, (t_method)pdp_conv_hor, gensym("hor"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_conv_class, (t_method)pdp_conv_ver, gensym("ver"), A_DEFFLOAT, A_NULL); + + class_addmethod(pdp_conv_class, (t_method)pdp_conv_hleft, gensym("hleft"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_conv_class, (t_method)pdp_conv_hmiddle, gensym("hmiddle"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_conv_class, (t_method)pdp_conv_hright, gensym("hright"), A_DEFFLOAT, A_NULL); + + class_addmethod(pdp_conv_class, (t_method)pdp_conv_vtop, gensym("vtop"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_conv_class, (t_method)pdp_conv_vmiddle, gensym("vmiddle"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_conv_class, (t_method)pdp_conv_vbottom, gensym("vbottom"), A_DEFFLOAT, A_NULL); + + class_addmethod(pdp_conv_class, (t_method)pdp_conv_vmask, gensym("vmask"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_conv_class, (t_method)pdp_conv_hmask, gensym("hmask"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_conv_class, (t_method)pdp_conv_mask, gensym("mask"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL); + + + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_basic/pdp_gain.c b/modules/image_basic/pdp_gain.c new file mode 100644 index 0000000..c36f758 --- /dev/null +++ b/modules/image_basic/pdp_gain.c @@ -0,0 +1,111 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_imagebase.h" + + +typedef struct pdp_gain_struct +{ + t_pdp_imagebase x_base; + void *x_gain; + +} t_pdp_gain; + + + + +static void pdp_gain_process(t_pdp_gain *x) +{ + int p = pdp_base_get_packet(x, 0); + u32 mask = pdp_imagebase_get_chanmask(x); + + pdp_packet_image_set_chanmask(p, mask); + pdp_imageproc_dispatch_1buf(&pdp_imageproc_gain_process, x->x_gain, 0, p); + +} + + +static void pdp_gain_gain(t_pdp_gain *x, t_floatarg f) +{ + pdp_imageproc_gain_setgain(x->x_gain, f); +} + + + +t_class *pdp_gain_class; + + + +void pdp_gain_free(t_pdp_gain *x) +{ + pdp_imagebase_free(x); + pdp_imageproc_gain_delete(x->x_gain); +} + +void *pdp_gain_new(t_floatarg f) +{ + t_pdp_gain *x = (t_pdp_gain *)pd_new(pdp_gain_class); + + /* super init */ + pdp_imagebase_init(x); + + /* no arg, or zero -> gain = 1 */ + if (f==0.0f) f = 1.0f; + + + /* io */ + pdp_base_add_gen_inlet(x, gensym("float"), gensym("gain")); + pdp_base_add_pdp_outlet(x); + + /* callbacks */ + pdp_base_set_process_method(x, (t_pdp_method)pdp_gain_process); + + x->x_gain = pdp_imageproc_gain_new(); + pdp_gain_gain(x, f); + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_gain_setup(void) +{ + + + pdp_gain_class = class_new(gensym("pdp_gain"), (t_newmethod)pdp_gain_new, + (t_method)pdp_gain_free, sizeof(t_pdp_gain), 0, A_DEFFLOAT, A_NULL); + + pdp_imagebase_setup(pdp_gain_class); + + class_addmethod(pdp_gain_class, (t_method)pdp_gain_gain, gensym("gain"), A_DEFFLOAT, A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_basic/pdp_logic.c b/modules/image_basic/pdp_logic.c new file mode 100644 index 0000000..002557c --- /dev/null +++ b/modules/image_basic/pdp_logic.c @@ -0,0 +1,252 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_imagebase.h" + +typedef struct pdp_logic_struct +{ + t_pdp_imagebase x_base; + + void *x_mask; + +} t_pdp_logic; + + +static void pdp_logic_process_and(t_pdp_logic *x) +{ + int p0 = pdp_base_get_packet(x, 0); + int p1 = pdp_base_get_packet(x, 1); + u32 mask = pdp_imagebase_get_chanmask(x); + pdp_imageproc_dispatch_2buf(&pdp_imageproc_and_process, 0, mask, p0, p1); +} + +static void pdp_logic_process_or(t_pdp_logic *x) +{ + int p0 = pdp_base_get_packet(x, 0); + int p1 = pdp_base_get_packet(x, 1); + u32 mask = pdp_imagebase_get_chanmask(x); + pdp_imageproc_dispatch_2buf(&pdp_imageproc_or_process, 0, mask, p0, p1); +} + +static void pdp_logic_process_xor(t_pdp_logic *x) +{ + int p0 = pdp_base_get_packet(x, 0); + int p1 = pdp_base_get_packet(x, 1); + u32 mask = pdp_imagebase_get_chanmask(x); + pdp_imageproc_dispatch_2buf(&pdp_imageproc_xor_process, 0, mask, p0, p1); +} + +static void pdp_logic_process_not(t_pdp_logic *x) +{ + int p0 = pdp_base_get_packet(x, 0); + u32 mask = pdp_imagebase_get_chanmask(x); + pdp_imageproc_dispatch_1buf(&pdp_imageproc_not_process, 0, mask, p0); +} + +static void pdp_logic_process_mask(t_pdp_logic *x) +{ + int p0 = pdp_base_get_packet(x, 0); + u32 mask = pdp_imagebase_get_chanmask(x); + pdp_imageproc_dispatch_1buf(&pdp_imageproc_mask_process, x->x_mask, mask, p0); +} + +static void pdp_logic_process_softthresh(t_pdp_logic *x) +{ + int p0 = pdp_base_get_packet(x, 0); + u32 mask = pdp_imagebase_get_chanmask(x); + pdp_imageproc_dispatch_1buf(&pdp_imageproc_softthresh_process, x->x_mask, mask, p0); +} + + +static void pdp_logic_process_hardthresh(t_pdp_logic *x) +{ + int p0 = pdp_base_get_packet(x, 0); + u32 mask = pdp_imagebase_get_chanmask(x); + pdp_imageproc_dispatch_1buf(&pdp_imageproc_hardthresh_process, x->x_mask, mask, p0); +} + + +static void pdp_logic_set_mask(t_pdp_logic *x, t_floatarg f) +{ + /* using a pointer as a variable hmm? */ + u32 mask = ((u32)f) & 0xffff; + x->x_mask = ((void * )mask); +} + +static void pdp_logic_set_threshold(t_pdp_logic *x, t_floatarg f) +{ + /* using a pointer as a variable hmm? */ + if (f<0.0f) f = 0.0f; + if (f>1.0f) f = 1.0f; + x->x_mask = (void *)((u32)(((float)0x7fff) * f)); +} + +static void pdp_logic_set_depth(t_pdp_logic *x, t_floatarg f) +{ + u32 mask; + int shift = (16 - ((int)f)); + if (shift < 0) shift = 0; + if (shift > 16) shift = 16; + mask = ((0xffff)<<shift) & 0xffff; + x->x_mask = (void *)mask; + +} + + +static void pdp_logic_free(t_pdp_logic *x) +{ + /* remove process method from queue before deleting data */ + pdp_imagebase_free(x); +} + +t_class *pdp_logic_class; + + +/* common new method */ +void *pdp_logic_new(void) +{ + t_pdp_logic *x = (t_pdp_logic *)pd_new(pdp_logic_class); + + /* super init */ + pdp_imagebase_init(x); + + /* outlet */ + pdp_base_add_pdp_outlet(x); + x->x_mask = 0; + + return (void *)x; +} + +void *pdp_logic_new_and(void) +{ + t_pdp_logic *x = pdp_logic_new(); + /* init in/out */ + pdp_base_add_pdp_inlet(x); + pdp_base_set_process_method(x, (t_pdp_method)pdp_logic_process_and); + + return (void *)x; +} + +void *pdp_logic_new_or(void) +{ + t_pdp_logic *x = pdp_logic_new(); + /* init in/out */ + pdp_base_add_pdp_inlet(x); + pdp_base_set_process_method(x, (t_pdp_method)pdp_logic_process_or); + return (void *)x; +} + +void *pdp_logic_new_xor(void) +{ + t_pdp_logic *x = pdp_logic_new(); + /* init in/out */ + pdp_base_add_pdp_inlet(x); + pdp_base_set_process_method(x, (t_pdp_method)pdp_logic_process_xor); + return (void *)x; +} + +void *pdp_logic_new_not(void) +{ + t_pdp_logic *x = pdp_logic_new(); + /* init in/out */ + pdp_base_set_process_method(x, (t_pdp_method)pdp_logic_process_not); + return (void *)x; +} + +void *pdp_logic_new_mask(void) +{ + t_pdp_logic *x = pdp_logic_new(); + /* init in/out */ + pdp_base_add_gen_inlet(x, gensym("float"), gensym("mask")); + pdp_base_set_process_method(x, (t_pdp_method)pdp_logic_process_mask); + + x->x_mask = (void *)0xffff; + return (void *)x; +} + +void *pdp_logic_new_depth(void) +{ + t_pdp_logic *x = pdp_logic_new(); + /* init in/out */ + pdp_base_add_gen_inlet(x, gensym("float"), gensym("depth")); + pdp_base_set_process_method(x, (t_pdp_method)pdp_logic_process_mask); + + x->x_mask = (void *)0xffff; + return (void *)x; +} + +void *pdp_logic_new_softthresh(t_floatarg f) +{ + t_pdp_logic *x = pdp_logic_new(); + /* init in/out */ + pdp_base_add_gen_inlet(x, gensym("float"), gensym("threshold")); + pdp_base_set_process_method(x, (t_pdp_method)pdp_logic_process_softthresh); + pdp_logic_set_threshold(x,f); + + return (void *)x; +} + + +void *pdp_logic_new_hardthresh(t_floatarg f) +{ + t_pdp_logic *x = pdp_logic_new(); + /* init in/out */ + pdp_base_add_gen_inlet(x, gensym("float"), gensym("threshold")); + pdp_base_set_process_method(x, (t_pdp_method)pdp_logic_process_hardthresh); + pdp_logic_set_threshold(x,f); + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_logic_setup(void) +{ + + + pdp_logic_class = class_new(gensym("pdp_and"), (t_newmethod)pdp_logic_new_and, + (t_method)pdp_logic_free, sizeof(t_pdp_logic), 0, A_DEFFLOAT, A_NULL); + + pdp_imagebase_setup(pdp_logic_class); + + class_addcreator((t_newmethod)pdp_logic_new_or, gensym("pdp_or"), A_NULL); + class_addcreator((t_newmethod)pdp_logic_new_xor, gensym("pdp_xor"), A_NULL); + class_addcreator((t_newmethod)pdp_logic_new_not, gensym("pdp_not"), A_NULL); + class_addcreator((t_newmethod)pdp_logic_new_mask, gensym("pdp_bitmask"), A_NULL); + class_addcreator((t_newmethod)pdp_logic_new_depth, gensym("pdp_bitdepth"), A_NULL); + class_addcreator((t_newmethod)pdp_logic_new_softthresh, gensym("pdp_sthresh"), A_NULL); + class_addcreator((t_newmethod)pdp_logic_new_hardthresh, gensym("pdp_hthresh"), A_NULL); + + class_addmethod(pdp_logic_class, (t_method)pdp_logic_set_mask, gensym("mask"), A_FLOAT, A_NULL); + class_addmethod(pdp_logic_class, (t_method)pdp_logic_set_depth, gensym("depth"), A_FLOAT, A_NULL); + class_addmethod(pdp_logic_class, (t_method)pdp_logic_set_threshold, gensym("threshold"), A_FLOAT, A_NULL); +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_basic/pdp_mix.c b/modules/image_basic/pdp_mix.c new file mode 100644 index 0000000..2d01d38 --- /dev/null +++ b/modules/image_basic/pdp_mix.c @@ -0,0 +1,165 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_imagebase.h" + +typedef struct pdp_mix_struct +{ + t_pdp_imagebase x_base; + + t_outlet *x_outlet0; + t_outlet *x_outlet1; + + void *x_mixer; + + int x_extrapolate; + +} t_pdp_mix; + + +static void pdp_mix_process(t_pdp_mix *x) +{ + int p0 = pdp_base_get_packet(x, 0); + int p1 = pdp_base_get_packet(x, 1); + u32 mask = pdp_imagebase_get_chanmask(x); + pdp_imageproc_dispatch_2buf(&pdp_imageproc_mix_process, x->x_mixer, mask, p0, p1); +} + + +static void pdp_mix_mix(t_pdp_mix *x, t_floatarg f) +{ + float f2; + if (!x->x_extrapolate){ + if (f < 0.0f) f = 0.0f; + if (f > 1.0f) f = 1.0f; + } + + f2 = (1.0f - f); + pdp_imageproc_mix_setleftgain(x->x_mixer, f2); + pdp_imageproc_mix_setrightgain(x->x_mixer, f); + +} + +static void pdp_mix_mix1(t_pdp_mix *x, t_floatarg f) +{ + pdp_imageproc_mix_setleftgain(x->x_mixer, f); + +} +static void pdp_mix_mix2(t_pdp_mix *x, t_floatarg f2) +{ + pdp_imageproc_mix_setrightgain(x->x_mixer, f2); +} + +static void pdp_mix_extrapolate(t_pdp_mix *x, t_floatarg f) +{ + if (f == 0.0f) x->x_extrapolate = 0; + if (f == 1.0f) x->x_extrapolate = 1; +} + + +static void pdp_mix_free(t_pdp_mix *x) +{ + pdp_imagebase_free(x); + pdp_imageproc_mix_delete(x->x_mixer); +} + +t_class *pdp_mix_class; +t_class *pdp_mix2_class; + + +void *pdp_mix_common_init(t_pdp_mix *x) +{ + int i; + + pdp_imagebase_init(x); + pdp_base_add_pdp_inlet(x); + pdp_base_add_pdp_outlet(x); + pdp_base_set_process_method(x, (t_pdp_method)pdp_mix_process); + + x->x_extrapolate = 0; + x->x_mixer = pdp_imageproc_mix_new(); + pdp_mix_mix(x, 0.0f); + + return (void *)x; +} + + +void *pdp_mix_new(t_floatarg mix) +{ + t_pdp_mix *x = (t_pdp_mix *)pd_new(pdp_mix_class); + pdp_mix_common_init(x); + pdp_base_add_gen_inlet(x, gensym("float"), gensym("mix")); + + if (mix == 0.0f) mix = 0.5f; + pdp_mix_mix(x, mix); + return (void *)x; +} + +void *pdp_mix2_new(t_floatarg mix1, t_floatarg mix2) +{ + t_pdp_mix *x = (t_pdp_mix *)pd_new(pdp_mix2_class); + pdp_mix_common_init(x); + + pdp_base_add_gen_inlet(x, gensym("float"), gensym("mix1")); + pdp_base_add_gen_inlet(x, gensym("float"), gensym("mix2")); + + if ((mix1 == 0.0f) && (mix2 == 0.0f)) mix1 = mix2 = 0.5f; + pdp_mix_mix1(x, mix1); + pdp_mix_mix2(x, mix2); + return (void *)x; +} + +#ifdef __cplusplus +extern "C" +{ +#endif + + + +void pdp_mix_setup(void) +{ + + + pdp_mix_class = class_new(gensym("pdp_mix"), (t_newmethod)pdp_mix_new, + (t_method)pdp_mix_free, sizeof(t_pdp_mix), 0, A_DEFFLOAT, A_NULL); + + pdp_imagebase_setup(pdp_mix_class); + class_addmethod(pdp_mix_class, (t_method)pdp_mix_mix, gensym("mix"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_mix_class, (t_method)pdp_mix_extrapolate, gensym("extrapolate"), A_DEFFLOAT, A_NULL); + + + + + pdp_mix2_class = class_new(gensym("pdp_mix2"), (t_newmethod)pdp_mix2_new, + (t_method)pdp_mix_free, sizeof(t_pdp_mix), 0, A_DEFFLOAT, A_DEFFLOAT, A_NULL); + + pdp_imagebase_setup(pdp_mix2_class); + class_addmethod(pdp_mix2_class, (t_method)pdp_mix_mix1, gensym("mix1"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_mix2_class, (t_method)pdp_mix_mix2, gensym("mix2"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_mix2_class, (t_method)pdp_mix_extrapolate, gensym("extrapolate"), A_DEFFLOAT, A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_basic/pdp_mul.c b/modules/image_basic/pdp_mul.c new file mode 100644 index 0000000..c7321d7 --- /dev/null +++ b/modules/image_basic/pdp_mul.c @@ -0,0 +1,85 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_imagebase.h" + +typedef struct pdp_mul_struct +{ + t_pdp_imagebase x_base; + +} t_pdp_mul; + + + +static void pdp_mul_process(t_pdp_mul *x) +{ + int p0 = pdp_base_get_packet(x, 0); + int p1 = pdp_base_get_packet(x, 1); + u32 mask = pdp_imagebase_get_chanmask(x); + pdp_imageproc_dispatch_2buf(&pdp_imageproc_mul_process, 0, mask, p0, p1); +} + + + +static void pdp_mul_free(t_pdp_mul *x) +{ + pdp_imagebase_free(x); +} + +t_class *pdp_mul_class; + + + +void *pdp_mul_new(void) +{ + t_pdp_mul *x = (t_pdp_mul *)pd_new(pdp_mul_class); + + /* super init */ + pdp_imagebase_init(x); + pdp_base_add_pdp_inlet(x); + pdp_base_add_pdp_outlet(x); + pdp_base_set_process_method(x, (t_pdp_method)pdp_mul_process); + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_mul_setup(void) +{ + + + pdp_mul_class = class_new(gensym("pdp_mul"), (t_newmethod)pdp_mul_new, + (t_method)pdp_mul_free, sizeof(t_pdp_mul), 0, A_NULL); + + pdp_imagebase_setup(pdp_mul_class); +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_basic/pdp_noise.c b/modules/image_basic/pdp_noise.c new file mode 100644 index 0000000..cb8f772 --- /dev/null +++ b/modules/image_basic/pdp_noise.c @@ -0,0 +1,160 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_imagebase.h" + + +typedef struct pdp_noise_struct +{ + t_pdp_imagebase x_base; + + int x_packet0; + t_outlet *x_outlet0; + void *x_noisegen; + + t_symbol *x_type; + + unsigned int x_width; + unsigned int x_height; + +} t_pdp_noise; + + + +void pdp_noise_type(t_pdp_noise *x, t_symbol *s) +{ + x->x_type = s; +} + + +void pdp_noise_random(t_pdp_noise *x, t_floatarg seed) +{ + if (seed == 0.0f) seed = (float)random(); + pdp_imageproc_random_setseed(x->x_noisegen, seed); + +} + +/* called inside pdp thread */ +static void pdp_noise_process(t_pdp_noise *x) +{ + /* seed the 16 bit rng with a new random number from the clib */ + pdp_noise_random(x, 0.0f); + + /* create new packet */ + if (x->x_type == gensym("grey")) { + x->x_packet0 = pdp_packet_new_image_grey(x->x_width, x->x_height); + } + else if (x->x_type == gensym("yv12")) { + x->x_packet0 = pdp_packet_new_image_YCrCb(x->x_width, x->x_height); + } + else return; + + /* call the image processor */ + pdp_imageproc_dispatch_1buf(&pdp_imageproc_random_process, x->x_noisegen, + -1, x->x_packet0); +} + +/* called inside pd thread: involves an outlet */ +static void pdp_noise_postproc(t_pdp_noise *x) +{ + pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet0); +} + +static void pdp_noise_bang(t_pdp_noise *x) +{ + pdp_base_bang(x); +} + +static void pdp_noise_dim(t_pdp_noise *x, t_floatarg w, t_floatarg h) +{ + x->x_width = pdp_imageproc_legalwidth((int)w); + x->x_height = pdp_imageproc_legalheight((int)h); + //post("dims %d %d", x->x_width, x->x_height); +} + + +static void pdp_noise_free(t_pdp_noise *x) +{ + pdp_imagebase_free(x); + + /* tidy up */ + pdp_packet_mark_unused(x->x_packet0); + pdp_imageproc_random_delete(x->x_noisegen); +} + +t_class *pdp_noise_class; + + +void *pdp_noise_new(void) +{ + int i; + + t_pdp_noise *x = (t_pdp_noise *)pd_new(pdp_noise_class); + + pdp_imagebase_init(x); + pdp_base_disable_active_inlet(x); + pdp_base_set_process_method(x, (t_pdp_method)pdp_noise_process); + pdp_base_set_postproc_method(x, (t_pdp_method)pdp_noise_postproc); + + x->x_outlet0 = pdp_base_add_pdp_outlet(x); + x->x_packet0 = -1; + + x->x_width = 320; + x->x_height = 240; + + x->x_noisegen = pdp_imageproc_random_new(); + + pdp_noise_random(x, 0.0f); + pdp_noise_type(x, gensym("yv12")); + + return (void *)x; +} + + + +#ifdef __cplusplus +extern "C" +{ +#endif + + + +void pdp_noise_setup(void) +{ + + + pdp_noise_class = class_new(gensym("pdp_noise"), (t_newmethod)pdp_noise_new, + (t_method)pdp_noise_free, sizeof(t_pdp_noise), 0, A_NULL); + + pdp_imagebase_setup(pdp_noise_class); + + class_addmethod(pdp_noise_class, (t_method)pdp_noise_random, gensym("seed"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_noise_class, (t_method)pdp_noise_type, gensym("type"), A_SYMBOL, A_NULL); + class_addmethod(pdp_noise_class, (t_method)pdp_noise_dim, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_noise_class, (t_method)pdp_noise_bang, gensym("bang"), A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_basic/pdp_plasma.c b/modules/image_basic/pdp_plasma.c new file mode 100644 index 0000000..78d886c --- /dev/null +++ b/modules/image_basic/pdp_plasma.c @@ -0,0 +1,166 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_imagebase.h" + + +typedef struct pdp_plasma_struct +{ + t_pdp_imagebase x_base; + + int x_packet0; + t_outlet *x_outlet0; + void *x_plasmagen; + + t_symbol *x_type; + + unsigned int x_width; + unsigned int x_height; + +} t_pdp_plasma; + + + +void pdp_plasma_type(t_pdp_plasma *x, t_symbol *s) +{ + x->x_type = s; +} + + +void pdp_plasma_random(t_pdp_plasma *x, t_floatarg seed) +{ + if (seed == 0.0f) seed = (float)random(); + pdp_imageproc_plasma_setseed(x->x_plasmagen, seed); + +} + +void pdp_plasma_turbulence(t_pdp_plasma *x, t_floatarg f) +{ + pdp_imageproc_plasma_setturbulence(x->x_plasmagen, f); + +} + +/* called inside pdp thread */ +static void pdp_plasma_process(t_pdp_plasma *x) +{ + /* seed the 16 bit rng with a new random number from the clib */ + pdp_plasma_random(x, 0.0f); + + /* create new packet */ + if (x->x_type == gensym("grey")) {x->x_packet0 = pdp_packet_new_image_grey(x->x_width, x->x_height);} + else if (x->x_type == gensym("yv12")) {x->x_packet0 = pdp_packet_new_image_YCrCb(x->x_width, x->x_height);} + else return; + + /* call the image processor */ + pdp_imageproc_dispatch_1buf(&pdp_imageproc_plasma_process, x->x_plasmagen, + -1, x->x_packet0); +} + +/* called inside pd thread: involves an outlet */ +static void pdp_plasma_postproc(t_pdp_plasma *x) +{ + pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet0); +} + +static void pdp_plasma_bang(t_pdp_plasma *x) +{ + pdp_base_bang(x); +} + +static void pdp_plasma_dim(t_pdp_plasma *x, t_floatarg w, t_floatarg h) +{ + x->x_width = pdp_imageproc_legalwidth((int)w); + x->x_height = pdp_imageproc_legalheight((int)h); + //post("dims %d %d", x->x_width, x->x_height); +} + + +static void pdp_plasma_free(t_pdp_plasma *x) +{ + pdp_imagebase_free(x); + + /* tidy up */ + pdp_packet_mark_unused(x->x_packet0); + pdp_imageproc_plasma_delete(x->x_plasmagen); +} + +t_class *pdp_plasma_class; + + +void *pdp_plasma_new(void) +{ + int i; + + t_pdp_plasma *x = (t_pdp_plasma *)pd_new(pdp_plasma_class); + + pdp_imagebase_init(x); + pdp_base_disable_active_inlet(x); + pdp_base_set_process_method(x, (t_pdp_method)pdp_plasma_process); + pdp_base_set_postproc_method(x, (t_pdp_method)pdp_plasma_postproc); + + pdp_base_add_gen_inlet(x, gensym("float"), gensym("turbulence")); + x->x_outlet0 = pdp_base_add_pdp_outlet(x); + x->x_packet0 = -1; + + x->x_width = 320; + x->x_height = 240; + + x->x_plasmagen = pdp_imageproc_plasma_new(); + + pdp_plasma_random(x, 0.0f); + pdp_plasma_type(x, gensym("yv12")); + pdp_plasma_turbulence(x, 0.1); + + + return (void *)x; +} + + + +#ifdef __cplusplus +extern "C" +{ +#endif + + + +void pdp_plasma_setup(void) +{ + + + pdp_plasma_class = class_new(gensym("pdp_plasma"), (t_newmethod)pdp_plasma_new, + (t_method)pdp_plasma_free, sizeof(t_pdp_plasma), 0, A_NULL); + + pdp_imagebase_setup(pdp_plasma_class); + + class_addmethod(pdp_plasma_class, (t_method)pdp_plasma_random, gensym("seed"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_plasma_class, (t_method)pdp_plasma_turbulence, gensym("turbulence"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_plasma_class, (t_method)pdp_plasma_type, gensym("type"), A_SYMBOL, A_NULL); + class_addmethod(pdp_plasma_class, (t_method)pdp_plasma_dim, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_plasma_class, (t_method)pdp_plasma_bang, gensym("bang"), A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_basic/pdp_randmix.c b/modules/image_basic/pdp_randmix.c new file mode 100644 index 0000000..2fd6adf --- /dev/null +++ b/modules/image_basic/pdp_randmix.c @@ -0,0 +1,113 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_imagebase.h" + +typedef struct pdp_randmix_struct +{ + t_pdp_imagebase x_base; + void *x_randmixer; + +} t_pdp_randmix; + + +void pdp_randmix_random(t_pdp_randmix *x, t_floatarg seed) +{ + pdp_imageproc_randmix_setseed(x->x_randmixer, seed); +} + + +static void pdp_randmix_process(t_pdp_randmix *x) +{ + int p0 = pdp_base_get_packet(x, 0); + int p1 = pdp_base_get_packet(x, 1); + u32 mask = pdp_imagebase_get_chanmask(x); + pdp_imageproc_dispatch_2buf(&pdp_imageproc_randmix_process, x->x_randmixer, mask, p0, p1); + +} + + +static void pdp_randmix_threshold(t_pdp_randmix *x, t_floatarg f) +{ + pdp_imageproc_randmix_setthreshold(x->x_randmixer, f); + +} + + + +static void pdp_randmix_free(t_pdp_randmix *x) +{ + pdp_imagebase_free(x); + pdp_imageproc_randmix_delete(x->x_randmixer); +} + +t_class *pdp_randmix_class; + + +void *pdp_randmix_new(void) +{ + int i; + + t_pdp_randmix *x = (t_pdp_randmix *)pd_new(pdp_randmix_class); + + pdp_imagebase_init(x); + pdp_base_add_pdp_inlet(x); + pdp_base_add_gen_inlet(x, gensym("float"), gensym("threshold")); + + pdp_base_set_process_method(x, (t_pdp_method)pdp_randmix_process); + + pdp_base_add_pdp_outlet(x); + x->x_randmixer = pdp_imageproc_randmix_new(); + + pdp_randmix_threshold(x, 0.5f); + pdp_randmix_random(x, 0.0f); + + return (void *)x; +} + + + +#ifdef __cplusplus +extern "C" +{ +#endif + + + +void pdp_randmix_setup(void) +{ + + + pdp_randmix_class = class_new(gensym("pdp_randmix"), (t_newmethod)pdp_randmix_new, + (t_method)pdp_randmix_free, sizeof(t_pdp_randmix), 0, A_NULL); + + pdp_imagebase_setup(pdp_randmix_class); + + class_addmethod(pdp_randmix_class, (t_method)pdp_randmix_threshold, gensym("threshold"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_randmix_class, (t_method)pdp_randmix_random, gensym("seed"), A_DEFFLOAT, A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_basic/pdp_stateless.c b/modules/image_basic/pdp_stateless.c new file mode 100644 index 0000000..cdcf313 --- /dev/null +++ b/modules/image_basic/pdp_stateless.c @@ -0,0 +1,185 @@ +/* + * Pure Data Packet module. Some stateless image operations. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_imagebase.h" + +typedef struct pdp_stateless_struct +{ + t_pdp_imagebase x_base; + +} t_pdp_stateless; + + + +static void pdp_stateless_process_abs(t_pdp_stateless *x) +{ + int p0 = pdp_base_get_packet(x, 0); + u32 mask = pdp_imagebase_get_chanmask(x); + pdp_imageproc_dispatch_1buf(&pdp_imageproc_abs_process, 0, mask, p0); +} + +static void pdp_stateless_process_hardthresh(t_pdp_stateless *x) +{ + int p0 = pdp_base_get_packet(x, 0); + u32 mask = pdp_imagebase_get_chanmask(x); + pdp_imageproc_dispatch_1buf(&pdp_imageproc_hardthresh_process, 0, mask, p0); +} + +static void pdp_stateless_process_zthresh(t_pdp_stateless *x) +{ + int p0 = pdp_base_get_packet(x, 0); + u32 mask = pdp_imagebase_get_chanmask(x); + pdp_imageproc_dispatch_1buf(&pdp_imageproc_zthresh_process, 0, mask, p0); +} + +static void pdp_stateless_process_positive(t_pdp_stateless *x) +{ + int p0 = pdp_base_get_packet(x, 0); + u32 mask = pdp_imagebase_get_chanmask(x); + pdp_imageproc_dispatch_1buf(&pdp_imageproc_ispositive_process, 0, mask, p0); +} + +static void pdp_stateless_process_sign(t_pdp_stateless *x) +{ + int p0 = pdp_base_get_packet(x, 0); + u32 mask = pdp_imagebase_get_chanmask(x); + pdp_imageproc_dispatch_1buf(&pdp_imageproc_sign_process, 0, mask, p0); +} + +static void pdp_stateless_process_flip_tb(t_pdp_stateless *x) +{ + int p0 = pdp_base_get_packet(x, 0); + u32 mask = pdp_imagebase_get_chanmask(x); + pdp_imageproc_dispatch_1buf(&pdp_imageproc_flip_tb_process, 0, mask, p0); +} + +static void pdp_stateless_process_flip_lr(t_pdp_stateless *x) +{ + int p0 = pdp_base_get_packet(x, 0); + u32 mask = pdp_imagebase_get_chanmask(x); + pdp_imageproc_dispatch_1buf(&pdp_imageproc_flip_lr_process, 0, mask, p0); +} + +static void pdp_stateless_free(t_pdp_stateless *x) +{ + /* remove process method from queue before deleting data */ + pdp_imagebase_free(x); +} + +t_class *pdp_stateless_class; + + +/* common new method */ +void *pdp_stateless_new(void) +{ + t_pdp_stateless *x = (t_pdp_stateless *)pd_new(pdp_stateless_class); + + /* super init */ + pdp_imagebase_init(x); + + /* outlet */ + pdp_base_add_pdp_outlet(x); + + return (void *)x; +} + +void *pdp_stateless_new_abs(void) +{ + t_pdp_stateless *x = pdp_stateless_new(); + /* init in/out */ + pdp_base_set_process_method(x, (t_pdp_method)pdp_stateless_process_abs); + return (void *)x; +} + +void *pdp_stateless_new_zthresh(void) +{ + t_pdp_stateless *x = pdp_stateless_new(); + /* init in/out */ + pdp_base_set_process_method(x, (t_pdp_method)pdp_stateless_process_zthresh); + return (void *)x; +} + +void *pdp_stateless_new_positive(void) +{ + t_pdp_stateless *x = pdp_stateless_new(); + /* init in/out */ + pdp_base_set_process_method(x, (t_pdp_method)pdp_stateless_process_positive); + return (void *)x; +} + +void *pdp_stateless_new_sign(void) +{ + t_pdp_stateless *x = pdp_stateless_new(); + /* init in/out */ + pdp_base_set_process_method(x, (t_pdp_method)pdp_stateless_process_sign); + return (void *)x; +} + +void *pdp_stateless_new_flip_tb(void) +{ + t_pdp_stateless *x = pdp_stateless_new(); + /* init in/out */ + pdp_base_set_process_method(x, (t_pdp_method)pdp_stateless_process_flip_tb); + return (void *)x; +} + + +void *pdp_stateless_new_flip_lr(void) +{ + t_pdp_stateless *x = pdp_stateless_new(); + /* init in/out */ + pdp_base_set_process_method(x, (t_pdp_method)pdp_stateless_process_flip_lr); + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_stateless_setup(void) +{ + + + pdp_stateless_class = class_new(gensym("pdp_abs"), (t_newmethod)pdp_stateless_new_abs, + (t_method)pdp_stateless_free, sizeof(t_pdp_stateless), 0, A_NULL); + + pdp_imagebase_setup(pdp_stateless_class); + + class_addcreator((t_newmethod)pdp_stateless_new_zthresh, gensym("pdp_zthresh"), A_NULL); + class_addcreator((t_newmethod)pdp_stateless_new_positive, gensym("pdp_positive"), A_NULL); + class_addcreator((t_newmethod)pdp_stateless_new_sign, gensym("pdp_sign"), A_NULL); + class_addcreator((t_newmethod)pdp_stateless_new_flip_tb, gensym("pdp_flip_tb"), A_NULL); + class_addcreator((t_newmethod)pdp_stateless_new_flip_lr, gensym("pdp_flip_lr"), A_NULL); + + /* future extensions */ + //class_addcreator((t_newmethod)pdp_stateless_new_garble, gensym("pdp_garble"), A_NULL); + + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_basic/pdp_zoom.c b/modules/image_basic/pdp_zoom.c new file mode 100644 index 0000000..48ba167 --- /dev/null +++ b/modules/image_basic/pdp_zoom.c @@ -0,0 +1,221 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_imagebase.h" + + + +typedef struct pdp_zoom_struct +{ + t_pdp_imagebase x_base; + + int x_packet1; + t_outlet *x_outlet0; + void *x_zoom; + + int x_quality; //not used + + +} t_pdp_zoom; + + +static void pdp_zoom_process(t_pdp_zoom *x) +{ + int p0 = pdp_base_get_packet(x, 0); + u32 mask = pdp_imagebase_get_chanmask(x); + pdp_imageproc_dispatch_2buf(&pdp_imageproc_resample_affinemap_process, x->x_zoom, mask, p0, x->x_packet1); +} + +static void pdp_zoom_postproc(t_pdp_zoom *x) +{ + /* delete source packet */ + pdp_packet_mark_unused(pdp_base_move_packet(x, 0)); + + /* unregister and propagate if valid dest packet */ + pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet1); +} + +static void pdp_zoom_preproc(t_pdp_zoom *x) +{ + int p = pdp_base_get_packet(x, 0); + t_pdp *header0 = pdp_packet_header(p); + if ((header0) && (PDP_IMAGE == header0->type)){ + x->x_packet1 = pdp_packet_clone_rw(p); + } + +} + + + +static void pdp_zoom_zoom_x(t_pdp_zoom *x, t_floatarg f) +{ + pdp_imageproc_resample_affinemap_setzoomx(x->x_zoom, f); +} + +static void pdp_zoom_angle(t_pdp_zoom *x, t_floatarg f) +{ + pdp_imageproc_resample_affinemap_setangle(x->x_zoom, f); +} + +static void pdp_zoom_zoom_y(t_pdp_zoom *x, t_floatarg f) +{ + pdp_imageproc_resample_affinemap_setzoomy(x->x_zoom, f); +} + +static void pdp_zoom_zoom(t_pdp_zoom *x, t_floatarg f) +{ + pdp_zoom_zoom_x(x, f); + pdp_zoom_zoom_y(x, f); +} + +static void pdp_zoom_center_x(t_pdp_zoom *x, t_floatarg f) +{ + pdp_imageproc_resample_affinemap_setcenterx(x->x_zoom, f); +} + +static void pdp_zoom_center_y(t_pdp_zoom *x, t_floatarg f) +{ + pdp_imageproc_resample_affinemap_setcentery(x->x_zoom, f); +} +static void pdp_zoom_center(t_pdp_zoom *x, t_floatarg fx, t_floatarg fy) +{ + pdp_zoom_center_x(x, fx); + pdp_zoom_center_y(x, fy); +} + +// not used +static void pdp_zoom_quality(t_pdp_zoom *x, t_floatarg f) +{ + if (f==0) x->x_quality = 0; + if (f==1) x->x_quality = 1; +} + + +t_class *pdp_zoom_class; + + + +void pdp_zoom_free(t_pdp_zoom *x) +{ + pdp_imagebase_free(x); + pdp_imageproc_resample_affinemap_delete(x->x_zoom); + pdp_packet_mark_unused(x->x_packet1); +} + + +void pdp_zoom_init_common(t_pdp_zoom *x) +{ + pdp_imagebase_init(x); + pdp_base_set_process_method(x, (t_pdp_method)pdp_zoom_process); + pdp_base_set_postproc_method(x, (t_pdp_method)pdp_zoom_postproc); + pdp_base_set_preproc_method(x, (t_pdp_method)pdp_zoom_preproc); + + x->x_outlet0 = pdp_base_add_pdp_outlet(x); + x->x_packet1 = -1; + x->x_zoom = pdp_imageproc_resample_affinemap_new(); + + //quality is not used: all routines are "high quality" bilinear + //pdp_zoom_quality(x, 1); + pdp_zoom_center_x(x, 0.5f); + pdp_zoom_center_y(x, 0.5f); + +} + + +void *pdp_zoom_new(t_floatarg zoom) +{ + t_pdp_zoom *x = (t_pdp_zoom *)pd_new(pdp_zoom_class); + + pdp_zoom_init_common(x); + pdp_base_add_gen_inlet(x, gensym("float"), gensym("zoom")); + + if (zoom == 0.0f) zoom = 1.0f; + pdp_zoom_zoom(x, zoom); + pdp_zoom_angle(x, 0.0f); + + return (void *)x; +} + +void *pdp_zrot_new(t_floatarg zoom, t_floatarg angle) +{ + t_pdp_zoom *x = (t_pdp_zoom *)pd_new(pdp_zoom_class); + + pdp_zoom_init_common(x); + pdp_base_add_gen_inlet(x, gensym("float"), gensym("zoom")); + pdp_base_add_gen_inlet(x, gensym("float"), gensym("angle")); + + + if (zoom == 0.0f) zoom = 1.0f; + pdp_zoom_zoom(x, zoom); + pdp_zoom_angle(x, angle); + + return (void *)x; +} + +void *pdp_rotate_new(t_floatarg angle) +{ + t_pdp_zoom *x = (t_pdp_zoom *)pd_new(pdp_zoom_class); + + pdp_zoom_init_common(x); + + pdp_base_add_gen_inlet(x, gensym("float"), gensym("angle")); + + pdp_zoom_zoom(x, 1.0f); + pdp_zoom_angle(x, angle); + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_zoom_setup(void) +{ + + pdp_zoom_class = class_new(gensym("pdp_zoom"), (t_newmethod)pdp_zoom_new, + (t_method)pdp_zoom_free, sizeof(t_pdp_zoom), 0, A_DEFFLOAT, A_NULL); + + class_addcreator((t_newmethod)pdp_zrot_new, gensym("pdp_zrot"), A_DEFFLOAT, A_DEFFLOAT, A_NULL); + class_addcreator((t_newmethod)pdp_rotate_new, gensym("pdp_rotate"), A_DEFFLOAT, A_NULL); + + pdp_imagebase_setup(pdp_zoom_class); + + class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_quality, gensym("quality"), A_FLOAT, A_NULL); + class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_center_x, gensym("centerx"), A_FLOAT, A_NULL); + class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_center_y, gensym("centery"), A_FLOAT, A_NULL); + class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_center, gensym("center"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_zoom_x, gensym("zoomx"), A_FLOAT, A_NULL); + class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_zoom_y, gensym("zoomy"), A_FLOAT, A_NULL); + class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_zoom, gensym("zoom"), A_FLOAT, A_NULL); + class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_angle, gensym("angle"), A_FLOAT, A_NULL); + + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_io/Makefile b/modules/image_io/Makefile new file mode 100644 index 0000000..b306ad8 --- /dev/null +++ b/modules/image_io/Makefile @@ -0,0 +1,11 @@ +current: all_modules + +include ../../Makefile.config + +# build optional modules +all_modules: $(PDP_OPTMOD) + +clean: + rm -f *~ + rm -f *.o + diff --git a/modules/image_io/README b/modules/image_io/README new file mode 100644 index 0000000..9493047 --- /dev/null +++ b/modules/image_io/README @@ -0,0 +1,2 @@ +This directory contains input/output modules for image packets. +Most of this is platform dependent stuff, and will be conditionally compiled. diff --git a/modules/image_io/pdp_glx.c b/modules/image_io/pdp_glx.c new file mode 100644 index 0000000..1df127f --- /dev/null +++ b/modules/image_io/pdp_glx.c @@ -0,0 +1,582 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +// gl stuff +#include <GL/gl.h> +#include <GL/glx.h> +#include <GL/glu.h> +//#include <GL/glut.h> + +// pdp stuff +#include "pdp.h" +#include "pdp_base.h" + +// some x window glue code +#include "pdp_xwindow.h" + +// pdp stuff +#include "pdp.h" +#include "pdp_llconv.h" +//#include "pdp_opengl.h" + + +/* initial image dimensions */ +#define PDP_OGL_W 320 +#define PDP_OGL_H 240 + +#define PDP_OGL_AUTOCREATE_RETRY 10 + + +typedef struct pdp_glx_struct +{ + t_object x_obj; + + t_pdp_xwindow *x_xwin; + + t_outlet *x_outlet; + + int x_packet0; + int x_queue_id; + t_symbol *x_display; + + t_pdp_xdisplay *x_xdpy; + + XVisualInfo *x_vis_info; + GLXContext x_glx_context; + + GLuint x_texture; + u32 x_tex_width; + u32 x_tex_height; + + unsigned char *x_data; + unsigned int x_width; + unsigned int x_height; + int x_last_encoding; + + int x_initialized; + int x_autocreate; + +} t_pdp_glx; + + + +static void pdp_glx_cursor(t_pdp_glx *x, t_floatarg f) +{ + if (x->x_initialized) + pdp_xwindow_cursor(x->x_xwin, f); +} + +static void pdp_glx_destroy(t_pdp_glx* x) +{ + t_pdp_procqueue *q = pdp_queue_get_queue(); + XEvent e; + + if (x->x_initialized){ + pdp_procqueue_finish(q, x->x_queue_id); + x->x_queue_id = -1; + glXDestroyContext(x->x_xdpy->dpy, x->x_glx_context); + pdp_xwindow_free(x->x_xwin); + pdp_xdisplay_free(x->x_xdpy); + x->x_xwin = 0; + x->x_xdpy = 0; + x->x_initialized = false; + } + +} + + +static void pdp_glx_fullscreen(t_pdp_glx *x) +{ + if (x->x_initialized) + pdp_xwindow_fullscreen(x->x_xwin); +} + +static void pdp_glx_resize(t_pdp_glx* x, t_floatarg width, t_floatarg height) +{ + if (x->x_initialized) + pdp_xwindow_resize(x->x_xwin, width, height); +} + +static void pdp_glx_move(t_pdp_glx* x, t_floatarg width, t_floatarg height) +{ + if (x->x_initialized) + pdp_xwindow_move(x->x_xwin, width, height); +} + +static void pdp_glx_moveresize(t_pdp_glx* x, t_floatarg xoff, t_floatarg yoff, t_floatarg width, t_floatarg height) +{ + if (x->x_initialized) + pdp_xwindow_moveresize(x->x_xwin, xoff, yoff, width, height); +} + +static void pdp_glx_tile(t_pdp_glx* x, t_floatarg xtiles, t_floatarg ytiles, t_floatarg i, t_floatarg j) +{ + if (x->x_initialized) + pdp_xwindow_tile(x->x_xwin, xtiles, ytiles, i, j); +} + + + + +void pdp_glx_generate_texture(t_pdp_glx *x) +{ + u32 width = x->x_tex_width; + u32 height = x->x_tex_height; + u32 depth = 4; + u32 i; + + u8 *dummydata = 0; + + while (x->x_width > width) width <<= 1; + while (x->x_height > height) height <<= 1; + + dummydata = (u8 *)pdp_alloc(width*height*depth); + + for (i=0; i<width*height*depth; i++){dummydata[i] = random(); } + + /* set window context current */ + glXMakeCurrent(x->x_xdpy->dpy, x->x_xwin->win, x->x_glx_context); + + /* generate texture if necessary */ + if (!glIsTexture(x->x_texture)) glGenTextures(1, &(x->x_texture)); + + glBindTexture(GL_TEXTURE_2D, x->x_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, dummydata); + + pdp_dealloc(dummydata); + + x->x_tex_width = width; + x->x_tex_height = height; +} + +void pdp_glx_regenerate_texture(t_pdp_glx *x) +{ + if ((x->x_width > x->x_tex_width) || (x->x_height > x->x_tex_height)) pdp_glx_generate_texture(x); + +} + + +static void pdp_glx_create(t_pdp_glx* x) +{ + unsigned int *uintdata = (unsigned int *)(x->x_data); + XEvent e; + unsigned int i; + static int vis_attr[] = {GLX_RGBA, GLX_RED_SIZE, 4, GLX_GREEN_SIZE, 4, GLX_BLUE_SIZE, 4, + GLX_DEPTH_SIZE, 16, GLX_DOUBLEBUFFER, None}; + + + if (x->x_initialized) return; + + /* manually open a display */ + if (NULL == (x->x_xdpy = pdp_xdisplay_new(x->x_display->s_name))){ + post("pdp_glx: cant open display %s\n",x->x_display->s_name); + x->x_initialized = false; + return; + } + + /* create a window on the display */ + x->x_xwin = pdp_xwindow_new(); + if (!(x->x_initialized = pdp_xwindow_create_on_display(x->x_xwin, x->x_xdpy))) + goto exit_error; + + + /* create a glx visual */ + if (!(x->x_vis_info = glXChooseVisual(x->x_xdpy->dpy, x->x_xdpy->screen, vis_attr))){ + post("pdp_glx: can't create visual"); + goto exit_error; + } + //post("visual: %x", x->x_vis_info); + + /* create the rendering context */ + if (!(x->x_glx_context = glXCreateContext(x->x_xdpy->dpy, x->x_vis_info, 0 /*share list*/, GL_TRUE))){ + post("pdp_glx: can't create render context"); + goto exit_error; + } + //post("context: %x", x->x_glx_context); + + + /* create texture */ + pdp_glx_generate_texture(x); + + + /* we're done initializing */ + x->x_initialized = true; + + /* disable/enable cursor */ + //pdp_glx_cursor(x, x->x_cursor); + return; + + + exit_error: + if (x->x_xwin){ + pdp_xwindow_free(x->x_xwin); + x->x_xwin = 0; + } + + if (x->x_xdpy){ + pdp_xdisplay_free(x->x_xdpy); + x->x_xdpy = 0; + } + + x->x_initialized = false; + return; +} + +static int pdp_glx_try_autocreate(t_pdp_glx *x) +{ + + if (x->x_autocreate){ + post("pdp_glx: autocreate window"); + pdp_glx_create(x); + if (!(x->x_initialized)){ + x->x_autocreate--; + if (!x->x_autocreate){ + post ("pdp_glx: autocreate failed %d times: disabled", PDP_OGL_AUTOCREATE_RETRY); + post ("pdp_glx: send [autocreate 1] message to re-enable"); + return 0; + } + } + else return 1; + + } + return 0; +} + +static void pdp_glx_bang(t_pdp_glx *x); + +static void pdp_glx_fill_texture(t_pdp_glx *x) +{ + t_pdp *header = pdp_packet_header(x->x_packet0); + void *data = pdp_packet_data (x->x_packet0); + + int i = header->info.image.width; + + + /* ensure image buffer is correct dim */ + if ((header->info.image.width != x->x_width) + || (header->info.image.height != x->x_height)) { + if (x->x_data) pdp_dealloc (x->x_data); + x->x_width = header->info.image.width; + x->x_height = header->info.image.height; + x->x_data = pdp_alloc(4*x->x_width*x->x_height); + } + + /* ensure texture is correct dim */ + pdp_glx_regenerate_texture(x); + + + /* set window context current */ + glXMakeCurrent(x->x_xdpy->dpy, x->x_xwin->win, x->x_glx_context); + glBindTexture(GL_TEXTURE_2D, x->x_texture); + + switch (header->info.image.encoding){ + case PDP_IMAGE_GREY: + /* convert image to greyscale 8 bit */ + pdp_llconv(data,RIF_GREY______S16, x->x_data, RIF_GREY______U8, x->x_width, x->x_height); + + /* upload grey subtexture */ + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, x->x_width, x->x_height, GL_LUMINANCE, GL_UNSIGNED_BYTE, x->x_data); + + break; + case PDP_IMAGE_YV12: + + /* convert image to rgb 8 bit */ + pdp_llconv(data,RIF_YVU__P411_S16, x->x_data, RIF_RGB__P____U8, x->x_width, x->x_height); + + /* upload subtexture */ + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, x->x_width, x->x_height, GL_RGB, GL_UNSIGNED_BYTE, x->x_data); + + break; + default: + break; + } + + +} + +static void pdp_glx_process(t_pdp_glx *x) +{ + t_pdp *header = pdp_packet_header(x->x_packet0); + void *data = pdp_packet_data (x->x_packet0); + + + if (-1 != x->x_queue_id) return; + + /* check if window is initialized */ + if (!(x->x_initialized)){ + if (!pdp_glx_try_autocreate(x)) return; + } + + /* check data packet */ + if (!(header)) { + post("pdp_glx: invalid packet header"); + return; + } + if (PDP_IMAGE != header->type) { + post("pdp_glx: packet is not a PDP_IMAGE"); + return; + } + if ((PDP_IMAGE_YV12 != header->info.image.encoding) + && (PDP_IMAGE_GREY != header->info.image.encoding)) { + post("pdp_glx: packet is not a PDP_IMAGE_YV12/GREY"); + return; + } + + + /* fill the texture with the data in the packet */ + pdp_glx_fill_texture(x); + + /* display the new image */ + pdp_glx_bang(x); + + +} + + + +static void pdp_glx_display_texture(t_pdp_glx *x) +{ + float fx = (float)x->x_width / x->x_tex_width; + float fy = (float)x->x_height / x->x_tex_height; + + if (!x->x_initialized) return; + + /* set window context current */ + glXMakeCurrent(x->x_xdpy->dpy, x->x_xwin->win, x->x_glx_context); + + /* setup viewport, projection and modelview */ + glViewport(0, 0, x->x_xwin->winwidth, x->x_xwin->winheight); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluOrtho2D(0.0, x->x_xwin->winwidth, 0.0, x->x_xwin->winheight); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + + /* enable default texture */ + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, x->x_texture); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + /* display texture */ + glBegin(GL_QUADS); + glTexCoord2f(fx, fy); + glVertex2i(x->x_xwin->winwidth,0); + glTexCoord2f(fx, 0); + glVertex2i(x->x_xwin->winwidth, x->x_xwin->winheight); + glTexCoord2f(0.0, 0.0); + glVertex2i(0, x->x_xwin->winheight); + glTexCoord2f(0, fy); + glVertex2i(0,0); + glEnd(); + + + glFlush(); + glXSwapBuffers(x->x_xdpy->dpy,x->x_xwin->win); + +} + + + +/* redisplays image */ +static void pdp_glx_bang_thread(t_pdp_glx *x) +{ + + + pdp_glx_display_texture(x); + XFlush(x->x_xdpy->dpy); + +} + +static void pdp_glx_bang_callback(t_pdp_glx *x) +{ + /* receive events + send to outputs */ + t_pdp_list *eventlist = pdp_xwindow_get_eventlist(x->x_xwin); + t_pdp_atom *a; + + for (a=eventlist->first; a; a=a->next){ + //pdp_list_print(a->w.w_list); + outlet_pdp_list(x->x_outlet, a->w.w_list); + } + + /* free list */ + pdp_tree_free(eventlist); + + /* release the packet if there is one */ + pdp_packet_mark_unused(x->x_packet0); + x->x_packet0 = -1; + +} +static void pdp_glx_bang(t_pdp_glx *x) +{ + + /* check if window is initialized */ + if (!(x->x_initialized)){ + if (!pdp_glx_try_autocreate(x)) return; + } + + + /* if previous queued method returned + schedule a new one, else ignore */ + +/* + if (-1 == x->x_queue_id) { + pdp_queue_add(x, pdp_glx_bang_thread, pdp_glx_bang_callback, &x->x_queue_id); + } +*/ + /* don't process in thread */ + pdp_glx_bang_thread(x); + pdp_glx_bang_callback(x); + +} + + + +static void pdp_glx_input_0(t_pdp_glx *x, t_symbol *s, t_floatarg f) +{ + + if (s == gensym("register_ro")) pdp_packet_copy_ro_or_drop(&x->x_packet0, (int)f); + if (s == gensym("process")) pdp_glx_process(x); +} + + + +static void pdp_glx_vga(t_pdp_glx *x) +{ + pdp_glx_resize(x, 640, 480); +} + +static void pdp_glx_autocreate(t_pdp_glx *x, t_floatarg f) +{ + if (f != 0.0f) x->x_autocreate = PDP_OGL_AUTOCREATE_RETRY; + else x->x_autocreate = 0; +} + +static void pdp_glx_display(t_pdp_glx *x, t_symbol *s) +{ + t_pdp_procqueue *q = pdp_queue_get_queue(); + pdp_procqueue_finish(q, x->x_queue_id); + x->x_queue_id = -1; + x->x_display = s; + if (x->x_initialized){ + pdp_glx_destroy(x); + pdp_glx_create(x); + } +} + + + +static void pdp_glx_free(t_pdp_glx *x) +{ + t_pdp_procqueue *q = pdp_queue_get_queue(); + pdp_procqueue_finish(q, x->x_queue_id); + pdp_glx_destroy(x); + if (x->x_data) pdp_dealloc (x->x_data); + pdp_packet_mark_unused(x->x_packet0); +} + +t_class *pdp_glx_class; + + + +void *pdp_glx_new(void) +{ + t_pdp_glx *x = (t_pdp_glx *)pd_new(pdp_glx_class); + + x->x_xwin = 0; + x->x_xdpy = 0; + + x->x_outlet = outlet_new(&x->x_obj, &s_anything); + + x->x_packet0 = -1; + x->x_queue_id = -1; + x->x_display = gensym(":0"); + + x->x_width = PDP_OGL_W; + x->x_height = PDP_OGL_H; + + x->x_data = pdp_alloc(4*PDP_OGL_W*PDP_OGL_H); + + x->x_initialized = 0; + pdp_glx_autocreate(x,1); + x->x_last_encoding = -1; + + x->x_tex_width = 64; + x->x_tex_height = 64; + + //pdp_glx_create(x); + + return (void *)x; +} + + + + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_glx_setup(void) +{ + + + pdp_glx_class = class_new(gensym("pdp_glx"), (t_newmethod)pdp_glx_new, + (t_method)pdp_glx_free, sizeof(t_pdp_glx), 0, A_NULL); + + /* add creator for pdp_tex_win */ + + class_addmethod(pdp_glx_class, (t_method)pdp_glx_bang, gensym("bang"), A_NULL); + class_addmethod(pdp_glx_class, (t_method)pdp_glx_create, gensym("open"), A_NULL); + class_addmethod(pdp_glx_class, (t_method)pdp_glx_create, gensym("create"), A_NULL); + class_addmethod(pdp_glx_class, (t_method)pdp_glx_autocreate, gensym("autocreate"), A_FLOAT, A_NULL); + class_addmethod(pdp_glx_class, (t_method)pdp_glx_destroy, gensym("destroy"), A_NULL); + class_addmethod(pdp_glx_class, (t_method)pdp_glx_destroy, gensym("close"), A_NULL); + class_addmethod(pdp_glx_class, (t_method)pdp_glx_move, gensym("move"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_glx_class, (t_method)pdp_glx_move, gensym("pos"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_glx_class, (t_method)pdp_glx_resize, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_glx_class, (t_method)pdp_glx_resize, gensym("size"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_glx_class, (t_method)pdp_glx_display, gensym("display"), A_SYMBOL, A_NULL); + class_addmethod(pdp_glx_class, (t_method)pdp_glx_cursor, gensym("cursor"), A_FLOAT, A_NULL); + class_addmethod(pdp_glx_class, (t_method)pdp_glx_fullscreen, gensym("fullscreen"), A_NULL); + class_addmethod(pdp_glx_class, (t_method)pdp_glx_moveresize, gensym("posdim"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_glx_class, (t_method)pdp_glx_tile, gensym("tile"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL); + + + /* accept both pdp and pdp_tex packets */ + class_addmethod(pdp_glx_class, (t_method)pdp_glx_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + + + /* some shortcuts for the lazy */ + class_addmethod(pdp_glx_class, (t_method)pdp_glx_vga, gensym("vga"), A_NULL); + +} + +#ifdef __cplusplus +} +#endif + + diff --git a/modules/image_io/pdp_qt.c b/modules/image_io/pdp_qt.c new file mode 100644 index 0000000..5e1111c --- /dev/null +++ b/modules/image_io/pdp_qt.c @@ -0,0 +1,974 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +#include <quicktime/lqt.h> +#include <quicktime/colormodels.h> + +#include "pdp.h" +#include "pdp_llconv.h" + + +#define min(x,y) ((x<y)?(x):(y)) + + + +#define FREE(x) {if (x) {pdp_dealloc(x); x=0;} else post("free null pointer");} + + +/* debug macro */ +//#define DEBUG_MSG_ENABLED + +#ifdef DEBUG_MSG_ENABLED + +#define DEBUG_MSG(EXP)\ +fprintf (stderr, "mark start: [" #EXP "], on line %d\n", __LINE__);\ + EXP \ +fprintf (stderr, "mark end: [" #EXP "], on line %d\n", __LINE__); + +#else +#define DEBUG_MSG(EXP) EXP +#endif + +typedef struct pdp_qt_struct +{ + t_object x_obj; + t_float x_f; + + float x_gain; + + + t_symbol *x_name; // this is our name + int x_istilde; // 0==pdp_qt / 1==pdp_qt~ + int x_syncaudio; + + + /* clock object */ + t_clock *x_clock; + int x_counter; + int x_queue_id; + + /* audio outlets */ + t_outlet *x_outleft; + t_outlet *x_outright; + + /* message outlets */ + t_outlet *x_outlet0; + t_outlet *x_outlet1; + t_outlet *x_outlet2; + + /* pdp data */ + int x_packet0; + + /* toggles */ + int x_loop; + int x_autoplay; + + /* qt data */ + unsigned char ** x_qt_rows; // pointer array to rows / colour planes + float ** x_qt_audiochans; // pointer array to audio channel buffers + unsigned char * x_qt_frame; + quicktime_t *x_qt; + int x_qt_cmodel; + + //t_pdp_qt_data *x_state_data; + + /* audio data */ + int x_chunk_current; + float *x_chunk_buf; + float *x_chunk[2][2]; + int x_chunk_used[2]; // marks if chunk is used or not + int x_chunk_size; + int x_chunk_pos; + + /* global state */ + int x_initialized; + int x_frame; + int x_frame_thread; + int x_process_in_thread; + + + /* audio info */ + int x_audio_tracks; // ==0 means audio not available + int x_audio_channels; + long x_audio_samplerate; + long x_audio_length; + + /* video info */ + int x_video_tracks; // ==0 means video not available + float x_video_framerate; + long x_video_length; + unsigned int x_video_width; + unsigned int x_video_height; + + +} t_pdp_qt; + + +static void pdp_qt_bang(t_pdp_qt *x); + +static void pdp_qt_close(t_pdp_qt *x) +{ + t_pdp_procqueue *q = pdp_queue_get_queue(); + + /* disable clock */ + clock_unset(x->x_clock); + pdp_procqueue_finish(q, x->x_queue_id); + + if (x->x_initialized){ + /* close file */ + quicktime_close(x->x_qt); + x->x_initialized = 0; + + + /* free video data */ + if (x->x_video_tracks){ + FREE(x->x_qt_frame); + FREE(x->x_qt_rows); + x->x_video_tracks = 0; + //x->x_qt_rows = 0; + //x->x_qt_frame = 0; + } + + /* free audio data */ + if (x->x_audio_tracks){ + x->x_chunk_used[0] = 0; + x->x_chunk_used[1] = 0; + FREE(x->x_chunk_buf); + FREE(x->x_qt_audiochans); + x->x_audio_tracks = 0; + //x->x_qt_audiochans = 0; + //x->x_chunk_buf = 0; + x->x_chunk[0][0] = 0; + x->x_chunk[0][1] = 0; + x->x_chunk[1][0] = 0; + x->x_chunk[1][1] = 0; + } + + + } + + +} + +void pdp_qt_create_pdp_packet(t_pdp_qt *x) +{ + t_pdp *header; + t_image *image; + + + /* round to next legal size */ + /* if size is illegal, image distortion will occur */ + u32 w = pdp_imageproc_legalwidth(x->x_video_width); + u32 h = pdp_imageproc_legalheight(x->x_video_height); + + + int nbpixels = w * h; + int packet_size = (nbpixels + (nbpixels >> 1)) << 1; + + + pdp_packet_mark_unused(x->x_packet0); + x->x_packet0 = pdp_packet_new_image_YCrCb(w, h); + header = pdp_packet_header(x->x_packet0); + image = pdp_packet_image_info(x->x_packet0); + + if (!header){ + post("%s: ERROR: can't create new packet", x->x_name->s_name); + return; + } + + + //header->info.image.encoding = (x->x_qt_cmodel == BC_RGB888) ? PDP_IMAGE_GREY : PDP_IMAGE_YV12; + //image->encoding = PDP_IMAGE_YV12; + //image->width = w; + //image->height = h; +} + + + + +static void pdp_qt_open(t_pdp_qt *x, t_symbol *name) +{ + unsigned int size; + unsigned int i; + unsigned int chunk_bytesize; + + post("%s: opening %s", x->x_name->s_name, name->s_name); + + + /* close previous one */ + pdp_qt_close(x); + + + /* check if qt file */ + if(0 == quicktime_check_sig(name->s_name)){ + post("%s: ERROR: not a quicktime file", x->x_name->s_name); + goto exit; + } + + /* open */ + DEBUG_MSG(x->x_qt = quicktime_open(name->s_name, 1, 0);) + if (!(x->x_qt)){ + post("%s: ERROR: can't open file", x->x_name->s_name); + goto exit; + } + + /* check video */ + x->x_video_tracks = 0; + if (quicktime_has_video(x->x_qt)) { + x->x_video_framerate = quicktime_frame_rate (x->x_qt, 0); + x->x_video_length = quicktime_video_length (x->x_qt, 0); + x->x_video_width = quicktime_video_width (x->x_qt, 0); + x->x_video_height = quicktime_video_height (x->x_qt, 0); + post("%s: video stream found (%dx%d pixels, %0.00f fps, %d frames, %s codec)", + x->x_name->s_name, x->x_video_width, x->x_video_height, x->x_video_framerate, + x->x_video_length, quicktime_video_compressor(x->x_qt, 0)); + x->x_video_tracks = quicktime_video_tracks(x->x_qt); + + } + + + /* check audior */ + x->x_audio_tracks = 0; + if (quicktime_has_audio(x->x_qt)) { + x->x_audio_tracks = quicktime_audio_tracks (x->x_qt); + //x->x_audio_channels = quicktime_track_channels (x->x_qt, 0); + x->x_audio_channels = lqt_total_channels (x->x_qt); + x->x_audio_samplerate = quicktime_sample_rate (x->x_qt, 0); + x->x_audio_length = quicktime_audio_length (x->x_qt, 0); + x->x_chunk_size = (int)((float)x->x_audio_samplerate / x->x_video_framerate); + post("%s: audio stream found (%d channels, %d Hz, %d samples, chunksize %d)", + x->x_name->s_name, x->x_audio_channels, x->x_audio_samplerate, x->x_audio_length, x->x_chunk_size); + } + + /* check if video codec is supported */ + if (x->x_video_tracks){ + if (!quicktime_supported_video(x->x_qt,0)) { + post("%s: WARNING: unsupported video codec",x->x_name->s_name); + x->x_video_tracks = 0; + } + } + + /* check if audio codec is supported */ + if (x->x_audio_tracks){ + if (!quicktime_supported_audio(x->x_qt,0)) { + post("%s: WARNING: unsupported audio codec", x->x_name->s_name); + x->x_audio_tracks = 0; + } + } + + + + /* check which colormodel to use */ + if (x->x_video_tracks){ + + if (quicktime_reads_cmodel(x->x_qt,BC_YUV420P,0)){ + post("%s: using colormodel YUV420P", x->x_name->s_name); + x->x_qt_cmodel = BC_YUV420P; + } + else if (quicktime_reads_cmodel(x->x_qt,BC_YUV422,0)){ + post("%s: using colormodel YUV422", x->x_name->s_name); + x->x_qt_cmodel = BC_YUV422; + } + else if (quicktime_reads_cmodel(x->x_qt,BC_RGB888,0)){ + post("%s: using colormodel RGB888", x->x_name->s_name); + x->x_qt_cmodel = BC_RGB888; + } + else { + post("%s: WARNING: can't find a usable colour model", x->x_name->s_name); + x->x_video_tracks = 0; + } + + } + + + + /* no video == errors */ + if (!x->x_video_tracks) { + post("%s: ERROR: no usable video stream found.", x->x_name->s_name); + goto exit_close; + } + + + /* initialize video data structures */ + if (x->x_video_tracks){ + + /* allocate enough space for all supported colormodels (24bpp)*/ + x->x_frame = 0; + x->x_qt_frame = (unsigned char*)pdp_alloc(x->x_video_width * x->x_video_height * 3); + x->x_qt_rows = (unsigned char **)pdp_alloc(sizeof(unsigned char *) * x->x_video_height); + size = x->x_video_width * x->x_video_height; + + switch(x->x_qt_cmodel){ + case BC_YUV420P: + /* planar with u&v 2x2 subsampled */ + x->x_qt_rows[0] = &x->x_qt_frame[0]; + x->x_qt_rows[2] = &x->x_qt_frame[size]; + x->x_qt_rows[1] = &x->x_qt_frame[size + (size>>2)]; + break; + + case BC_YUV422: + /* packed with u&v 2x subsampled (lines) */ + /* later on we will convert this to planar */ + for(i=0; i< x->x_video_height; i++) x->x_qt_rows[i] = &x->x_qt_frame[i * x->x_video_width * 2]; + break; + + case BC_RGB888: + /* packed rgb */ + /* later on we will convert this to planar */ + for(i=0; i< x->x_video_height; i++) x->x_qt_rows[i] = &x->x_qt_frame[i * x->x_video_width * 3]; + break; + + default: + post("%s: error on init: unkown colour model",x->x_name->s_name); + break; + } + + DEBUG_MSG(quicktime_set_cmodel(x->x_qt, x->x_qt_cmodel);) + outlet_float(x->x_outlet2, (float)quicktime_video_length(x->x_qt,0)); + + } + + /* initialize audio data structures */ + if (x->x_audio_tracks){ + x->x_chunk_pos = 0; + x->x_chunk_current = 0; + + chunk_bytesize = sizeof(float)*x->x_chunk_size; + x->x_chunk_buf = (float *)pdp_alloc(chunk_bytesize * 4); + memset(x->x_chunk_buf, 0, chunk_bytesize * 4); + x->x_chunk[0][0] = x->x_chunk_buf; + x->x_chunk[0][1] = x->x_chunk_buf + x->x_chunk_size ; + x->x_chunk[1][0] = x->x_chunk_buf + x->x_chunk_size * 2; + x->x_chunk[1][1] = x->x_chunk_buf + x->x_chunk_size * 3; + x->x_chunk_used[0] = 0; + x->x_chunk_used[1] = 0; + x->x_syncaudio = x->x_istilde; //sync on audio if this is a tilde object + + DEBUG_MSG(if (x->x_audio_channels == 0) exit(1);) + x->x_qt_audiochans = (float **)pdp_alloc(x->x_audio_channels * sizeof(float **)); + memset(x->x_qt_audiochans, 0, x->x_audio_channels * sizeof(float **)); + } + else { + x->x_syncaudio = 0; + } + + + /* everything went well */ + x->x_initialized = 1; + + /* start playback if outplay is on */ + if(x->x_autoplay) clock_delay(x->x_clock, 1000.0L / (double)x->x_video_framerate); + + /* brag about success */ + post("%s: %s opened", x->x_name->s_name, name->s_name); + + return; + + /* error exits */ + + exit_close: + DEBUG_MSG(quicktime_close(x->x_qt);) + + exit: + x->x_initialized = 0; + x->x_audio_tracks = 0; + x->x_video_tracks = 0; + return; + +} + + +//static void pdp_qt_setposition(t_pdp_qt *x, int pos) +//{ +// x->x_frame = pos; +// DEBUG_MSG(if(x->x_video_tracks) quicktime_set_video_position(x->x_qt, pos, 0);) +// DEBUG_MSG(if(x->x_audio_tracks) quicktime_set_audio_position(x->x_qt, pos * x->x_chunk_size, 0);) +// +//} + + +static void pdp_qt_bangaudio(t_pdp_qt *x) +{ + int lefterr=0; + int righterr=0; + int err=0; + int sample = 0; + int remaining = 0; + int readamount = 0; + + + + if (!x->x_initialized){ + //post("pdp_qt: no qt file opened"); + return; + } + + + if (!x->x_audio_tracks){ + //post("pdp_qt: no audio stream present"); + return; + } + + + + //DEBUG_MSG(sample = quicktime_audio_position(x->x_qt,0);) + + + // if the active chunk is unused, clear it and mark it used + if (!x->x_chunk_used[x->x_chunk_current]){ + //post("%s: clearing unused active chunk",x->x_name->s_name); + + + + //probably this is the !@#%&*(*)&!$() bug + //memset(x->x_chunk[0][x->x_chunk_current], 0, sizeof(float)*2*x->x_chunk_size); + //memset(x->x_chunk[1][x->x_chunk_current], 0, sizeof(float)*2*x->x_chunk_size); + + memset(x->x_chunk[0][x->x_chunk_current], 0, sizeof(float) * x->x_chunk_size); + memset(x->x_chunk[1][x->x_chunk_current], 0, sizeof(float) * x->x_chunk_size); + + + + + x->x_chunk_used[x->x_chunk_current] = 1; + } + + // compute the remaining time + DEBUG_MSG(remaining = (int ) ( quicktime_audio_length(x->x_qt, 0) - quicktime_audio_position(x->x_qt, 0) );) + readamount = min(remaining, x->x_chunk_size); + if (!readamount) return; + + + // if the inactive chunk is unused, fill it with the current frame's audio data and mark it used + if (!x->x_chunk_used[!x->x_chunk_current]){ + switch(x->x_audio_channels){ + case 1: + x->x_qt_audiochans[0] = x->x_chunk[0][!x->x_chunk_current]; + x->x_qt_audiochans[1] = 0; + DEBUG_MSG(err = lqt_decode_audio(x->x_qt, NULL, x->x_qt_audiochans, readamount);) + break; + default: + x->x_qt_audiochans[0] = x->x_chunk[0][!x->x_chunk_current]; + x->x_qt_audiochans[1] = x->x_chunk[1][!x->x_chunk_current]; + DEBUG_MSG(err = lqt_decode_audio(x->x_qt, NULL, x->x_qt_audiochans, readamount);) + break; + } + x->x_chunk_used[!x->x_chunk_current] = 1; + } + // if it is used, something went wrong with sync + else{ + //post("%s: dropping audio chunk %d.",x->x_name->s_name, x->x_frame_thread); + } + + + if (err) post("%s: error decoding audio",x->x_name->s_name, x->x_frame_thread); + + // ensure audio pointer points to next frame's data + //DEBUG_MSG(quicktime_set_audio_position(x->x_qt, sample + readamount, 0);) + +} + + + + +static void pdp_qt_bangvideo(t_pdp_qt *x) +{ + unsigned int w, h, nbpixels, packet_size, i,j; + unsigned int *source, *dest; + unsigned int uoffset, voffset; + short int* data; + t_pdp* header; + + // check if we want greyscale output or not + //int grey = (x->x_qt_cmodel == BC_RGB888); + + static short int gain[4] = {0x7fff, 0x7fff, 0x7fff, 0x7fff}; + + if ((!x->x_initialized) || (!x->x_video_tracks)){ + //post("pdp_qt: no qt file opened"); + return; + } + + w = x->x_video_width; + h = x->x_video_height; + nbpixels = x->x_video_width * x->x_video_height; + + // create a new packet + pdp_qt_create_pdp_packet(x); + + header = pdp_packet_header(x->x_packet0); + + if (!header) { + post("%s: ERROR: no packet available", x->x_name->s_name); + return; + } + + data = (short int *) pdp_packet_data(x->x_packet0); + + + DEBUG_MSG(lqt_decode_video(x->x_qt, x->x_qt_rows, 0);) + + + switch(x->x_qt_cmodel){ + case BC_YUV420P: + pdp_llconv(x->x_qt_frame, RIF_YVU__P411_U8, data, RIF_YVU__P411_S16, x->x_video_width, x->x_video_height); + break; + + case BC_YUV422: + pdp_llconv(x->x_qt_frame, RIF_YUYV_P____U8, data, RIF_YVU__P411_S16, x->x_video_width, x->x_video_height); + break; + + case BC_RGB888: + pdp_llconv(x->x_qt_frame, RIF_RGB__P____U8, data, RIF_YVU__P411_S16, x->x_video_width, x->x_video_height); + break; + + default: + post("%s: error on decode: unkown colour model",x->x_name->s_name); + break; + } + + + +} + +static void pdp_qt_sendpacket(t_pdp_qt *x) +{ + + pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet0); + + //if (x->x_packet0 != -1){ + //pdp_packet_mark_unused(x->x_packet0); + //outlet_pdp(x->x_outlet0, x->x_packet0); + //x->x_packet0 = -1; + //} +} + + +static void pdp_qt_thread_bang(t_pdp_qt *x) +{ + // set audio position + if(x->x_video_tracks) quicktime_set_video_position(x->x_qt, x->x_frame_thread, 0); + + // bang video + pdp_qt_bangvideo(x); + + // if it's a tilde object, bang audio + if (x->x_istilde && x->x_audio_tracks){ + quicktime_set_audio_position(x->x_qt, x->x_frame_thread * x->x_chunk_size, 0); + pdp_qt_bangaudio(x); + } + +} + + +static void pdp_qt_bang(t_pdp_qt *x) +{ + int length, pos; + + t_pdp_procqueue *q = pdp_queue_get_queue(); + + /* return if not initialized */ + if (!x->x_initialized) return; + + //length = quicktime_video_length(x->x_qt,0); + //pos = quicktime_video_position(x->x_qt,0); + length = x->x_video_length; + pos = x->x_frame; + + + /* check bounds */ + if (x->x_loop){ + pos = x->x_frame % length; + if (pos < 0) pos += length; + } + else{ + if (pos < 0) pos = 0; + if (pos >= length) pos = length - 1; + } + + /* store next frame for access in thread */ + x->x_frame_thread = pos; + + + // if autoplay is on and we do not have audio synchro + // set clock to play next frame + if (x->x_autoplay && !x->x_syncaudio) clock_delay(x->x_clock, 1000.0L / (double)x->x_video_framerate); + + + // make sure prev decode is finished don't drop frames in this one + pdp_procqueue_finish(q, x->x_queue_id); + x->x_queue_id = -1; + + /* only decode new stuff if previous is done */ + if (-1 == x->x_queue_id){ + // send the current frame number to outlet + outlet_float(x->x_outlet1, (float)pos); + + //pdp_qt_setposition(x, pos); + + // start process method + if (x->x_process_in_thread) pdp_procqueue_add(q, x, pdp_qt_thread_bang, pdp_qt_sendpacket, &x->x_queue_id); + else { + pdp_qt_thread_bang(x); + pdp_qt_sendpacket(x); + } + } + // advance frame + x->x_frame = pos + 1; + + + // send the packet + //pdp_qt_sendpacket(x); +} + + + +//static void pdp_qt_getaudiochunk(t_pdp_qt *x, int channel) +//{ +// if (!x->x_audio_tracks) return; +// quicktime_decode_audio(x->x_qt, NULL, x->x_chunk[channel][x->x_chunk_current], x->x_chunk_size<<1, channel); +// +//} + +static void pdp_qt_loop(t_pdp_qt *x, t_floatarg loop) +{ + int loopi = (int)loop; + x->x_loop = !(loopi == 0); +} + +static void pdp_qt_autoplay(t_pdp_qt *x, t_floatarg play) +{ + int playi = (int)play; + x->x_autoplay = !(playi == 0); + + + // reset clock if autoplay is off + if (!x->x_autoplay) clock_unset(x->x_clock); + + +} + + + +static void pdp_qt_frame_cold(t_pdp_qt *x, t_floatarg frameindex) +{ + int frame = (int)frameindex; + //int length; + + + x->x_frame = frame; + + //if (!(x->x_initialized)) return; + + //length = quicktime_video_length(x->x_qt,0); + + //frame = (frame >= length) ? length-1 : frame; + //frame = (frame < 0) ? 0 : frame; + + //pdp_qt_setposition(x, frame); +} + +static void pdp_qt_frame(t_pdp_qt *x, t_floatarg frameindex) +{ + pdp_qt_frame_cold(x, frameindex); + pdp_qt_bang(x); +} + +static void pdp_qt_stop(t_pdp_qt *x) +{ + pdp_qt_autoplay(x, 0); +} + +static void pdp_qt_continue(t_pdp_qt *x) +{ + pdp_qt_autoplay(x, 1); + pdp_qt_bang(x); +} + + +static void pdp_qt_play(t_pdp_qt *x){ + pdp_qt_frame_cold(x, 0); + pdp_qt_continue(x); +} + + + + +static void pdp_qt_importaudio(t_pdp_qt *x, t_symbol *array, t_floatarg channel) +{ + t_pdp_procqueue *q = pdp_queue_get_queue(); + int c = (int)channel; + t_garray *g; + int vecsize; + int sample; + float *f; + int i; + + /* if there's no audio, there's nothing to export */ + if (!x->x_audio_tracks) return; + + /* check audio channel */ + if ((c < 0) || (c >= x->x_audio_channels)) return; + + /* check if array exists */ + if (!(g = (t_garray *)pd_findbyclass(array, garray_class))){ + pd_error(x, "%s: no such table", array->s_name); + return; + } + + post("%s: importing audio channel %d into array %s", x->x_name->s_name, c, array->s_name); + + + // make sure decode is finished + pdp_procqueue_finish(q, x->x_queue_id); + x->x_queue_id = -1; + + + /* resize array */ + garray_resize(g, x->x_audio_length); + + /* for sanity's sake let's clear the save-in-patch flag here */ + garray_setsaveit(g, 0); + garray_getfloatarray(g, &vecsize, &f); + + /* if the resize failed, garray_resize reported the error */ + if (vecsize != x->x_audio_length){ + pd_error(x, "array resize failed"); + return; + } + + /* save pointer in file */ + DEBUG_MSG(sample = quicktime_audio_position(x->x_qt, 0);) + DEBUG_MSG(quicktime_set_audio_position(x->x_qt, 0, 0);) + + /* transfer the audio file to the end of the array */ + DEBUG_MSG(quicktime_decode_audio(x->x_qt, NULL, f, vecsize, c);) + + /* restore pointer in file */ + DEBUG_MSG(quicktime_set_audio_position(x->x_qt, sample, 0);) + + +} + + + +static t_int *pdp_qt_perform(t_int *w) +{ + t_pdp_qt *x = (t_pdp_qt *)w[1]; + t_float *out0 = (t_float *)w[2]; + t_float *out1 = (t_float *)w[3]; + t_int n = (t_int)w[4]; + + t_int xfer_samples; + if (!x->x_initialized || !x->x_audio_tracks) goto zero; + + while(1){ + // check current chunk + if (!x->x_chunk_used[x->x_chunk_current]) goto zero; + + + // transfer from chunk to output + xfer_samples = min(n, x->x_chunk_size - x->x_chunk_pos); + + //x->x_audio_channels = 1; + + if (x->x_audio_channels == 1){ + memcpy(out0, x->x_chunk[0][x->x_chunk_current] + x->x_chunk_pos, sizeof(float)*xfer_samples); + memcpy(out1, x->x_chunk[0][x->x_chunk_current] + x->x_chunk_pos, sizeof(float)*xfer_samples); + } + else { + memcpy(out0, x->x_chunk[0][x->x_chunk_current] + x->x_chunk_pos, sizeof(float)*xfer_samples); + memcpy(out1, x->x_chunk[1][x->x_chunk_current] + x->x_chunk_pos, sizeof(float)*xfer_samples); + } + out0 += xfer_samples; + out1 += xfer_samples; + n -= xfer_samples; + x->x_chunk_pos += xfer_samples; + + + // check if chunk is finished, if so mark unused, swap buffers and set clock + if (x->x_chunk_size == x->x_chunk_pos){ + x->x_chunk_used[x->x_chunk_current] = 0; + x->x_chunk_pos = 0; + x->x_chunk_current ^= 1; + if (x->x_autoplay) clock_delay(x->x_clock, 0L); + } + + // if chunk is not finished, the output buffer is full + else{ + goto exit; + } + + } + + + zero: + // fill the rest of the output with zeros + memset(out0, 0, sizeof(float)*n); + memset(out1, 0, sizeof(float)*n); + + exit: + return(w+5); +} + +static void pdp_qt_dsp(t_pdp_qt *x, t_signal **sp) +{ + dsp_add(pdp_qt_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); + +} + +static void pdp_qt_process_in_thread(t_pdp_qt *x, t_float f) +{ + + int t = (f != 0.0f); + + x->x_process_in_thread = t; + + post("pdp_qt: thread processing switched %d", t ? "on" : "off"); + +} + +static void pdp_qt_tick(t_pdp_qt *x) +{ + + // bang audio/video + pdp_qt_bang(x); +} + +static void pdp_qt_free(t_pdp_qt *x) +{ + clock_unset(x->x_clock); + pdp_qt_close(x); + clock_free(x->x_clock); + //free (x->x_state_data); + +} + + + +t_class *pdp_qt_class; +t_class *pdp_qt_tilde_class; + + +void pdp_qt_init_common(t_pdp_qt *x) +{ + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("frame_cold")); + + /* add common outlets */ + x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + x->x_outlet1 = outlet_new(&x->x_obj, &s_float); + x->x_outlet2 = outlet_new(&x->x_obj, &s_float); + + /* init */ + x->x_gain = 1.0f; + x->x_process_in_thread = 0; + x->x_packet0 = -1; + x->x_queue_id = -1; + x->x_initialized = 0; + x->x_audio_tracks = 0; + x->x_video_tracks = 0; + x->x_loop = 0; + x->x_autoplay = 0; + x->x_chunk[0][0] = 0; + x->x_chunk[0][1] = 0; + x->x_chunk[1][0] = 0; + x->x_chunk[1][1] = 0; + + /* initialize clock object */ + x->x_clock = clock_new(x, (t_method)pdp_qt_tick); + + + + +} + +void *pdp_qt_new(void) +{ + t_pdp_qt *x = (t_pdp_qt *)pd_new(pdp_qt_class); + x->x_name = gensym("pdp_qt"); + x->x_istilde = 0; + pdp_qt_init_common(x); + return (void *)x; +} + +void *pdp_qt_tilde_new(void) +{ + t_pdp_qt *x = (t_pdp_qt *)pd_new(pdp_qt_tilde_class); + x->x_name = gensym("pdp_qt"); + x->x_istilde = 1; + + pdp_qt_init_common(x); + + /* add outlets to the right so pdp_qt~ can replace pdp_qt without breaking a patch */ + x->x_outleft = outlet_new(&x->x_obj, &s_signal); + x->x_outright = outlet_new(&x->x_obj, &s_signal); + + return (void *)x; +} + + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_qt_setup_common(t_class *class) +{ + class_addmethod(class, (t_method)pdp_qt_bang, gensym("bang"), A_NULL); + class_addmethod(class, (t_method)pdp_qt_close, gensym("close"), A_NULL); + class_addmethod(class, (t_method)pdp_qt_open, gensym("open"), A_SYMBOL, A_NULL); + class_addmethod(class, (t_method)pdp_qt_autoplay, gensym("autoplay"), A_DEFFLOAT, A_NULL); + class_addmethod(class, (t_method)pdp_qt_stop, gensym("stop"), A_NULL); + class_addmethod(class, (t_method)pdp_qt_play, gensym("play"), A_NULL); + class_addmethod(class, (t_method)pdp_qt_continue, gensym("cont"), A_NULL); + class_addmethod(class, (t_method)pdp_qt_loop, gensym("loop"), A_DEFFLOAT, A_NULL); + class_addfloat (class, (t_method)pdp_qt_frame); + class_addmethod(class, (t_method)pdp_qt_frame_cold, gensym("frame_cold"), A_FLOAT, A_NULL); + class_addmethod(class, (t_method)pdp_qt_process_in_thread, gensym("thread"), A_FLOAT, A_NULL); + class_addmethod(class, (t_method)pdp_qt_importaudio, gensym("importaudio"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(class, (t_method)pdp_qt_importaudio, gensym("dump"), A_SYMBOL, A_DEFFLOAT, A_NULL); +} + +void pdp_qt_setup(void) +{ + + /* plain class */ + pdp_qt_class = class_new(gensym("pdp_qt"), (t_newmethod)pdp_qt_new, + (t_method)pdp_qt_free, sizeof(t_pdp_qt), 0, A_NULL); + pdp_qt_setup_common(pdp_qt_class); + + + /* tilde class */ + pdp_qt_tilde_class = class_new(gensym("pdp_qt~"), (t_newmethod)pdp_qt_tilde_new, + (t_method)pdp_qt_free, sizeof(t_pdp_qt), 0, A_NULL); + pdp_qt_setup_common(pdp_qt_tilde_class); + + class_addmethod(pdp_qt_tilde_class, (t_method)pdp_qt_dsp, gensym("dsp"), 0); +} + +#ifdef __cplusplus +} +#endif + + diff --git a/modules/image_io/pdp_sdl.c b/modules/image_io/pdp_sdl.c new file mode 100644 index 0000000..a46264b --- /dev/null +++ b/modules/image_io/pdp_sdl.c @@ -0,0 +1,337 @@ +/* + * Pure Data Packet module. + * Copyright (c) 2003 by martin pi <pi@attacksyour.net> + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +/* + +pdp sdl output + +DONE: + +TODO: + * close window (event) + * fullscreen chose resolution + * event handling in different object (and look at mplayer for that!) + +*/ + + +#include <stdio.h> +#include <SDL/SDL.h> +#include "pdp.h" +#include "pdp_llconv.h" + + + + +/* initial image dimensions */ + +#define WINWIDTH 640 +#define WINHEIGHT 480 +#define OVERLAYWIDTH 320 +#define OVERLAYHEIGHT 240 + + + +typedef struct pdp_sdl_struct { + t_object x_obj; + + SDL_Surface *x_surface; + SDL_Overlay *x_overlay; + int x_surface_flags; + + int x_surface_width; + int x_surface_height; + + unsigned int x_overlay_width; + unsigned int x_overlay_height; + + + t_outlet *x_outlet; + + +} t_pdp_sdl; + +static t_pdp_sdl *sdl_singleton; // only one instance allowed + +static void destroy_overlay(t_pdp_sdl *x) { + if (x->x_overlay){ + SDL_FreeYUVOverlay(x->x_overlay); + x->x_overlay = 0; + } +} + +static void create_overlay(t_pdp_sdl *x, int width, int height) { + if (x->x_surface){ + if (x->x_overlay = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, x->x_surface)){ + x->x_overlay_width = width; + x->x_overlay_height = height; + return; + } + } + pdp_post("SDL: can't create overlay."); +} + +static void check_overlay(t_pdp_sdl *x, unsigned int width, unsigned int height){ + if (!x->x_overlay + || (x->x_overlay_width != width) + || (x->x_overlay_height != height)){ + destroy_overlay(x); + create_overlay(x, width, height); + } +} + + +static void create_surface(t_pdp_sdl *x, int width, int height, int flags) +{ + flags |= SDL_HWSURFACE|SDL_ANYFORMAT|SDL_RESIZABLE; // add default flags +// flags |= SDL_HWSURFACE|SDL_ANYFORMAT; // add default flags +// flags |= SDL_SWSURFACE|SDL_ANYFORMAT; // add default flags + + /* flags: + SDL_HWSURFACE use hardware surface + SDL_ANYFORMAT return current surface, even if it doesn't match + SDL_OPENGL|SDL_DOUBLEBUF double buffer and opengl + SDL_RLEACCEL rle accelleration for blitting + SDL_FULLSCREEN fullscreen window + */ + + //pdp_post("create_surface %d %d %d", width, height, flags); + + /* check args */ + if (width < 1) width = 1; + if (height < 1) height = 1; + + /* free old stuff */ + if (x->x_overlay) destroy_overlay(x); + /* form manpage: + The framebuffer surface, or NULL if it fails. The surface returned + is freed by SDL_Quit() and should nt be freed by the caller. */ + if (x->x_surface) { /*SDL_FreeSurface(surface);*/ } + + + /* create new surface */ + if (!(x->x_surface = SDL_SetVideoMode(width, height, 16, flags))){ + pdp_post("SDL: Couldn't create a surface: %s", SDL_GetError()); + return; + } + + /* setup surface */ + SDL_WM_SetCaption("pdp", "pdp"); + SDL_ShowCursor(0); + /* set event mask to something conservative + and add a word to ask for some types of events */ + x->x_surface_width = width; + x->x_surface_height = height; + x->x_surface_flags = flags; + +} + +static void poll_events(t_pdp_sdl *x){ + + SDL_Event event; + static t_symbol *keydown=0, *keyup, *quit, *motion; + t_atom atom; + + /* cache symbols */ + if (!keydown){ + keydown = gensym("keypress"); + keyup = gensym("keyrelease"); + quit = gensym("quit"); + } + + if (!x->x_surface) return; + + /* poll events */ + while(SDL_PollEvent(&event)){ + switch(event.type){ + + case SDL_KEYDOWN: + SETFLOAT(&atom, (float)event.key.keysym.scancode); + outlet_anything(x->x_outlet, keydown, 1, &atom); + break; + + case SDL_KEYUP: + SETFLOAT(&atom, (float)event.key.keysym.scancode); + outlet_anything(x->x_outlet, keyup, 1, &atom); + break; + + case SDL_QUIT: + outlet_symbol(x->x_outlet, quit); + break; + + case SDL_VIDEORESIZE: + create_surface(x, event.resize.w, event.resize.h, x->x_surface_flags); + break; + } + } +} + + +static void fullscreen(t_pdp_sdl *x, t_floatarg f) +{ + post("fullscreen not implemented"); +} + + +static void resize(t_pdp_sdl *x, t_floatarg fw, t_floatarg fh) +{ + create_surface(x, (int)fw, (int)fh, 0); +} + + + +static void input_0(t_pdp_sdl *x, t_symbol *s, t_floatarg f) { + + int input_packet = (int)f; + if (s == gensym("register_ro")){ + int p = pdp_packet_convert_ro(input_packet, pdp_gensym("bitmap/yv12/*")); + + /* poll anyway. */ + //poll_events(x); + + /* check packet */ + if (-1 == p){ + post("SDL: can't convert image to bitmap/yv12/*"); + return; + } + else { + t_bitmap *bitmap = pdp_packet_subheader(p); + unsigned char *data = pdp_packet_data(p); + int planesize = bitmap->width * bitmap->height; + check_overlay(x, bitmap->width, bitmap->height); + if (x->x_overlay){ + SDL_Rect rect = {0, 0, x->x_surface_width, x->x_surface_height}; + + /* copy */ + SDL_LockYUVOverlay(x->x_overlay); + memcpy(x->x_overlay->pixels[0], data, planesize); data += planesize; + memcpy(x->x_overlay->pixels[1], data, planesize >> 2); data += (planesize >> 2); + memcpy(x->x_overlay->pixels[2], data, planesize >> 2); + SDL_UnlockYUVOverlay(x->x_overlay); + + /* display */ + if (SDL_DisplayYUVOverlay(x->x_overlay, &rect)){ + pdp_post("SDL: can't display overlay"); + return; + } + } + + else { + pdp_post("SDL: error creating overlay"); + } + + pdp_packet_mark_unused(p); + return; + } + } +} + + + + + +static void pdp_sdl_free(t_pdp_sdl *x) +{ + destroy_overlay(x); + sdl_singleton = 0; + SDL_Quit(); +} + + +t_class *pdp_sdl_class; + +void *pdp_sdl_new(t_floatarg width, t_floatarg height) { + + t_pdp_sdl *x; + int w = (int)width; + int h = (int)height; + + if (sdl_singleton) { + post("Only one sdl object allowed."); + return 0; + } + + if( SDL_Init(SDL_INIT_VIDEO) < 0 ) { + pdp_post("Could not initialize SDL: %s", SDL_GetError()); + return 0; + } + atexit(SDL_Quit); + + + x = (t_pdp_sdl *)pd_new(pdp_sdl_class); + sdl_singleton = x; + + + x->x_surface = NULL; + x->x_overlay = NULL; + + x->x_outlet = outlet_new(&x->x_obj, &s_anything); + + + /* try to create a surface */ + create_surface(x, w ? w : WINWIDTH, h ? h : WINHEIGHT, 0); + if (!x->x_surface){ + pdp_post("Can't create surface"); + goto error_cleanup; + } + + /* try to create overlay */ + check_overlay(x, 320, 240); + if (!x->x_overlay){ + pdp_post("Can't create overlay"); + goto error_cleanup; + } + + return (void *)x; + + error_cleanup: + pdp_sdl_free(x); + return (void *)0; +} + + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_sdl_setup(void) +{ + + sdl_singleton = 0; + + pdp_sdl_class = class_new(gensym("pdp_sdl"), (t_newmethod)pdp_sdl_new, + (t_method)pdp_sdl_free, sizeof(t_pdp_sdl), 0, A_NULL); + + + class_addmethod(pdp_sdl_class, (t_method)resize, gensym("size"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_sdl_class, (t_method)poll_events, gensym("poll"), A_NULL); + class_addmethod(pdp_sdl_class, (t_method)fullscreen, gensym("fullscreen"), A_FLOAT, A_NULL); + class_addmethod(pdp_sdl_class, (t_method)input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + +} + +#ifdef __cplusplus +} +#endif + diff --git a/modules/image_io/pdp_v4l.c b/modules/image_io/pdp_v4l.c new file mode 100644 index 0000000..85c34f1 --- /dev/null +++ b/modules/image_io/pdp_v4l.c @@ -0,0 +1,835 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +#include "pdp_config.h" +#include "pdp.h" +#include "pdp_llconv.h" +#include "pdp_imageproc.h" +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/time.h> +#include <linux/types.h> +#include <linux/videodev.h> +#include <sys/mman.h> +#include <sched.h> +#include <pthread.h> + +// dont open any more after a set number +// of failed attempts +// this is to prevent locks on auto-open +// is reset when manually opened or closed +#define PDP_XV_RETRIES 10 + +//include it anyway +//#ifdef HAVE_PWCV4L +#include "pwc-ioctl.h" +//#endif + + +#define DEVICENO 0 +#define NBUF 2 +#define COMPOSITEIN 1 + + + + +typedef struct pdp_v4l_struct +{ + t_object x_obj; + t_float x_f; + + t_outlet *x_outlet0; + + int x_format; // 0 means autodetect + + bool x_initialized; + bool x_auto_open; + + unsigned int x_width; + unsigned int x_height; + int x_channel; + unsigned int x_norm; + int x_freq; + + unsigned int x_framerate; + + struct video_tuner x_vtuner; + struct video_picture x_vpicture; + struct video_buffer x_vbuffer; + struct video_capability x_vcap; + struct video_channel x_vchannel; + struct video_audio x_vaudio; + struct video_mbuf x_vmbuf; + struct video_mmap x_vmmap[NBUF]; + struct video_window x_vwin; + int x_tvfd; + int x_frame; + unsigned char *x_videobuf; + int x_skipnext; + int x_mytopmargin, x_mybottommargin; + int x_myleftmargin, x_myrightmargin; + + t_symbol *x_device; + t_symbol *x_image_type; + //int x_pdp_image_type; + int x_v4l_palette; + + pthread_t x_thread_id; + int x_continue_thread; + int x_frame_ready; + int x_only_new_frames; + int x_last_frame; + + + int x_open_retry; + + u32 x_minwidth; + u32 x_maxwidth; + u32 x_minheight; + u32 x_maxheight; + + +} t_pdp_v4l; + + + + + +static void pdp_v4l_audio(t_pdp_v4l *x, t_floatarg f) +{ + int i = 0; + if (x->x_initialized){ + fprintf(stderr," audios : %d\n",x->x_vcap.audios); + x->x_vaudio.audio = 0; + ioctl(x->x_tvfd,VIDIOCGAUDIO, &x->x_vaudio); + + fprintf(stderr," %d (%s): ",i,x->x_vaudio.name); + if (x->x_vaudio.flags & VIDEO_AUDIO_MUTABLE) + fprintf(stderr,"muted=%s ", + (x->x_vaudio.flags & VIDEO_AUDIO_MUTE) ? "yes":"no"); + if (x->x_vaudio.flags & VIDEO_AUDIO_VOLUME) + fprintf(stderr,"volume=%d ",x->x_vaudio.volume); + if (x->x_vaudio.flags & VIDEO_AUDIO_BASS) + fprintf(stderr,"bass=%d ",x->x_vaudio.bass); + if (x->x_vaudio.flags & VIDEO_AUDIO_TREBLE) + fprintf(stderr,"treble=%d ",x->x_vaudio.treble); + fprintf(stderr,"\n"); + + } +} + + +static void pdp_v4l_close(t_pdp_v4l *x) +{ + /* close the v4l device and dealloc buffer */ + + void *dummy; + + /* terminate thread if there is one */ + if(x->x_continue_thread){ + x->x_continue_thread = 0; + pthread_join (x->x_thread_id, &dummy); + } + + + if (x->x_tvfd >= 0) + { + close(x->x_tvfd); + x->x_tvfd = -1; + } + + if (x->x_initialized){ + munmap(x->x_videobuf, x->x_vmbuf.size); + x->x_initialized = false; + } + +} + +static void pdp_v4l_close_manual(t_pdp_v4l *x) +{ + x->x_open_retry = PDP_XV_RETRIES; + pdp_v4l_close(x); + +} + +static void pdp_v4l_close_error(t_pdp_v4l *x) +{ + pdp_v4l_close(x); + if(x->x_open_retry) x->x_open_retry--; +} + + +static void pdp_v4l_pwc_init(t_pdp_v4l *x) +{ + struct pwc_probe probe; + int isPhilips = 0; + +#ifdef HAVE_PWCV4L + /* skip test */ + isPhilips = 1; +#else + /* test for pwc */ + if (ioctl(x->x_tvfd, VIDIOCPWCPROBE, &probe) == 0) + if (!strcmp(x->x_vcap.name, probe.name)) + isPhilips = 1; + +#endif + + /* don't do pwc specific stuff */ + if (!isPhilips) return; + + post("pdp_v4l: detected pwc"); + + if(ioctl(x->x_tvfd, VIDIOCPWCRUSER)){ + perror("pdp_v4l: pwc: VIDIOCPWCRUSER"); + goto closit; + } + + if (ioctl(x->x_tvfd, VIDIOCGWIN, &x->x_vwin)){ + perror("pdp_v4l: pwc: VIDIOCGWIN"); + goto closit; + } + + + + if (x->x_vwin.flags & PWC_FPS_MASK){ + //post("pdp_v4l: pwc: camera framerate: %d", (x->x_vwin.flags & PWC_FPS_MASK) >> PWC_FPS_SHIFT); + //post("pdp_v4l: pwc: setting camera framerate to %d", x->x_framerate); + x->x_vwin.flags &= PWC_FPS_MASK; + x->x_vwin.flags |= (x->x_framerate << PWC_FPS_SHIFT); + if (ioctl(x->x_tvfd, VIDIOCSWIN, &x->x_vwin)){ + perror("pdp_v4l: pwc: VIDIOCSWIN"); + goto closit; + } + if (ioctl(x->x_tvfd, VIDIOCGWIN, &x->x_vwin)){ + perror("pdp_v4l: pwc: VIDIOCGWIN"); + goto closit; + } + post("pdp_v4l: camera framerate set to %d fps", (x->x_vwin.flags & PWC_FPS_MASK) >> PWC_FPS_SHIFT); + + } + + + return; + + + + closit: + pdp_v4l_close_error(x); + return; + +} + +static void pdp_v4l_sync_frame(t_pdp_v4l* x){ + /* grab frame */ + if (ioctl(x->x_tvfd, VIDIOCSYNC, &x->x_vmmap[x->x_frame].frame) < 0){ + perror("pdp_v4l: VIDIOCSYNC"); + pdp_v4l_close(x); + return; + } +} + +static void pdp_v4l_capture_frame(t_pdp_v4l* x){ + if (ioctl(x->x_tvfd, VIDIOCMCAPTURE, &x->x_vmmap[x->x_frame]) < 0){ + if (errno == EAGAIN) + post("pdp_v4l: can't sync (no video source?)\n"); + else + perror("pdp_v4l: VIDIOCMCAPTURE"); + if (ioctl(x->x_tvfd, VIDIOCMCAPTURE, &x->x_vmmap[x->x_frame]) < 0) + perror("pdp_v4l: VIDIOCMCAPTURE2"); + + post("pdp_v4l: frame %d %d, format %d, width %d, height %d", + x->x_frame, x->x_vmmap[x->x_frame].frame, x->x_vmmap[x->x_frame].format, + x->x_vmmap[x->x_frame].width, x->x_vmmap[x->x_frame].height); + + pdp_v4l_close(x); + return; + } +} + + +static void *pdp_v4l_thread(void *voidx) +{ + t_pdp_v4l *x = ((t_pdp_v4l *)voidx); + + + /* flip buffers */ + x->x_frame ^= 0x1; + + /* capture with a double buffering scheme */ + while (x->x_continue_thread){ + + /* schedule capture command for next frame */ + pdp_v4l_capture_frame(x); + + /* wait until previous capture is ready */ + x->x_frame ^= 0x1; + pdp_v4l_sync_frame(x); + + /* setup pointers for main thread */ + x->x_frame_ready = 1; + x->x_last_frame = x->x_frame; + + } + + return 0; +} + +static void pdp_v4l_setlegaldim(t_pdp_v4l *x, int xx, int yy); + +static void pdp_v4l_open(t_pdp_v4l *x, t_symbol *name) +{ + /* open a v4l device and allocate a buffer */ + + unsigned int size; + int i; + + unsigned int width, height; + + + /* if already opened -> close */ + if (x->x_initialized) pdp_v4l_close(x); + + + /* exit if retried too much */ + if (!x->x_open_retry){ + post("pdp_v4l: retry count reached zero for %s", name->s_name); + post("pdp_v4l: try to open manually"); + return; + } + + post("pdp_v4l: opening %s", name->s_name); + + x->x_device = name; + + if ((x->x_tvfd = open(name->s_name, O_RDWR)) < 0) + { + post("pdp_v4l: error:"); + perror(name->s_name); + goto closit; + } + + + if (ioctl(x->x_tvfd, VIDIOCGCAP, &x->x_vcap) < 0) + { + perror("get capabilities"); + goto closit; + } + + post("pdp_v4l: cap: name %s type %d channels %d maxw %d maxh %d minw %d minh %d", + x->x_vcap.name, x->x_vcap.type, x->x_vcap.channels, x->x_vcap.maxwidth, x->x_vcap.maxheight, + x->x_vcap.minwidth, x->x_vcap.minheight); + + x->x_minwidth = pdp_imageproc_legalwidth(x->x_vcap.minwidth); + x->x_maxwidth = pdp_imageproc_legalwidth_round_down(x->x_vcap.maxwidth); + x->x_minheight = pdp_imageproc_legalheight(x->x_vcap.minheight); + x->x_maxheight = pdp_imageproc_legalheight_round_down(x->x_vcap.maxheight); + + + if (ioctl(x->x_tvfd, VIDIOCGPICT, &x->x_vpicture) < 0) + { + perror("VIDIOCGCAP"); + goto closit; + } + + post("pdp_v4l: picture: brightness %d depth %d palette %d", + x->x_vpicture.brightness, x->x_vpicture.depth, x->x_vpicture.palette); + + /* get channel info */ + for (i = 0; i < x->x_vcap.channels; i++) + { + x->x_vchannel.channel = i; + if (ioctl(x->x_tvfd, VIDIOCGCHAN, &x->x_vchannel) < 0) + { + perror("VDIOCGCHAN"); + goto closit; + } + post("pdp_v4l: channel %d name %s type %d flags %d", + x->x_vchannel.channel, x->x_vchannel.name, + x->x_vchannel.type, x->x_vchannel.flags); + } + + /* switch to the desired channel */ + if (x->x_channel < 0) x->x_channel = 0; + if (x->x_channel >= x->x_vcap.channels) x->x_channel = x->x_vcap.channels - 1; + + x->x_vchannel.channel = x->x_channel; + if (ioctl(x->x_tvfd, VIDIOCGCHAN, &x->x_vchannel) < 0) + { + perror("pdp_v4l: warning: VDIOCGCHAN"); + post("pdp_v4l: cant change to channel %d",x->x_channel); + + // ignore error + // goto closit; + } + else{ + post("pdp_v4l: switched to channel %d", x->x_channel); + } + + + /* set norm */ + x->x_vchannel.norm = x->x_norm; + if (ioctl(x->x_tvfd, VIDIOCSCHAN, &x->x_vchannel) < 0) + { + perror("pdp_v4l: warning: VDIOCSCHAN"); + post("pdp_v4l: cant change to norm %d",x->x_norm); + + // ignore error + // goto closit; + } + else { + post("pdp_v4l: set norm to %u", x->x_norm); + } + + if (x->x_freq > 0){ + if (ioctl(x->x_tvfd, VIDIOCSFREQ, &x->x_freq) < 0) + perror ("couldn't set frequency :"); + } + + + + + /* get mmap numbers */ + if (ioctl(x->x_tvfd, VIDIOCGMBUF, &x->x_vmbuf) < 0) + { + perror("pdp_v4l: VIDIOCGMBUF"); + goto closit; + } + post("pdp_v4l: buffer size %d, frames %d, offset %d %d", x->x_vmbuf.size, + x->x_vmbuf.frames, x->x_vmbuf.offsets[0], x->x_vmbuf.offsets[1]); + if (!(x->x_videobuf = (unsigned char *) + mmap(0, x->x_vmbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, x->x_tvfd, 0))) + { + perror("pdp_v4l: mmap"); + goto closit; + } + + pdp_v4l_setlegaldim(x, x->x_width, x->x_height); + width = x->x_width; + height = x->x_height; + + for (i = 0; i < NBUF; i++) + { + //x->x_vmmap[i].format = VIDEO_PALETTE_YUV420P; + //x->x_vmmap[i].format = VIDEO_PALETTE_UYVY; + x->x_vmmap[i].width = width; + x->x_vmmap[i].height = height; + x->x_vmmap[i].frame = i; + } + + +/* fallthrough macro for case statement */ +#define TRYPALETTE(palette) \ + x->x_v4l_palette = palette; \ + for (i = 0; i < NBUF; i++) x->x_vmmap[i].format = x->x_v4l_palette; \ + if (ioctl(x->x_tvfd, VIDIOCMCAPTURE, &x->x_vmmap[x->x_frame]) < 0) \ + { \ + if (errno == EAGAIN) \ + post("pdp_v4l: can't sync (no video source?)"); \ + if (x->x_format) break; /* only break if not autodetecting */ \ + } \ + else{ \ + post("pdp_v4l: using " #palette); \ + goto capture_ok; \ + } + + switch(x->x_format){ + default: + case 0: + case 1: TRYPALETTE(VIDEO_PALETTE_YUV420P); + case 2: TRYPALETTE(VIDEO_PALETTE_YUV422); + case 3: TRYPALETTE(VIDEO_PALETTE_RGB24); + case 4: TRYPALETTE(VIDEO_PALETTE_RGB32); + } + + // none of the formats are supported + perror("pdp_v4l: VIDIOCMCAPTURE: format not supported"); + goto closit; + + + capture_ok: + + post("pdp_v4l: frame %d %d, format %d, width %d, height %d", + x->x_frame, x->x_vmmap[x->x_frame].frame, x->x_vmmap[x->x_frame].format, + x->x_vmmap[x->x_frame].width, x->x_vmmap[x->x_frame].height); + + x->x_width = width; + x->x_height = height; + + post("pdp_v4l: Opened video connection (%dx%d)",x->x_width,x->x_height); + + + /* do some pwc specific inits */ + pdp_v4l_pwc_init(x); + + + x->x_initialized = true; + + /* create thread */ + x->x_continue_thread = 1; + x->x_frame_ready = 0; + pthread_create(&x->x_thread_id, 0, pdp_v4l_thread, x); + + return; + closit: + pdp_v4l_close_error(x); + +} + +static void pdp_v4l_open_manual(t_pdp_v4l *x, t_symbol *name) +{ + x->x_open_retry = PDP_XV_RETRIES; + pdp_v4l_open(x, name); +} + + +static void pdp_v4l_channel(t_pdp_v4l *x, t_float f) +{ + int channel = (float)f; + + if (x->x_initialized){ + pdp_v4l_close(x); + x->x_channel = channel; + pdp_v4l_open(x, x->x_device); + } + else + x->x_channel = channel; +} + +static void pdp_v4l_norm(t_pdp_v4l *x, t_symbol *s) +{ + unsigned int norm; + + if (gensym("PAL") == s) norm = VIDEO_MODE_PAL; + else if (gensym("NTSC") == s) norm = VIDEO_MODE_NTSC; + else if (gensym("SECAM") == s) norm = VIDEO_MODE_SECAM; + else norm = VIDEO_MODE_AUTO; + + + + if (x->x_initialized){ + pdp_v4l_close(x); + x->x_norm = norm; + pdp_v4l_open(x, x->x_device); + } + else + x->x_norm = norm; +} + +static void pdp_v4l_freq(t_pdp_v4l *x, t_float f) +{ + int freq = (int)f; + + x->x_freq = freq; + if (x->x_freq > 0){ + if (ioctl(x->x_tvfd, VIDIOCSFREQ, &x->x_freq) < 0) + perror ("couldn't set frequency :"); + //else {post("pdp_v4l: tuner frequency: %f MHz", f / 16.0f);} + } + +} + +static void pdp_v4l_freqMHz(t_pdp_v4l *x, t_float f) +{ + pdp_v4l_freq(x, f*16.0f); +} + + +static void pdp_v4l_bang(t_pdp_v4l *x) +{ + + /* if initialized, grab a frame and output it */ + + unsigned int w,h,nbpixels,packet_size,plane1,plane2; + unsigned char *newimage; + int object,length,pos,i,encoding; + t_pdp* header; + t_image* image; + short int * data; + + + static short int gain[4] = {0x7fff, 0x7fff, 0x7fff, 0x7fff}; + + if (!(x->x_initialized)){ + post("pdp_v4l: no device opened"); + + if (x->x_auto_open){ + post("pdp_v4l: attempting auto open"); + pdp_v4l_open(x, x->x_device); + if (!(x->x_initialized)){ + post("pdp_v4l: auto open failed"); + return; + } + } + + else return; + } + + + /* do nothing if there is no frame ready */ + if((!x->x_frame_ready) && (x->x_only_new_frames)) return; + x->x_frame_ready = 0; + + /* get the address of the "other" frame */ + newimage = x->x_videobuf + x->x_vmbuf.offsets[x->x_last_frame]; + + /* create new packet */ + w = x->x_width; + h = x->x_height; + + //nbpixels = w * h; + +/* + switch(x->x_pdp_image_type){ + case PDP_IMAGE_GREY: + packet_size = nbpixels << 1; + break; + case PDP_IMAGE_YV12: + packet_size = (nbpixels + (nbpixels >> 1)) << 1; + break; + default: + packet_size = 0; + post("pdp_v4l: internal error"); + } +*/ + + //packet_size = (nbpixels + (nbpixels >> 1)) << 1; + + + //plane1 = nbpixels; + //plane2 = nbpixels + (nbpixels>>2); + + object = pdp_packet_new_image(PDP_IMAGE_YV12, w, h); + header = pdp_packet_header(object); + image = pdp_packet_image_info(object); + + if (!header){ + post("pdp_v4l: ERROR: can't allocate packet"); + return; + } + + data = (short int *) pdp_packet_data(object); + newimage = x->x_videobuf + x->x_vmbuf.offsets[x->x_frame ^ 0x1]; + + + /* convert data to pdp packet */ + + switch(x->x_v4l_palette){ + case VIDEO_PALETTE_YUV420P: + pdp_llconv(newimage, RIF_YUV__P411_U8, data, RIF_YVU__P411_S16, w, h); + break; + + /* long live standards. v4l's rgb is in fact ogl's bgr */ + case VIDEO_PALETTE_RGB24: + pdp_llconv(newimage, RIF_BGR__P____U8, data, RIF_YVU__P411_S16, w, h); + break; + + case VIDEO_PALETTE_RGB32: + pdp_llconv(newimage, RIF_BGRA_P____U8, data, RIF_YVU__P411_S16, w, h); + break; + + case VIDEO_PALETTE_YUV422: + pdp_llconv(newimage, RIF_YUYV_P____U8, data, RIF_YVU__P411_S16, w, h); + break; + + + default: + post("pdp_v4l: unsupported palette"); + break; + } + +/* + if (PDP_IMAGE_YV12 == x->x_pdp_image_type){ + pixel_unpack_u8s16_y(&newimage[0], data, nbpixels>>3, x->x_state_data->gain); + pixel_unpack_u8s16_uv(&newimage[plane1], &data[plane2], nbpixels>>5, x->x_state_data->gain); + pixel_unpack_u8s16_uv(&newimage[plane2], &data[plane1], nbpixels>>5, x->x_state_data->gain); + } +*/ + //x->x_v4l_palette = VIDEO_PALETTE_YUV420P; + //x->x_v4l_palette = VIDEO_PALETTE_RGB24; + +/* + + else if(PDP_IMAGE_GREY == x->x_pdp_image_type){ + pixel_unpack_u8s16_y(&newimage[0], data, nbpixels>>3, x->x_state_data->gain); + } +*/ + //post("pdp_v4l: mark unused %d", object); + + pdp_packet_pass_if_valid(x->x_outlet0, &object); + +} + + +static void pdp_v4l_setlegaldim(t_pdp_v4l *x, int xx, int yy) +{ + + unsigned int w,h; + + w = pdp_imageproc_legalwidth((int)xx); + h = pdp_imageproc_legalheight((int)yy); + + w = (w < x->x_maxwidth) ? w : x->x_maxwidth; + w = (w > x->x_minwidth) ? w : x->x_minwidth; + + h = (h < x->x_maxheight) ? h : x->x_maxheight; + h = (h > x->x_minheight) ? h : x->x_minheight; + + x->x_width = w; + x->x_height = h; +} + +static void pdp_v4l_dim(t_pdp_v4l *x, t_floatarg xx, t_floatarg yy) +{ + if (x->x_initialized){ + pdp_v4l_close(x); + pdp_v4l_setlegaldim(x, (int)xx, (int)yy); + pdp_v4l_open(x, x->x_device); + + } + else{ + pdp_v4l_setlegaldim(x, (int)xx, (int)yy); + } +} + +static void pdp_v4l_format(t_pdp_v4l *x, t_symbol *s) +{ + if (s == gensym("YUV420P")) x->x_format = 1; + else if (s == gensym("YUV422")) x->x_format = 2; + else if (s == gensym("RGB24")) x->x_format = 3; + else if (s == gensym("RGB32")) x->x_format = 4; + else if (s == gensym("auto")) x->x_format = 0; + else { + post("pdp_v4l: format %s unknown, using autodetect", s->s_name); + x->x_format = 0; + } + + if (x->x_initialized){ + pdp_v4l_close(x); + pdp_v4l_open(x, x->x_device); + } +} + + +static void pdp_v4l_free(t_pdp_v4l *x) +{ + pdp_v4l_close(x); +} + +t_class *pdp_v4l_class; + + + +void *pdp_v4l_new(t_symbol *vdef, t_symbol *format) +{ + t_pdp_v4l *x = (t_pdp_v4l *)pd_new(pdp_v4l_class); + + x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + + x->x_initialized = false; + + + x->x_tvfd = -1; + x->x_frame = 0; + x->x_last_frame = 0; + + x->x_framerate = 27; + + x->x_auto_open = true; + if (vdef != gensym("")){ + x->x_device = vdef; + } + else{ + x->x_device = gensym("/dev/video0"); + } + + if (format != gensym("")){ + pdp_v4l_format(x, format); + } + else { + x->x_format = 0; // default is autodetect + } + + x->x_continue_thread = 0; + x->x_only_new_frames = 1; + + x->x_width = 320; + x->x_height = 240; + +// pdp_v4l_type(x, gensym("yv12")); + + + x->x_open_retry = PDP_XV_RETRIES; + + x->x_channel = 0; + x->x_norm = 0; // PAL + x->x_freq = -1; //don't set freq by default + + x->x_minwidth = pdp_imageproc_legalwidth(0); + x->x_maxwidth = pdp_imageproc_legalwidth_round_down(0x7fffffff); + x->x_minheight = pdp_imageproc_legalheight(0); + x->x_maxheight = pdp_imageproc_legalheight_round_down(0x7fffffff); + + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_v4l_setup(void) +{ + + + pdp_v4l_class = class_new(gensym("pdp_v4l"), (t_newmethod)pdp_v4l_new, + (t_method)pdp_v4l_free, sizeof(t_pdp_v4l), 0, A_DEFSYMBOL, A_DEFSYMBOL, A_NULL); + + + class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_bang, gensym("bang"), A_NULL); + class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_audio, gensym("audio"), A_NULL); + class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_close_manual, gensym("close"), A_NULL); + class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_open_manual, gensym("open"), A_SYMBOL, A_NULL); + class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_channel, gensym("channel"), A_FLOAT, A_NULL); + class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_norm, gensym("norm"), A_SYMBOL, A_NULL); + class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_dim, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_freq, gensym("freq"), A_FLOAT, A_NULL); + class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_freqMHz, gensym("freqMHz"), A_FLOAT, A_NULL); + class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_format, gensym("captureformat"), A_SYMBOL, A_NULL); + + + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_io/pdp_xv.c b/modules/image_io/pdp_xv.c new file mode 100644 index 0000000..93383fd --- /dev/null +++ b/modules/image_io/pdp_xv.c @@ -0,0 +1,343 @@ +/* + * Pure Data Packet module. Xvideo image packet output + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +// pdp stuff +#include "pdp.h" +#include "pdp_base.h" + +// some x window glue code +#include "pdp_xwindow.h" +#include "pdp_xvideo.h" + + +#define PDP_XV_AUTOCREATE_RETRY 10 + + +typedef struct pdp_xv_struct +{ + t_object x_obj; + + t_pdp_xdisplay *x_xdpy; + t_pdp_xwindow *x_xwin; + t_pdp_xvideo *x_xvid; + + t_outlet *x_outlet; + + int x_packet0; + int x_queue_id; + t_symbol *x_display; + + //Display *x_dpy; + + int x_initialized; + int x_autocreate; + + +} t_pdp_xv; + + +static void pdp_xv_cursor(t_pdp_xv *x, t_floatarg f) +{ + if (x->x_xwin) pdp_xwindow_cursor(x->x_xwin, f); +} + +/* delete all submodules */ +static void _pdp_xv_cleanup(t_pdp_xv *x) +{ + if (x->x_xwin) pdp_xwindow_free(x->x_xwin); + if (x->x_xvid) pdp_xvideo_free(x->x_xvid); + if (x->x_xdpy) pdp_xdisplay_free(x->x_xdpy); + x->x_xwin = 0; + x->x_xvid = 0; + x->x_xdpy = 0; + x->x_initialized = 0; +} + +/* wait for thread to finish */ +static void _pdp_xv_waitforthread(t_pdp_xv *x) +{ + t_pdp_procqueue *q = pdp_queue_get_queue(); + pdp_procqueue_finish(q, x->x_queue_id); // wait for thread to finish + x->x_queue_id = -1; +} + +// this destroys the window and all the x connections +static void pdp_xv_destroy(t_pdp_xv* x) +{ + if (x->x_initialized){ + + _pdp_xv_waitforthread(x); // wait for thread + _pdp_xv_cleanup(x); // delete all objects + + pdp_packet_mark_unused(x->x_packet0); // delete packet + x->x_packet0 = -1; + x->x_initialized = 0; + + } +} + + +/* this creates a window (opens a dpy connection, creates xvideo and xwinow objects) */ +static void pdp_xv_create(t_pdp_xv* x) +{ + int i; + if(x->x_initialized) return; + + + /* open a display */ + if (!(x->x_xdpy = pdp_xdisplay_new(x->x_display->s_name))) goto exit; + + /* open an xv port on the display */ + x->x_xvid = pdp_xvideo_new(); + if (!pdp_xvideo_open_on_display(x->x_xvid, x->x_xdpy)) goto exit; + + /* create a window on the display */ + x->x_xwin = pdp_xwindow_new(); + if (!pdp_xwindow_create_on_display(x->x_xwin, x->x_xdpy)) goto exit; + + /* done */ + x->x_initialized = 1; + return; + + /* cleanup exits */ + exit: + post("pdp_xv: cant open display %s\n",x->x_display->s_name); + _pdp_xv_cleanup(x); + +} + +static int pdp_xv_try_autocreate(t_pdp_xv *x) +{ + + if (x->x_autocreate){ + post("pdp_xv: autocreate window"); + pdp_xv_create(x); + if (!(x->x_initialized)){ + x->x_autocreate--; + if (!x->x_autocreate){ + post ("pdp_xv: autocreate failed %d times: disabled", PDP_XV_AUTOCREATE_RETRY); + post ("pdp_xv: send [autocreate 1] message to re-enable"); + return 0; + } + } + else return 1; + + } + return 0; +} + +static void pdp_xv_bang(t_pdp_xv *x); + +static void pdp_xv_bang_thread(t_pdp_xv *x) +{ + pdp_xvideo_display_packet(x->x_xvid, x->x_xwin, x->x_packet0); +} + + +static void pdp_xv_bang_callback(t_pdp_xv *x) +{ + /* receive events + send to outputs */ + t_pdp_list *eventlist = pdp_xwindow_get_eventlist(x->x_xwin); + t_pdp_atom *a; + + for (a=eventlist->first; a; a=a->next){ + //pdp_list_print(a->w.w_list); + outlet_pdp_list(x->x_outlet, a->w.w_list); + } + + /* free list */ + pdp_tree_free(eventlist); + + /* release the packet if there is one */ + pdp_packet_mark_unused(x->x_packet0); + x->x_packet0 = -1; + +} + +/* manually poll for events */ +static void pdp_xv_poll(t_pdp_xv *x) +{ + if (x->x_initialized) + pdp_xv_bang_callback(x); +} + +static void pdp_xv_bang(t_pdp_xv *x) +{ + t_pdp_procqueue *q = pdp_queue_get_queue(); + + /* check if window is initialized */ + if (!(x->x_initialized)){ + if (!pdp_xv_try_autocreate(x)) return; + } + + /* check if we can proceed */ + if (-1 != x->x_queue_id) return; + if (-1 == x->x_packet0) return; + + /* if previous queued method returned + schedule a new one, else ignore */ + if (-1 == x->x_queue_id) { + pdp_procqueue_add(q, x, pdp_xv_bang_thread, pdp_xv_bang_callback, &x->x_queue_id); + } + +} + +static void pdp_xv_input_0(t_pdp_xv *x, t_symbol *s, t_floatarg f) +{ + + if (s == gensym("register_ro")) pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("bitmap/yv12/*")); + if (s == gensym("process")) pdp_xv_bang(x); + +} + + + +static void pdp_xv_autocreate(t_pdp_xv *x, t_floatarg f) +{ + if (f != 0.0f) x->x_autocreate = PDP_XV_AUTOCREATE_RETRY; + else x->x_autocreate = 0; +} + +static void pdp_xv_display(t_pdp_xv *x, t_symbol *s) +{ + _pdp_xv_waitforthread(x); + x->x_display = s; + + /* only create if already active */ + if (x->x_initialized){ + pdp_xv_destroy(x); + pdp_xv_create(x); + } +} + +static void pdp_xv_movecursor(t_pdp_xv *x, float cx, float cy) +{ + if (x->x_initialized){ + cx *= x->x_xwin->winwidth; + cy *= x->x_xwin->winheight; + pdp_xwindow_warppointer(x->x_xwin, cx, cy); + } +} + +static void pdp_xv_fullscreen(t_pdp_xv *x) +{ + if (x->x_initialized) + pdp_xwindow_fullscreen(x->x_xwin); +} + +static void pdp_xv_resize(t_pdp_xv* x, t_floatarg width, t_floatarg height) +{ + if (x->x_initialized) + pdp_xwindow_resize(x->x_xwin, width, height); +} + +static void pdp_xv_move(t_pdp_xv* x, t_floatarg width, t_floatarg height) +{ + if (x->x_initialized) + pdp_xwindow_move(x->x_xwin, width, height); +} + +static void pdp_xv_moveresize(t_pdp_xv* x, t_floatarg xoff, t_floatarg yoff, t_floatarg width, t_floatarg height) +{ + if (x->x_initialized) + pdp_xwindow_moveresize(x->x_xwin, xoff, yoff, width, height); +} + +static void pdp_xv_tile(t_pdp_xv* x, t_floatarg xtiles, t_floatarg ytiles, t_floatarg i, t_floatarg j) +{ + if (x->x_initialized) + pdp_xwindow_tile(x->x_xwin, xtiles, ytiles, i, j); +} + +static void pdp_xv_vga(t_pdp_xv *x) +{ + pdp_xv_resize(x, 640, 480); +} + +static void pdp_xv_free(t_pdp_xv *x) +{ + pdp_xv_destroy(x); +} + +t_class *pdp_xv_class; + + + +void *pdp_xv_new(void) +{ + t_pdp_xv *x = (t_pdp_xv *)pd_new(pdp_xv_class); + x->x_outlet = outlet_new(&x->x_obj, &s_anything); + x->x_xwin = 0; + x->x_xvid = 0; + x->x_xdpy = 0; + x->x_packet0 = -1; + x->x_queue_id = -1; + x->x_display = gensym(":0"); + x->x_xdpy = 0; + pdp_xv_autocreate(x,1); + + return (void *)x; +} + + + + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_xv_setup(void) +{ + pdp_xv_class = class_new(gensym("pdp_xv"), (t_newmethod)pdp_xv_new, + (t_method)pdp_xv_free, sizeof(t_pdp_xv), 0, A_NULL); + + + class_addmethod(pdp_xv_class, (t_method)pdp_xv_bang, gensym("bang"), A_NULL); + class_addmethod(pdp_xv_class, (t_method)pdp_xv_create, gensym("open"), A_NULL); + class_addmethod(pdp_xv_class, (t_method)pdp_xv_create, gensym("create"), A_NULL); + class_addmethod(pdp_xv_class, (t_method)pdp_xv_autocreate, gensym("autocreate"), A_FLOAT, A_NULL); + class_addmethod(pdp_xv_class, (t_method)pdp_xv_destroy, gensym("destroy"), A_NULL); + class_addmethod(pdp_xv_class, (t_method)pdp_xv_destroy, gensym("close"), A_NULL); + class_addmethod(pdp_xv_class, (t_method)pdp_xv_resize, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_xv_class, (t_method)pdp_xv_move, gensym("move"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_xv_class, (t_method)pdp_xv_move, gensym("pos"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_xv_class, (t_method)pdp_xv_resize, gensym("size"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_xv_class, (t_method)pdp_xv_display, gensym("display"), A_SYMBOL, A_NULL); + class_addmethod(pdp_xv_class, (t_method)pdp_xv_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_xv_class, (t_method)pdp_xv_cursor, gensym("cursor"), A_FLOAT, A_NULL); + class_addmethod(pdp_xv_class, (t_method)pdp_xv_movecursor, gensym("movecursor"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_xv_class, (t_method)pdp_xv_fullscreen, gensym("fullscreen"), A_NULL); + class_addmethod(pdp_xv_class, (t_method)pdp_xv_poll, gensym("poll"), A_NULL); + class_addmethod(pdp_xv_class, (t_method)pdp_xv_moveresize, gensym("posdim"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_xv_class, (t_method)pdp_xv_tile, gensym("tile"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL); + + /* some shortcuts for the lazy */ + class_addmethod(pdp_xv_class, (t_method)pdp_xv_vga, gensym("vga"), A_NULL); + +} + +#ifdef __cplusplus +} +#endif + + diff --git a/modules/image_special/Makefile b/modules/image_special/Makefile new file mode 100644 index 0000000..005832f --- /dev/null +++ b/modules/image_special/Makefile @@ -0,0 +1,15 @@ +current: all_modules + +include ../../Makefile.config + +PDP_MOD = pdp_chrot.o pdp_grey2mask.o pdp_scale.o pdp_scan.o \ + pdp_scanxy.o pdp_scope.o \ + pdp_cog.o pdp_array.o $(PDP_IMAGE_SPECIAL) + +# build special case image (and sound) processing modules +all_modules: $(PDP_MOD) + +clean: + rm -f *~ + rm -f *.o + diff --git a/modules/image_special/README b/modules/image_special/README new file mode 100644 index 0000000..208710f --- /dev/null +++ b/modules/image_special/README @@ -0,0 +1,2 @@ +This directory contains image processors that don't fit into the basic and io categories. + diff --git a/modules/image_special/pdp_array.c b/modules/image_special/pdp_array.c new file mode 100644 index 0000000..41ea0d5 --- /dev/null +++ b/modules/image_special/pdp_array.c @@ -0,0 +1,194 @@ +/*
+ * Pure Data Packet module.
+ * Copyright (c) 2003 by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * 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.
+ *
+ */
+
+
+#include <math.h>
+
+#include "pdp.h"
+#include "pdp_base.h"
+
+
+typedef struct _pdp_array
+{
+ t_object x_obj;
+ t_symbol *x_array_sym;
+ t_outlet *x_outlet; // for array->pdp
+ t_int x_rows;
+
+ /* the packet */
+ int x_packet0;
+
+} t_pdp_array;
+
+
+static void pdp_array_bang(t_pdp_array *x)
+{
+ post("not implemented");
+}
+
+
+static void pdp_array_input_0(t_pdp_array *x, t_symbol *s, t_floatarg f)
+{
+ int packet = (int)f;
+
+
+ /* register */
+ if (s == gensym("register_ro")){
+ /* replace if not compatible or we are not interpolating */
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = pdp_packet_convert_ro(packet, pdp_gensym("image/grey/*"));
+ }
+
+ /* process */
+ if (s == gensym("process")){
+ float *vec;
+ int nbpoints;
+ t_garray *a;
+ t_pdp *header = pdp_packet_header(x->x_packet0);
+ short int *data = pdp_packet_data(x->x_packet0);
+ if (!header || !data) return;
+
+ /* dump to array if possible */
+ if (!x->x_array_sym){
+ }
+
+ /* check if array is valid */
+ else if (!(a = (t_garray *)pd_findbyclass(x->x_array_sym, garray_class))){
+ post("pdp_array: %s: no such array", x->x_array_sym->s_name);
+ }
+ /* get data */
+ else if (!garray_getfloatarray(a, &nbpoints, &vec)){
+ post("pdp_array: %s: bad template", x->x_array_sym->s_name);
+ }
+ /* scale and dump in array */
+ else{
+ int i;
+ int w = header->info.image.width;
+ int h = header->info.image.height;
+ int N = w*h;
+ N = (nbpoints < N) ? nbpoints : N;
+
+ /* scan rows */
+ if (x->x_rows){
+ for (i=0; i<N; i++)
+ vec[i] = (float)data[i] * (1.0f / (float)0x8000);
+ }
+ /* scan columns */
+ else{
+ for (i=0; i<N; i++) {
+ int x = i / h;
+ int y = i % h;
+ vec[i] = (float)data[x+(h-y-1)*w] * (1.0f / (float)0x8000);
+ }
+ }
+ //garray_redraw(a);
+ }
+
+ }
+}
+
+static void pdp_array_array(t_pdp_array *x, t_symbol *s)
+{
+ //post("setting symbol %x", s);
+ x->x_array_sym = s;
+ x->x_packet0 = -1;
+}
+
+
+static void pdp_array_free(t_pdp_array *x)
+{
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+
+t_class *pdp_array2grey_class;
+t_class *pdp_grey2array_class;
+
+
+
+void *pdp_array2grey_new(t_symbol *s, t_symbol *r)
+{
+ t_pdp_array *x = (t_pdp_array *)pd_new(pdp_array2grey_class);
+ pdp_array_array(x, s);
+ return (void *)x;
+}
+
+void *pdp_grey2array_new(t_symbol *s, t_symbol *r)
+{
+ t_pdp_array *x = (t_pdp_array *)pd_new(pdp_grey2array_class);
+ pdp_array_array(x, s);
+ if (r == gensym("rows")){
+ x->x_rows = 1;
+ post("pdp_grey2array: scanning rows");
+ }
+ else {
+ x->x_rows = 0;
+ post("pdp_grey2array: scanning columns");
+ }
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_array_setup(void)
+{
+
+ pdp_array2grey_class = class_new(gensym("pdp_array2grey"),
+ (t_newmethod)pdp_array2grey_new,
+ (t_method)pdp_array_free,
+ sizeof(t_pdp_array),
+ 0, A_DEFSYMBOL, A_DEFSYMBOL, A_NULL);
+
+ pdp_grey2array_class = class_new(gensym("pdp_grey2array"),
+ (t_newmethod)pdp_grey2array_new,
+ (t_method)pdp_array_free,
+ sizeof(t_pdp_array),
+ 0, A_DEFSYMBOL, A_DEFSYMBOL, A_NULL);
+
+
+ /* packet input */
+ class_addmethod(pdp_grey2array_class,
+ (t_method)pdp_array_input_0,
+ gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+ /* bang method */
+ class_addmethod(pdp_array2grey_class,
+ (t_method)pdp_array_bang, gensym("bang"), A_NULL);
+
+
+ /* bookkeeping */
+ class_addmethod(pdp_array2grey_class, (t_method)pdp_array_array,
+ gensym("array"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_grey2array_class, (t_method)pdp_array_array,
+ gensym("array"), A_SYMBOL, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/modules/image_special/pdp_chrot.c b/modules/image_special/pdp_chrot.c new file mode 100644 index 0000000..27993c6 --- /dev/null +++ b/modules/image_special/pdp_chrot.c @@ -0,0 +1,144 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_base.h" +#include <math.h> + + +typedef struct pdp_chrot_struct +{ + t_pdp_base x_base; + + float x_matrix[4]; + void *x_crot2d; + +} t_pdp_chrot; + + + +static void pdp_chrot_process(t_pdp_chrot *x) +{ + int packet; + t_pdp *header; + void *data; + unsigned int w,h,size,v_offset; + short int *idata; + + + /* get packet & info */ + packet = pdp_base_get_packet(x, 0); + header = pdp_packet_header(packet); + data = pdp_packet_data (packet); + + /* only process if we have a vlid yv12 image */ + if ((header) && (PDP_IMAGE == header->type) && (PDP_IMAGE_YV12 == header->info.image.encoding)){ + + w = header->info.image.width; + h = header->info.image.height; + + size = w*h; + v_offset = size; + + idata = (short int *)data; + + + /* color rotation for 2 colour planes */ + pdp_imageproc_crot2d_process(x->x_crot2d, idata + v_offset, w>>1, h>>1); + + } + return; +} + + +static void pdp_chrot_setelement(t_pdp_chrot *x, int element, float f) +{ + x->x_matrix[element] = f; + +} + +static void pdp_chrot_angle_radians(t_pdp_chrot *x, t_floatarg angle) +{ + float c = cos(angle); + float s = sin(angle); + + pdp_chrot_setelement(x, 0, c); + pdp_chrot_setelement(x, 1, s); + pdp_chrot_setelement(x, 2, -s); + pdp_chrot_setelement(x, 3, c); + + pdp_imageproc_crot2d_setmatrix(x->x_crot2d, x->x_matrix); +} + +static void pdp_chrot_angle_degrees(t_pdp_chrot *x, t_floatarg angle) +{ + pdp_chrot_angle_radians(x, (angle * (M_PI / 180.f))); + +} + +static void pdp_chrot_free(t_pdp_chrot *x) +{ + pdp_base_free(x); + pdp_imageproc_crot2d_delete(x->x_crot2d); +} + +t_class *pdp_chrot_class; + + + +void *pdp_chrot_new(t_floatarg f) +{ + t_pdp_chrot *x = (t_pdp_chrot *)pd_new(pdp_chrot_class); + + pdp_base_init(x); + pdp_base_add_gen_inlet(x, gensym("float"), gensym("angle")); + pdp_base_add_pdp_outlet(x); + pdp_base_set_process_method(x, (t_pdp_method)pdp_chrot_process); + + x->x_crot2d = pdp_imageproc_crot2d_new(); + pdp_chrot_angle_radians(x, 0.0f); + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_chrot_setup(void) +{ + + + pdp_chrot_class = class_new(gensym("pdp_chrot"), (t_newmethod)pdp_chrot_new, + (t_method)pdp_chrot_free, sizeof(t_pdp_chrot), 0, A_DEFFLOAT, A_NULL); + + pdp_base_setup(pdp_chrot_class); + class_addmethod(pdp_chrot_class, (t_method)pdp_chrot_angle_degrees, gensym("angle"), A_DEFFLOAT, A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_special/pdp_cog.c b/modules/image_special/pdp_cog.c new file mode 100644 index 0000000..c1ea1bf --- /dev/null +++ b/modules/image_special/pdp_cog.c @@ -0,0 +1,243 @@ +/*
+ * Pure Data Packet module.
+ * Copyright (c) 2003 by Johannes Taelman <johannes.taelman@rug.ac.be>
+ * API updates by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * 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.
+ *
+ */
+
+
+
+#include "pdp.h"
+#include "pdp_base.h"
+#include <math.h>
+
+typedef struct pdp_cog_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+ t_outlet *x_outlet1;
+ t_outlet *x_outlet2;
+ t_outlet *x_outlet3;
+ t_outlet *x_outlet4;
+
+ int x_packet0;
+ int x_threshold;
+ int x_do_thresholding;
+} t_pdp_cog;
+
+
+static void _pdp_cog_perform(t_pdp_cog *x, int width, int height, short int *data0)
+{
+ short int *pp;
+ int nbpixels;
+
+ int y;
+ int h,v;
+
+ int rowsums[width];
+ int columnsums[height];
+
+ float vsum,vvar,vcog,vstd;
+ float hsum,hvar,hcog,hstd;
+
+
+ pp=data0;
+
+ nbpixels=width*height;
+
+ for (h=0;h<width;h++)
+ columnsums[h]=0;
+
+ /* create column & row sums from thresholded data */
+ if (x->x_do_thresholding){
+ for (v=0;v<height;v++){
+ int rs=0;
+ for (h=0;h<width;h++){
+ int d=*pp++;
+
+ d=(d>x->x_threshold) ? d : ((d<-x->x_threshold)?(-d):0);
+ columnsums[h]+= d;
+ rs+=d;
+ }
+ rowsums[v]=rs;
+ }
+ }
+
+ /* don't perform thresholding */
+ else{
+ for (v=0;v<height;v++){
+ int rs=0;
+ for (h=0;h<width;h++){
+ int d=*pp++;
+ columnsums[h]+= d;
+ rs+=d;
+ }
+ rowsums[v]=rs;
+ }
+ }
+
+
+ /* compute vertical mean and standard dev */
+ vsum=1;
+ vvar=height*height/4;
+ vcog=height/2;
+ for (v=0;v<height;v++){
+ float d=rowsums[v];
+ vsum+=d;
+ vcog+=d*v;
+ }
+ vcog/=vsum;
+ for (v=0;v<height;v++){
+ float d=rowsums[v];
+ float f=v-vcog;
+ vvar+=d*f*f;
+ }
+ vstd=sqrt(vvar/vsum)/height;
+
+ /* compute horizontal meaan and standard dev */
+ hsum=1;
+ hvar=width*width/4;
+ hcog=width/2;
+ for (h=0;h<width;h++){
+ float d=columnsums[h];
+ hsum+=d;
+ hcog+=d*h;
+ }
+ hcog/=hsum;
+ for (h=0;h<width;h++){
+ float d=columnsums[h];
+ float f=h-hcog;
+ hvar+=d*f*f;
+ }
+ hstd=sqrt(hvar/hsum)/width;
+
+ /* pass it on */
+ outlet_float(x->x_outlet4,vstd);
+ outlet_float(x->x_outlet3,hstd);
+ outlet_float(x->x_outlet2,vcog/height);
+ outlet_float(x->x_outlet1,hcog/width);
+ outlet_float(x->x_outlet0,(1.0f / (float)(0x7fff)) * hsum/(height*width));
+}
+
+
+// packet is an image/*/* packet or invalid */
+static void pdp_cog_perform(t_pdp_cog *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data(x->x_packet0);
+ if (!header0 || !data0) return;
+
+ _pdp_cog_perform(x,
+ header0->info.image.width,
+ header0->info.image.height,
+ data0);
+}
+
+
+
+static void pdp_cog_input_0(t_pdp_cog *x, t_symbol *s, t_floatarg f)
+{
+ int packet = (int)f;
+
+ /* register */
+ if (s == gensym("register_ro")){
+ /* replace if not compatible or we are not interpolating */
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = pdp_packet_convert_ro(packet, pdp_gensym("image/*/*"));
+
+ }
+
+ if (s == gensym("process")){
+ pdp_cog_perform(x);
+ }
+
+}
+
+
+static void pdp_cog_threshold(t_pdp_cog *x, t_floatarg f)
+{
+ x->x_threshold=(int) (f * ((float) 0x7fff));
+}
+
+
+
+static void pdp_cog_free(t_pdp_cog *x)
+{
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+
+t_class *pdp_cog_class;
+
+
+
+void *pdp_cog_new(void)
+{
+
+ t_pdp_cog *x = (t_pdp_cog *)pd_new(pdp_cog_class);
+
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet3 = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet4 = outlet_new(&x->x_obj, &s_float);
+
+ x->x_packet0 = -1;
+ x->x_do_thresholding = 0;
+
+ return (void *)x;
+}
+
+void *pdp_cog_abs_thresh_new(t_floatarg f)
+{
+ t_pdp_cog *x = (t_pdp_cog *)pdp_cog_new();
+ inlet_new((void *)x, &x->x_obj.ob_pd, gensym("float"),gensym("threshold"));
+ pdp_cog_threshold(x, f);
+ x->x_do_thresholding = 1;
+ return (void *)x;
+}
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_cog_setup(void)
+{
+
+ pdp_cog_class = class_new(gensym("pdp_cog"), (t_newmethod)pdp_cog_new,
+ (t_method)pdp_cog_free, sizeof(t_pdp_cog), 0,A_NULL);
+
+ class_addcreator((t_newmethod)pdp_cog_abs_thresh_new, gensym("pdp_cog_abs_thresh"), A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_cog_class, (t_method)pdp_cog_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_cog_class, (t_method)pdp_cog_threshold, gensym("threshold"),A_DEFFLOAT, A_NULL);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/modules/image_special/pdp_grey2mask.c b/modules/image_special/pdp_grey2mask.c new file mode 100644 index 0000000..4f10772 --- /dev/null +++ b/modules/image_special/pdp_grey2mask.c @@ -0,0 +1,195 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 module converts a greyscale image or the luma channel of a colour image + to a colour image intensity mask, usable for multiplication */ + +#include "pdp.h" +#include "pdp_resample.h" + +typedef struct pdp_grey2mask_struct +{ + t_object x_obj; + t_float x_f; + + t_outlet *x_outlet0; + + int x_packet0; + int x_dropped; + int x_queue_id; + + +} t_pdp_grey2mask; + + + +static void pdp_grey2mask_process_grey(t_pdp_grey2mask *x) +{ + t_pdp *header = pdp_packet_header(x->x_packet0); + short int *data = (short int *)pdp_packet_data (x->x_packet0); + t_pdp *newheader = 0; + short int *newdata = 0; + int newpacket = -1; + + unsigned int w = header->info.image.width; + unsigned int h = header->info.image.height; + + unsigned int size = w*h; + unsigned int totalnbpixels = size; + unsigned int u_offset = size; + unsigned int v_offset = size + (size>>2); + + unsigned int row, col; + + newpacket = pdp_packet_new_image_YCrCb(w, h); + newheader = pdp_packet_header(newpacket); + newdata = (short int *)pdp_packet_data(newpacket); + + /* copy luma channel */ + memcpy(newdata, data, size * sizeof(s16)); + + /* subsample luma -> chroma channel */ + pdp_resample_halve(data, newdata+u_offset, w, h); + + /* copy this to the other chroma channel */ + memcpy(newdata+v_offset, newdata+u_offset, (size>>2)*sizeof(s16)); + + /* delete source packet and replace with new packet */ + pdp_packet_mark_unused(x->x_packet0); + x->x_packet0 = newpacket; + return; +} + +static void pdp_grey2mask_process_yv12(t_pdp_grey2mask *x) +{ + /* process only the luminance channel */ + pdp_grey2mask_process_grey(x); +} + + + +static void pdp_grey2mask_process(t_pdp_grey2mask *x) +{ + int encoding; + t_pdp *header = 0; + + /* check if image data packets are compatible */ + if ( (header = pdp_packet_header(x->x_packet0)) + && (PDP_IMAGE == header->type)){ + + /* pdp_grey2mask_process inputs and write into active inlet */ + switch(pdp_packet_header(x->x_packet0)->info.image.encoding){ + + case PDP_IMAGE_YV12: + pdp_grey2mask_process_yv12(x); + break; + + case PDP_IMAGE_GREY: + pdp_grey2mask_process_grey(x); + break; + + default: + /* don't know the type, so dont pdp_grey2mask_process */ + + break; + } + } +} + +static void pdp_grey2mask_sendpacket(t_pdp_grey2mask *x) +{ + /* unregister and propagate if valid packet */ + pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet0); +} + +static void pdp_grey2mask_input_0(t_pdp_grey2mask *x, t_symbol *s, t_floatarg f) +{ + + int p = (int)f; + + if (s== gensym("register_ro")) x->x_dropped = pdp_packet_copy_ro_or_drop(&x->x_packet0, p); + + + if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){ + + + /* add the process method and callback to the process queue */ + + //pdp_queue_add(x, pdp_grey2mask_process, pdp_grey2mask_sendpacket, &x->x_queue_id); + // since the process method creates a packet, this is not processed in the thread + // $$$TODO: fix this + pdp_grey2mask_process(x); + pdp_grey2mask_sendpacket(x); + } + +} + + + +static void pdp_grey2mask_free(t_pdp_grey2mask *x) +{ + t_pdp_procqueue *q = pdp_queue_get_queue(); + pdp_procqueue_finish(q, x->x_queue_id); + pdp_packet_mark_unused(x->x_packet0); + +} + +t_class *pdp_grey2mask_class; + + + +void *pdp_grey2mask_new(void) +{ + int i; + + t_pdp_grey2mask *x = (t_pdp_grey2mask *)pd_new(pdp_grey2mask_class); + + x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + x->x_packet0 = -1; + x->x_queue_id = -1; + + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_grey2mask_setup(void) +{ + + + pdp_grey2mask_class = class_new(gensym("pdp_grey2mask"), (t_newmethod)pdp_grey2mask_new, + (t_method)pdp_grey2mask_free, sizeof(t_pdp_grey2mask), 0, A_NULL); + + + class_addmethod(pdp_grey2mask_class, (t_method)pdp_grey2mask_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_special/pdp_histo.c b/modules/image_special/pdp_histo.c new file mode 100644 index 0000000..43cdb8c --- /dev/null +++ b/modules/image_special/pdp_histo.c @@ -0,0 +1,415 @@ +/*
+ * Pure Data Packet module.
+ * Copyright (c) 2003 by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * 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.
+ *
+ */
+
+
+
+#include "pdp.h"
+#include "pdp_base.h"
+#include <math.h>
+
+struct _pdp_histo;
+typedef void (*t_histo_proc)(struct _pdp_histo *);
+
+
+typedef struct _pdp_histo
+{
+ t_object x_obj;
+ t_int x_logN;
+ t_symbol *x_array_sym;
+ t_float x_scale;
+ t_int x_debug;
+ t_int x_sample_size; /* pointcloud size */
+ t_histo_proc x_process_method; /* what to do with the histogram */
+ t_outlet *x_outlet0;
+ int x_matrix_output;
+
+ /* the packet */
+ int x_packet0;
+
+ /* packet data */
+ short int *x_data;
+ int x_width;
+ int x_height;
+ int x_nb_pixels;
+
+ /* histo data for processor: these are stored on the stack */
+ int *x_histo;
+
+} t_pdp_histo;
+
+
+static int round_up_2log(int i)
+{
+ int l = 0;
+ i--;
+ while (i) {
+ i >>= 1;
+ l++;
+ }
+ //post("log is %d, 2^n is %d", l, 1 << l);
+
+ l = (l < 16) ? l : 15;
+ return l;
+}
+
+
+static void dump_to_array(t_pdp_histo *x)
+{
+ float *vec;
+ int nbpoints;
+ t_garray *a;
+ int i;
+ int *histo = x->x_histo;
+ int N = 1 << (x->x_logN);
+ float scale = 1.0f / (float)(x->x_nb_pixels);
+
+
+ /* dump to array if possible */
+ if (!x->x_array_sym){
+ }
+
+ /* check if array is valid */
+ else if (!(a = (t_garray *)pd_findbyclass(x->x_array_sym, garray_class))){
+ post("pdp_histo: %s: no such array", x->x_array_sym->s_name);
+ }
+ /* get data */
+ else if (!garray_getfloatarray(a, &nbpoints, &vec)){
+ post("pdp_histo: %s: bad template", x->x_array_sym->s_name);
+ }
+ /* scale and dump in array */
+ else{
+
+ N = (nbpoints < N) ? nbpoints : N;
+ for (i=0; i<N; i++) vec[i] = (float)(histo[i]) * scale * x->x_scale;
+ //garray_redraw(a);
+ }
+
+}
+
+static void get_sampleset(t_pdp_histo *x, int log_tmp_size, int threshold)
+{
+ int N = 1 << log_tmp_size;
+ int mask = N-1;
+ int index, nbpoints, i;
+ t_atom a[2];
+ double scalex = 1.0f / (double)(x->x_width);
+ double scaley = 1.0f / (double)(x->x_height);
+ t_symbol *s = gensym("list");
+ int matrix_packet;
+ double *mat_data;
+
+ /* store the offsets of the points in a in an oversized array
+ the oversizing is to eliminate a division and to limit the
+ searching for a free location after a random index is generated */
+
+ int offset[N];
+
+ /* reset the array */
+ memset(offset, -1, N * sizeof(int));
+
+ /* get the coordinates of the tempsize brightest points
+ and store them in a random location in the hash */
+ for (i=0; i<x->x_nb_pixels; i++){
+ if (x->x_data[i] >= threshold){
+ /* get a random index */
+ int ri = random();
+ //int ri = 0;
+ /* find an empty spot to store it */
+ while (-1 != offset[ri & mask]) ri++;
+ offset[ri & mask] = i;
+ }
+ }
+
+
+ /* repack the array to get the requested
+ sample size at the start */
+ index = 0;
+ nbpoints = 0;
+ while (nbpoints < x->x_sample_size){
+ while (-1 == offset[index]) index++; // ffwd to next nonepty slot
+ offset[nbpoints++] = offset[index++]; // move slot
+ }
+
+
+ /* MATRIX OUTPUT */
+ if (x->x_matrix_output){
+
+ matrix_packet = pdp_packet_new_matrix(x->x_sample_size, 2, PDP_MATRIX_TYPE_RDOUBLE);
+ mat_data = pdp_packet_data(matrix_packet);
+ if (mat_data){
+
+ /* build the cluster data struct */
+ for (i=0; i<x->x_sample_size; i++){
+ mat_data[2*i] = ((double)(offset[i] % x->x_width)) * scalex;
+ mat_data[2*i+1] = ((double)(offset[i] / x->x_width)) * scaley;
+ }
+
+ pdp_pass_if_valid(x->x_outlet0, &matrix_packet);
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = -1;
+ }
+
+ }
+
+ /* IMAGE OUTPUT */
+ else {
+
+ /* get rw copy */
+ pdp_packet_replace_with_writable(&x->x_packet0);
+ x->x_data = pdp_packet_data(x->x_packet0);
+
+ /* mark output packet samples */
+ if (x->x_data){
+ memset(x->x_data, 0, 2*x->x_nb_pixels);
+ for (i=0; i<x->x_sample_size; i++){
+ x->x_data[offset[i]] = 0x7fff;
+ }
+ }
+
+ /* send packet to left outlet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+ }
+
+
+}
+
+static void get_brightest(t_pdp_histo *x)
+{
+ int i;
+ int *histo = x->x_histo;
+ int N = 1 << (x->x_logN);
+
+ int index, nsamps;
+
+ /* check requested size */
+ if (x->x_sample_size > x->x_nb_pixels){
+ post("WARNING: more samples requested than pixels in image");
+ x->x_sample_size = x->x_nb_pixels;
+ }
+
+
+ /* find limiting index */
+ index = N;
+ nsamps = 0;
+ while (nsamps < x->x_sample_size){
+ index--;
+ nsamps += histo[index];
+ }
+
+ /* status report */
+ if (x->x_debug){
+ post("found %d samples between h[%d] and h[%d]", nsamps, index, N-1);
+ }
+
+ /* get a representative set from the candidates
+ the tempbuf is the rounded log of the nb of samples + 1
+ so it is at least 50% sparse */
+ get_sampleset(x, round_up_2log(nsamps) + 1, index << (15-x->x_logN));
+
+}
+
+
+static void _pdp_histo_perform(t_pdp_histo *x)
+{
+ short int *pp;
+ int N = 1 << x->x_logN;
+ int nbpixels = x->x_width * x->x_height, i;
+
+ int histo[N];
+
+ /* init */
+ for (i=0; i<N; i++) histo[i] = 0;
+
+ /* build histo */
+ for (i=0; i<nbpixels; i++){
+ int index = x->x_data[i] >> (15 - x->x_logN);
+ if (index < 0) index = 0; /* negative -> zero */
+ histo[index]++;
+ }
+
+ /* save the histo stack location */
+ x->x_histo = histo;
+
+ /* print it */
+ if (x->x_debug){
+ post("histogram:");
+ for (i=0; i<N; i++){
+ fprintf(stderr, "%d\t", histo[i]);
+ if (!(i % 10)) post("");
+ }
+ post("");
+ }
+
+ /* call the processor */
+ x->x_process_method(x);
+
+
+}
+
+
+// packet is an image/*/* packet or invalid */
+static void pdp_histo_perform(t_pdp_histo *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data(x->x_packet0);
+ if (!header0 || !data0) return;
+
+ x->x_width = header0->info.image.width;
+ x->x_height = header0->info.image.height;
+ x->x_nb_pixels = x->x_width * x->x_height;
+ x->x_data = data0;
+
+ _pdp_histo_perform(x);
+}
+
+
+
+static void pdp_histo_input_0(t_pdp_histo *x, t_symbol *s, t_floatarg f)
+{
+ int packet = (int)f;
+
+ /* register */
+ if (s == gensym("register_rw")){
+ /* replace if not compatible or we are not interpolating */
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = pdp_packet_convert_ro(packet, pdp_gensym("image/grey/*"));
+
+ }
+
+ if (s == gensym("process")){
+ pdp_histo_perform(x);
+ }
+
+}
+
+
+
+static void pdp_histo_samplesize(t_pdp_histo *x, t_floatarg f)
+{
+ int i = (int)f;
+ if (i > 0) x->x_sample_size = i;
+}
+
+
+static void pdp_histo_scale(t_pdp_histo *x, t_floatarg f){x->x_scale = f;}
+
+
+
+static void pdp_histo_size(t_pdp_histo *x, t_floatarg f)
+{
+ int i = (int)f;
+ if (i < 1) return;
+ x->x_logN = round_up_2log(i);
+}
+
+
+static void pdp_histo_array(t_pdp_histo *x, t_symbol *s)
+{
+ //post("setting symbol %x", s);
+ x->x_array_sym = s;
+}
+
+
+static void pdp_histo_free(t_pdp_histo *x)
+{
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+
+t_class *pdp_histo_class;
+
+
+
+void *pdp_histo_new(t_floatarg f)
+{
+
+ t_pdp_histo *x = (t_pdp_histo *)pd_new(pdp_histo_class);
+ if (f == 0.0f) f = 64;
+ pdp_histo_size(x, f);
+ x->x_packet0 = -1;
+ x->x_debug = 0;
+ x->x_sample_size = 16;
+ return (void *)x;
+}
+
+
+void *pdp_histo_array_new(t_symbol *s, t_float f, t_float f2)
+{
+ t_pdp_histo *x = (t_pdp_histo *)pdp_histo_new(f);
+ if (f2 == 0.0f) f2 = 1.0f;
+ pdp_histo_scale(x, f2);
+ pdp_histo_array(x, s);
+ x->x_process_method = dump_to_array;
+ return (void *)x;
+}
+
+void *pdp_histo_sample_new(t_float nbsamples, t_float histosize)
+{
+ t_pdp_histo *x;
+ if (histosize == 0.0f) histosize = 256.0f;
+ x = (t_pdp_histo *)pdp_histo_new(histosize);
+ if (nbsamples == 0.0f) nbsamples = 16.0f;
+ pdp_histo_samplesize(x, nbsamples);
+ x->x_process_method = get_brightest;
+ x->x_outlet0 = outlet_new(&x->x_obj, gensym("anything"));
+ x->x_matrix_output = 0;
+
+ inlet_new((t_object *)x, (t_pd *)&x->x_obj, gensym("float"), gensym("nbpoints"));
+
+ return (void *)x;
+}
+
+void *pdp_histo_sample_matrix_new(t_float nbsamples, t_float histosize)
+{
+ t_pdp_histo *x = pdp_histo_sample_new(nbsamples, histosize);
+ if (x) x->x_matrix_output = 1;
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_histo_setup(void)
+{
+
+ pdp_histo_class = class_new(gensym("pdp_histo"), (t_newmethod)pdp_histo_array_new,
+ (t_method)pdp_histo_free, sizeof(t_pdp_histo), 0, A_DEFSYMBOL, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+
+ class_addcreator((t_newmethod)pdp_histo_sample_new, gensym("pdp_pointcloud"), A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+ class_addcreator((t_newmethod)pdp_histo_sample_matrix_new, gensym("pdp_pointcloud_matrix"), A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_histo_class, (t_method)pdp_histo_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_histo_class, (t_method)pdp_histo_size, gensym("size"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_histo_class, (t_method)pdp_histo_size, gensym("scale"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_histo_class, (t_method)pdp_histo_array, gensym("array"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_histo_class, (t_method)pdp_histo_samplesize, gensym("nbpoints"), A_FLOAT, A_NULL);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/modules/image_special/pdp_scale.c b/modules/image_special/pdp_scale.c new file mode 100644 index 0000000..3c74bd8 --- /dev/null +++ b/modules/image_special/pdp_scale.c @@ -0,0 +1,277 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_resample.h" + + + +typedef struct pdp_scale_struct +{ + t_object x_obj; + t_float x_f; + + t_outlet *x_outlet0; + + + int x_packet0; + int x_packet1; + int x_dropped; + int x_queue_id; + + unsigned int x_width; + unsigned int x_height; + int x_quality; + + +} t_pdp_scale; + + +static void pdp_scale_process_yv12(t_pdp_scale *x) +{ + t_pdp *header0 = pdp_packet_header(x->x_packet0); + t_pdp *header1 = pdp_packet_header(x->x_packet1); + void *data0 = pdp_packet_data (x->x_packet0); + void *data1 = pdp_packet_data (x->x_packet1); + + unsigned int src_w = header0->info.image.width; + unsigned int src_h = header0->info.image.height; + + unsigned int dst_w = header1->info.image.width; + unsigned int dst_h = header1->info.image.height; + + short int *src_image = (short int *)data0; + short int *dst_image = (short int *)data1; + + unsigned int src_size = src_w*src_h; + unsigned int src_voffset = src_size; + unsigned int src_uoffset = src_size + (src_size>>2); + + unsigned int dst_size = dst_w*dst_h; + unsigned int dst_voffset = dst_size; + unsigned int dst_uoffset = dst_size + (dst_size>>2); + + if (x->x_quality){ + pdp_resample_scale_bilin(src_image, dst_image, src_w, src_h, dst_w, dst_h); + pdp_resample_scale_bilin(src_image+src_voffset, dst_image+dst_voffset, src_w>>1, src_h>>1, dst_w>>1, dst_h>>1); + pdp_resample_scale_bilin(src_image+src_uoffset, dst_image+dst_uoffset, src_w>>1, src_h>>1, dst_w>>1, dst_h>>1); + } + else{ + pdp_resample_scale_nn(src_image, dst_image, src_w, src_h, dst_w, dst_h); + pdp_resample_scale_nn(src_image+src_voffset, dst_image+dst_voffset, src_w>>1, src_h>>1, dst_w>>1, dst_h>>1); + pdp_resample_scale_nn(src_image+src_uoffset, dst_image+dst_uoffset, src_w>>1, src_h>>1, dst_w>>1, dst_h>>1); + } + + return; +} + +static void pdp_scale_process_grey(t_pdp_scale *x) +{ + + t_pdp *header0 = pdp_packet_header(x->x_packet0); + t_pdp *header1 = pdp_packet_header(x->x_packet1); + void *data0 = pdp_packet_data (x->x_packet0); + void *data1 = pdp_packet_data (x->x_packet1); + + unsigned int src_w = header0->info.image.width; + unsigned int src_h = header0->info.image.height; + + unsigned int dst_w = header1->info.image.width; + unsigned int dst_h = header1->info.image.height; + + short int *src_image = (short int *)data0; + short int *dst_image = (short int *)data1; + + if (x->x_quality) pdp_resample_scale_bilin(src_image, dst_image, src_w, src_h, dst_w, dst_h); + else pdp_resample_scale_nn(src_image, dst_image, src_w, src_h, dst_w, dst_h); + + return; + + +} + +static void pdp_scale_sendpacket(t_pdp_scale *x) +{ + /* delete source packet */ + pdp_packet_mark_unused(x->x_packet0); + x->x_packet0 = -1; + + /* unregister and propagate if valid dest packet */ + pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet1); +} + +static void pdp_scale_process(t_pdp_scale *x) +{ + t_pdp_procqueue *q = pdp_queue_get_queue(); + t_pdp *header0 = pdp_packet_header(x->x_packet0); + + /* check data packets */ + + if ((header0) && (PDP_IMAGE == header0->type)){ + + /* if dims are equal, just send the packet */ + if ((header0->info.image.width == x->x_width) + && (header0->info.image.height == x->x_height)){ + x->x_packet1 = x->x_packet0; + x->x_packet0 = -1; + pdp_scale_sendpacket(x); + return; + } + + /* type hub */ + switch(header0->info.image.encoding){ + + case PDP_IMAGE_YV12: + x->x_packet1 = pdp_packet_new_image_YCrCb(x->x_width, x->x_height); + if(x->x_packet1 == -1){ + post("pdp_scale: can't allocate packet"); + return; + } + pdp_procqueue_add(q, x, pdp_scale_process_yv12, pdp_scale_sendpacket, &x->x_queue_id); + break; + + case PDP_IMAGE_GREY: + x->x_packet1 = pdp_packet_new_image_grey(x->x_width, x->x_height); + if(x->x_packet1 == -1){ + post("pdp_scale: can't allocate packet"); + return; + } + pdp_procqueue_add(q, x, pdp_scale_process_grey, pdp_scale_sendpacket, &x->x_queue_id); + break; + + default: + break; + /* don't know the type, so dont process */ + + } + } + +} + + + + +static void pdp_scale_input_0(t_pdp_scale *x, t_symbol *s, t_floatarg f) +{ + + int p = (int)f; + int passes, i; + + if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_ro_or_drop(&x->x_packet0, p); + + + if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){ + + /* add the process method and callback to the process queue */ + pdp_scale_process(x); + + } + +} + + + + +static void pdp_scale_width(t_pdp_scale *x, t_floatarg f) +{ + int i = (int)f; + if (i < 32) i = 32; + x->x_width = i; +} + +static void pdp_scale_height(t_pdp_scale *x, t_floatarg f) +{ + int i = (int)f; + if (i < 32) i = 32; + x->x_height = i; +} + + +static void pdp_scale_dim(t_pdp_scale *x, t_floatarg w, t_floatarg h) +{ + pdp_scale_width(x, w); + pdp_scale_height(x, h); +} + +static void pdp_scale_quality(t_pdp_scale *x, t_floatarg f) +{ + if (f==0) x->x_quality = 0; + if (f==1) x->x_quality = 1; +} + + +t_class *pdp_scale_class; + + + +void pdp_scale_free(t_pdp_scale *x) +{ + t_pdp_procqueue *q = pdp_queue_get_queue(); + pdp_procqueue_finish(q, x->x_queue_id); + pdp_packet_mark_unused(x->x_packet0); + pdp_packet_mark_unused(x->x_packet1); +} + +void *pdp_scale_new(t_floatarg fw, t_floatarg fh) +{ + t_pdp_scale *x = (t_pdp_scale *)pd_new(pdp_scale_class); + + x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + + x->x_packet0 = -1; + x->x_packet1 = -1; + x->x_queue_id = -1; + + if ((fw != 0.0f) && (fh != 0.0f)) pdp_scale_dim(x, fw, fh); + else pdp_scale_dim(x, 320, 240); + + pdp_scale_quality(x, 1); + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_scale_setup(void) +{ + + + pdp_scale_class = class_new(gensym("pdp_scale"), (t_newmethod)pdp_scale_new, + (t_method)pdp_scale_free, sizeof(t_pdp_scale), 0, A_DEFFLOAT, A_DEFFLOAT, A_NULL); + + + class_addmethod(pdp_scale_class, (t_method)pdp_scale_quality, gensym("quality"), A_FLOAT, A_NULL); + class_addmethod(pdp_scale_class, (t_method)pdp_scale_width, gensym("width"), A_FLOAT, A_NULL); + class_addmethod(pdp_scale_class, (t_method)pdp_scale_height, gensym("height"), A_FLOAT, A_NULL); + class_addmethod(pdp_scale_class, (t_method)pdp_scale_dim, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_scale_class, (t_method)pdp_scale_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_special/pdp_scan.c b/modules/image_special/pdp_scan.c new file mode 100644 index 0000000..9b80fea --- /dev/null +++ b/modules/image_special/pdp_scan.c @@ -0,0 +1,231 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_mmx.h" +#include <math.h> + +#define PDP_SCAN_COSTABLE_SIZE 1024 +static float pdp_cos[PDP_SCAN_COSTABLE_SIZE]; + +typedef struct pdp_scan_struct +{ + t_object x_obj; + t_float x_f; + + t_outlet *x_outlet0; + t_outlet *x_outlet1; + + float x_centerx; + float x_centery; + float x_sizeh; + float x_sizev; + + int x_packet0; + int x_packet1; + + int x_interpolate; + + +} t_pdp_scan; + + +static t_int *pdp_scan_perform(t_int *w) +{ + + t_pdp_scan *x = (t_pdp_scan *)(w[1]); + t_int n = (t_int)(w[2]); + t_float *in = (float *)(w[3]); + t_float *out = (float *)(w[4]); + + + /* check if valid image */ + if (-1 == x->x_packet0){ + while (n--) *out++ = 0; + return (w+5); + } + else{ + + t_pdp *header0 = pdp_packet_header(x->x_packet0); + short int *data0 = (short int *)pdp_packet_data (x->x_packet0); + short int *data1 = (short int *)pdp_packet_data (x->x_packet1); + int width = (float)header0->info.image.width; + float widthm1 = (float)header0->info.image.width - 1; + float heightm1 = (float)header0->info.image.height - 1; + int i; + + float scale = 1.0f / 32767.0f; + + if (x->x_interpolate && (-1 != x->x_packet1)){ + float a_old = 1.0f; + float a_new = 0.0f; + float a_inc = 1.0f / (float)n; + float old, new; + + while(n--){ + float phase = *in++; + int iphase = (int)(phase * PDP_SCAN_COSTABLE_SIZE); + float c = pdp_cos[iphase & (PDP_SCAN_COSTABLE_SIZE - 1)]; + float s = pdp_cos[(iphase - (PDP_SCAN_COSTABLE_SIZE>>1)) & (PDP_SCAN_COSTABLE_SIZE - 1)]; + int xxx = (int)((x->x_centerx + x->x_sizeh * c) * widthm1); + int yyy = (int)((x->x_centery + x->x_sizev * c) * heightm1); + int offset = yyy*width+xxx; + new = ((float)(data0[offset])) * scale; + old = ((float)(data1[offset])) * scale; + *out++ = a_old * old + a_new * new; + a_new += a_inc; + a_old -= a_inc; + } + + pdp_packet_mark_unused(x->x_packet1); + x->x_packet1 = -1; + } + else{ + while(n--){ + float phase = *in++; + int iphase = (int)(phase * PDP_SCAN_COSTABLE_SIZE); + float c = pdp_cos[iphase & (PDP_SCAN_COSTABLE_SIZE - 1)]; + float s = pdp_cos[(iphase - (PDP_SCAN_COSTABLE_SIZE>>1)) & (PDP_SCAN_COSTABLE_SIZE - 1)]; + int xxx = (int)((x->x_centerx + x->x_sizeh * c) * widthm1); + int yyy = (int)((x->x_centery + x->x_sizev * c) * heightm1); + *out++ = ((float)(data0[yyy*width+xxx])) * scale; + } + } + + return (w+5); + + } +} + + + + +static void pdp_scan_input_0(t_pdp_scan *x, t_symbol *s, t_floatarg f) +{ + int packet = (int)f; + + /* register */ + if (s== gensym("register_ro")){ + t_pdp *header = pdp_packet_header(packet); + if (!header) return; + if (PDP_IMAGE != header->type) return; + if ((header->info.image.encoding != PDP_IMAGE_YV12) && (header->info.image.encoding != PDP_IMAGE_GREY)) return; + + /* replace if not compatible or we are not interpolating */ + if (!x->x_interpolate || (!pdp_packet_image_compat(x->x_packet0, packet))){ + pdp_packet_mark_unused(x->x_packet0); + x->x_packet0 = pdp_packet_copy_ro(packet); + } + /* otherwize keep the old one */ + else{ + pdp_packet_mark_unused(x->x_packet1); + x->x_packet1 = x->x_packet0; + x->x_packet0 = pdp_packet_copy_ro(packet); + } + } + + /* pass packet */ + if (s== gensym("process")){ + //if (-1 != x->x_packet0) outlet_pdp (x->x_outlet0, x->x_packet0); + } + + +} + + + + +static void pdp_scan_dsp (t_pdp_scan *x, t_signal **sp) +{ + dsp_add(pdp_scan_perform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + +} + + +static void pdp_scan_interpolate(t_pdp_scan *x, t_floatarg f) +{ + if (0.0 == f){ + x->x_interpolate = 0; + pdp_packet_mark_unused(x->x_packet1); + } + if (1.0 == f) x->x_interpolate = 1; +} + +static void pdp_scan_free(t_pdp_scan *x) +{ + pdp_packet_mark_unused(x->x_packet0); +} + + +t_class *pdp_scan_class; + + + +void *pdp_scan_new(void) +{ + t_pdp_scan *x = (t_pdp_scan *)pd_new(pdp_scan_class); + + + //x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + x->x_outlet1 = outlet_new(&x->x_obj, &s_signal); + x->x_packet0 = -1; + x->x_packet1 = -1; + + x->x_centerx = 0.5f; + x->x_centery = 0.5f; + x->x_sizeh = 0.3; + x->x_sizev = 0.3; + + pdp_scan_interpolate(x, 0); + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_scan_setup(void) +{ + int i; + for (i=0; i<PDP_SCAN_COSTABLE_SIZE; i++) + pdp_cos[i] = cos((double)(i) * 2 * M_PI / PDP_SCAN_COSTABLE_SIZE); + + + pdp_scan_class = class_new(gensym("pdp_scan~"), (t_newmethod)pdp_scan_new, + (t_method)pdp_scan_free, sizeof(t_pdp_scan), 0, A_NULL); + + CLASS_MAINSIGNALIN(pdp_scan_class, t_pdp_scan, x_f); + + class_addmethod(pdp_scan_class, (t_method)pdp_scan_interpolate, gensym("interpolate"), A_FLOAT, A_NULL); + class_addmethod(pdp_scan_class, (t_method)pdp_scan_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_scan_class, (t_method)pdp_scan_dsp, gensym("dsp"), A_NULL); + + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_special/pdp_scanxy.c b/modules/image_special/pdp_scanxy.c new file mode 100644 index 0000000..6fd7201 --- /dev/null +++ b/modules/image_special/pdp_scanxy.c @@ -0,0 +1,207 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include <math.h> + +typedef struct pdp_scanxy_struct +{ + t_object x_obj; + t_float x_f; + + t_outlet *x_outlet0; + t_outlet *x_outlet1; + + int x_packet0; + int x_packet1; + + int x_interpolate; + + +} t_pdp_scanxy; + + +static t_int *pdp_scanxy_perform(t_int *w) +{ + + t_pdp_scanxy *x = (t_pdp_scanxy *)(w[1]); + t_int n = (t_int)(w[2]); + t_float *inx = (float *)(w[3]); + t_float *iny = (float *)(w[4]); + t_float *out = (float *)(w[5]); + + + /* check if valid image */ + if (-1 == x->x_packet0){ + while (n--) *out++ = 0; + return (w+6); + } + else{ + + t_pdp *header0 = pdp_packet_header(x->x_packet0); + short int *data0 = (short int *)pdp_packet_data (x->x_packet0); + short int *data1 = (short int *)pdp_packet_data (x->x_packet1); + int width = (float)header0->info.image.width; + int height = (float)header0->info.image.height; + int i; + + float scale = 1.0f / 32767.0f; + float scalein = 0x10000; + + if (x->x_interpolate && (-1 != x->x_packet1)){ + float a_old = 1.0f; + float a_new = 0.0f; + float a_inc = 1.0f / (float)n; + float old, new; + + while(n--){ + int xxx = ((((int)(scalein * *inx++)) & 0xffff) * width) >> 16; + int yyy = ((((int)(scalein * *iny++)) & 0xffff) * height) >> 16; + int offset = yyy*width+xxx; + new = ((float)(data0[offset])) * scale; + old = ((float)(data1[offset])) * scale; + *out++ = a_old * old + a_new * new; + a_new += a_inc; + a_old -= a_inc; + } + + pdp_packet_mark_unused(x->x_packet1); + x->x_packet1 = -1; + } + else{ + while(n--){ + int xxx = ((((int)(scalein * *inx++)) & 0xffff) * width) >> 16; + int yyy = ((((int)(scalein * *iny++)) & 0xffff) * height) >> 16; + int offset = yyy*width+xxx; + *out++ = ((float)(data0[offset])) * scale; + } + } + + return (w+6); + + } +} + + + + +static void pdp_scanxy_input_0(t_pdp_scanxy *x, t_symbol *s, t_floatarg f) +{ + int packet = (int)f; + + /* register */ + if (s== gensym("register_ro")){ + t_pdp *header = pdp_packet_header(packet); + if (!header) return; + if (PDP_IMAGE != header->type) return; + if ((header->info.image.encoding != PDP_IMAGE_YV12) && (header->info.image.encoding != PDP_IMAGE_GREY)) return; + + /* replace if not compatible or we are not interpolating */ + if (!x->x_interpolate || (!pdp_packet_image_compat(x->x_packet0, packet))){ + pdp_packet_mark_unused(x->x_packet0); + x->x_packet0 = pdp_packet_copy_ro(packet); + } + /* otherwize keep the old one */ + else{ + pdp_packet_mark_unused(x->x_packet1); + x->x_packet1 = x->x_packet0; + x->x_packet0 = pdp_packet_copy_ro(packet); + } + } + + /* pass packet */ + if (s== gensym("process")){ + //if (-1 != x->x_packet0) outlet_pdp (x->x_outlet0, x->x_packet0); + } + + +} + + + + +static void pdp_scanxy_dsp (t_pdp_scanxy *x, t_signal **sp) +{ + dsp_add(pdp_scanxy_perform, 5, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); + +} + + +static void pdp_scanxy_interpolate(t_pdp_scanxy *x, t_floatarg f) +{ + if (0.0 == f){ + x->x_interpolate = 0; + pdp_packet_mark_unused(x->x_packet1); + } + if (1.0 == f) x->x_interpolate = 1; +} + +static void pdp_scanxy_free(t_pdp_scanxy *x) +{ + pdp_packet_mark_unused(x->x_packet0); +} + + +t_class *pdp_scanxy_class; + + + +void *pdp_scanxy_new(void) +{ + t_pdp_scanxy *x = (t_pdp_scanxy *)pd_new(pdp_scanxy_class); + + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal")); + x->x_outlet1 = outlet_new(&x->x_obj, &s_signal); + x->x_packet0 = -1; + x->x_packet1 = -1; + + pdp_scanxy_interpolate(x, 0); + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_scanxy_setup(void) +{ + + pdp_scanxy_class = class_new(gensym("pdp_scanxy~"), (t_newmethod)pdp_scanxy_new, + (t_method)pdp_scanxy_free, sizeof(t_pdp_scanxy), 0, A_NULL); + + CLASS_MAINSIGNALIN(pdp_scanxy_class, t_pdp_scanxy, x_f); + + class_addmethod(pdp_scanxy_class, (t_method)pdp_scanxy_interpolate, gensym("interpolate"), A_FLOAT, A_NULL); + class_addmethod(pdp_scanxy_class, (t_method)pdp_scanxy_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_scanxy_class, (t_method)pdp_scanxy_dsp, gensym("dsp"), A_NULL); + + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/image_special/pdp_scope.c b/modules/image_special/pdp_scope.c new file mode 100644 index 0000000..4311a0b --- /dev/null +++ b/modules/image_special/pdp_scope.c @@ -0,0 +1,317 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include <string.h> + +#define BUFSIZE 2048 + +typedef struct pdp_scope_data +{ + short int random_seed[4]; + +}t_pdp_scope_data; + +typedef struct pdp_scope_struct +{ + t_object x_obj; + t_float x_f; + + t_outlet *x_outlet0; + + t_pdp_scope_data *x_data; + int x_packet0; + int x_queue_id; + + int x_pdp_image_type; + + unsigned int x_width; + unsigned int x_height; + + float *x_buffer; + int x_needle; + + +} t_pdp_scope; + + + +void pdp_scope_type(t_pdp_scope *x, t_symbol *s) +{ + if (gensym("yv12") == s) {x->x_pdp_image_type = PDP_IMAGE_YV12; return;} + if (gensym("grey") == s) {x->x_pdp_image_type = PDP_IMAGE_GREY; return;} + + x->x_pdp_image_type = -1; + +} + + + + + +static void pdp_scope_createpacket_yv12(t_pdp_scope *x) +{ + t_pdp *header; + + unsigned int w = x->x_width; + unsigned int h = x->x_height; + + unsigned int size = w*h; + unsigned int totalnbpixels = size + (size >> 1); + unsigned int packet_size = totalnbpixels << 1; + + x->x_packet0 = pdp_packet_new_image_YCrCb(w, h); + if(x->x_packet0 == -1){ + post("pdp_scope: can't allocate packet"); + return; + } + header = pdp_packet_header(x->x_packet0); + memset(pdp_packet_data(x->x_packet0), 0, packet_size); + +} + +static void pdp_scope_generate_yv12(t_pdp_scope *x) +{ + unsigned int w = x->x_width; + unsigned int h = x->x_height; + unsigned int size = w*h; + unsigned int totalnbpixels = size + (size >> 1); + short int *data = (short int *) pdp_packet_data(x->x_packet0); + + unsigned int i; + int offset = x->x_needle; + int val; + unsigned int y; + float fh2 = (float)(h/2); + + if (!data) return; + + + for (i=0; i<w; i++){ + y = (h/2) + (int)(fh2 * -x->x_buffer[(offset - w + i) & (BUFSIZE - 1)]); + if (y>=h) y = h-1; + + data[i + y*w] = 0x7fff; + } + + return; + +} + +static void pdp_scope_createpacket_grey(t_pdp_scope *x) +{ + t_pdp *header; + short int *data; + + unsigned int w = x->x_width; + unsigned int h = x->x_height; + + unsigned int size = w*h; + unsigned int totalnbpixels = size; + unsigned int packet_size = totalnbpixels << 1; + + /* create new packet */ + x->x_packet0 = pdp_packet_new_image_grey(w,h); + if(x->x_packet0 == -1){ + post("pdp_scope: can't allocate packet"); + return; + } + + + header = pdp_packet_header(x->x_packet0); + data = (short int *) pdp_packet_data(x->x_packet0); + + memset(pdp_packet_data(x->x_packet0), 0, packet_size); + +} + +static void pdp_scope_generate_grey(t_pdp_scope *x) +{ + unsigned int w = x->x_width; + unsigned int h = x->x_height; + unsigned int totalnbpixels = x->x_width * x->x_height; + short int *data = (short int *) pdp_packet_data(x->x_packet0); + + unsigned int i; + int offset = x->x_needle; + int val; + unsigned int y; + float fh2 = (float)(h/2); + + if (!data) return; + + for (i=0; i<w; i++){ + y = (h/2) + (int)(fh2 * -x->x_buffer[(offset - w + i) & (BUFSIZE - 1)]); + if (y>=h) y = h-1; + + data[i + y*w] = 0x7fff; + } + + return; +} + +static void pdp_scope_sendpacket(t_pdp_scope *x) +{ + /* propagate if valid */ + pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet0); +} + + +static void pdp_scope_bang(t_pdp_scope *x) +{ + + int encoding; + + /* if we have an active packet, don't do anything */ + if (-1 != x->x_packet0) return; + + switch(x->x_pdp_image_type){ + + case PDP_IMAGE_YV12: + pdp_scope_createpacket_yv12(x); // don't create inside thread!!! + pdp_scope_generate_yv12(x); + pdp_scope_sendpacket(x); + //pdp_queue_add(x, pdp_scope_generate_yv12, pdp_scope_sendpacket, &x->x_queue_id); + break; + + case PDP_IMAGE_GREY: + pdp_scope_createpacket_grey(x); // don't create inside thread!!! + pdp_scope_generate_grey(x); + pdp_scope_sendpacket(x); + //pdp_queue_add(x, pdp_scope_generate_grey, pdp_scope_sendpacket, &x->x_queue_id); + break; + + default: + break; + + } + + + /* release the packet */ + +} + + +static void pdp_scope_dim(t_pdp_scope *x, t_floatarg w, t_floatarg h) +{ + if (w<32.0f) w = 32.0f; + if (h<32.0f) h = 32.0f; + + x->x_width = (unsigned int)w; + x->x_height = (unsigned int)h; +} + + +static void pdp_scope_free(t_pdp_scope *x) +{ + + /* remove callback from process queue */ + t_pdp_procqueue *q = pdp_queue_get_queue(); + pdp_procqueue_finish(q, x->x_queue_id); + + + /* tidy up */ + pdp_packet_mark_unused(x->x_packet0); + pdp_dealloc(x->x_data); + +} +static t_int *pdp_scope_perform(t_int *w) +{ + + + t_float *in = (float *)(w[3]); + t_pdp_scope *x = (t_pdp_scope *)(w[1]); + t_int n = (t_int)(w[2]); + t_int i; + + t_int offset = x->x_needle; + + for (i=0; i<n; i++) + x->x_buffer[(offset+i)&(BUFSIZE-1)] = in[i]; + + x->x_needle = (offset + n ) & (BUFSIZE - 1); + + return (w+4); + +} +static void pdp_scope_dsp(t_pdp_scope *x, t_signal **sp) +{ + dsp_add(pdp_scope_perform, 3, x, sp[0]->s_n, sp[0]->s_vec); + +} + +t_class *pdp_scope_class; + + + + +void *pdp_scope_new(void) +{ + int i; + + t_pdp_scope *x = (t_pdp_scope *)pd_new(pdp_scope_class); + + x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + + x->x_packet0 = -1; + x->x_queue_id = -1; + x->x_width = 320; + x->x_height = 240; + x->x_f = 0.0; + + x->x_data = (t_pdp_scope_data *)pdp_alloc(sizeof(t_pdp_scope_data)); + + pdp_scope_type(x, gensym("yv12")); + + x->x_buffer = (float *)pdp_alloc(sizeof(float) * BUFSIZE); + x->x_needle = 0; + + return (void *)x; +} + + + +#ifdef __cplusplus +extern "C" +{ +#endif + + + +void pdp_scope_setup(void) +{ + + + pdp_scope_class = class_new(gensym("pdp_scope~"), (t_newmethod)pdp_scope_new, + (t_method)pdp_scope_free, sizeof(t_pdp_scope), 0, A_NULL); + + CLASS_MAINSIGNALIN(pdp_scope_class, t_pdp_scope, x_f); + + class_addmethod(pdp_scope_class, (t_method)pdp_scope_type, gensym("type"), A_SYMBOL, A_NULL); + class_addmethod(pdp_scope_class, (t_method)pdp_scope_dim, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_scope_class, (t_method)pdp_scope_bang, gensym("bang"), A_NULL); + class_addmethod(pdp_scope_class, (t_method)pdp_scope_dsp, gensym("dsp"), 0); +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/matrix_basic/Makefile b/modules/matrix_basic/Makefile new file mode 100644 index 0000000..77094a1 --- /dev/null +++ b/modules/matrix_basic/Makefile @@ -0,0 +1,12 @@ +current: all_modules + +include ../../Makefile.config + +PDP_MOD = $(PDP_MATRIX_BASIC) + +all_modules: $(PDP_MOD) + +clean: + rm -f *~ + rm -f *.o + diff --git a/modules/matrix_basic/README b/modules/matrix_basic/README new file mode 100644 index 0000000..d6ece1b --- /dev/null +++ b/modules/matrix_basic/README @@ -0,0 +1,5 @@ +This directory contains "normal" matrix packet processors, +derived from the t_pdp_base class defined in pdp_base.h + +Most modules are wrappers around Gnu Scientific Library (gsl) calls + diff --git a/modules/matrix_basic/clusterstuff.c b/modules/matrix_basic/clusterstuff.c new file mode 100644 index 0000000..432a807 --- /dev/null +++ b/modules/matrix_basic/clusterstuff.c @@ -0,0 +1,540 @@ +/*
+ * Pure Data Packet module.
+ * Copyright (c) 2003 by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * 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.
+ *
+ */
+
+
+
+#include "pdp.h"
+#include "pdp_base.h"
+#include <math.h>
+
+struct _pdp_histo;
+typedef void (*t_histo_proc)(struct _pdp_histo *);
+
+
+/* the cluster struct */
+typedef struct _cluster
+{
+ float N;
+ float cx;
+ float cy;
+} t_cluster;
+
+
+
+typedef struct _pdp_histo
+{
+ t_object x_obj;
+ t_int x_logN;
+ t_symbol *x_array_sym;
+ t_float x_scale;
+ t_int x_debug;
+ t_int x_sample_size; /* pointcloud size */
+ t_int x_nb_clusters; /* nb of clusters */
+ t_cluster *x_cluster; /* cluster data (for tracking) */
+ t_histo_proc x_process_method; /* what to do with the histogram */
+ t_outlet *x_outlet0;
+ t_outlet *x_outlet1;
+
+ /* the packet */
+ int x_packet0;
+
+ /* packet data */
+ short int *x_data;
+ int x_width;
+ int x_height;
+ int x_nb_pixels;
+
+ /* histo data for processor: these are stored on the stack */
+ int *x_histo;
+ int *x_pixel_offset;
+
+} t_pdp_histo;
+
+
+// join 2 clusters. clear the second one
+static void cluster_join(t_cluster *cA, t_cluster *cB)
+{
+ float scale = 1.0f / (cA->N + cB->N);
+ cA->cx = (cA->N * cA->cx + cB->N * cB->cx) * scale;
+ cA->cy = (cA->N * cA->cy + cB->N * cB->cy) * scale;
+ cA->N += cB->N;
+
+ cB->N = 0.0f;
+}
+
+static void cluster_copy(t_cluster *cA, t_cluster *cB)
+{
+ cA->cx = cB->cx;
+ cA->cy = cB->cy;
+ cA->N = cB->N;
+}
+
+static void cluster_clear(t_cluster *c)
+{
+ c->N = 0.0f;
+}
+
+static void cluster_new(t_cluster *c, float x, float y)
+{
+ c->N = 1.0f;
+ c->cx = x;
+ c->cy = y;
+}
+
+static float cluster_dsquared(t_cluster *cA, t_cluster *cB)
+{
+ float dx = cA->cx - cB->cx;
+ float dy = cA->cy - cB->cy;
+ return dx*dx + dy*dy;
+}
+
+
+static int round_up_2log(int i)
+{
+ int l = 0;
+ i--;
+ while (i) {
+ i >>= 1;
+ l++;
+ }
+ //post("log is %d, 2^n is %d", l, 1 << l);
+
+ l = (l < 16) ? l : 15;
+ return l;
+}
+
+
+static void compute_clusters(t_pdp_histo *x)
+{
+ t_cluster c[x->x_sample_size];
+ int i;
+ float scalex = 1.0f / (float)(x->x_width);
+ float scaley = 1.0f / (float)(x->x_height);
+ int nb_clusters = x->x_sample_size;
+
+ /* build the cluster data struct */
+ for (i=0; i<x->x_sample_size; i++)
+ cluster_new(c+i,
+ ((float)(x->x_pixel_offset[i] % x->x_width)) * scalex,
+ ((float)(x->x_pixel_offset[i] / x->x_width)) * scaley);
+
+ /* the clustering loop */
+ while (nb_clusters > x->x_nb_clusters){
+ /* initialize cA, cB, d */
+ int cA=0;
+ int cB=1;
+ float d = cluster_dsquared(c+0, c+1);
+ int i,j;
+
+ /* find the closest 2 clusters:
+ scan the distance matrix above the diagonal */
+ for (i=2; i<nb_clusters; i++){
+ for (j=0; j<i; j++){
+ float dij = cluster_dsquared(c+i, c+j);
+ if (dij < d){
+ cA = j;
+ cB = i;
+ d = dij;
+ }
+ }
+ }
+
+ /* join the two clusters (cA < cB) */
+ cluster_join (c+cA, c+cB);
+
+ /* reduce the distance matrix by moving
+ the last element to the empty spot cB */
+ nb_clusters--;
+ cluster_copy (c+cB, c+nb_clusters);
+ }
+
+ /* copy cluster data */
+ if (!x->x_cluster){
+ int size = sizeof(t_cluster) * x->x_nb_clusters;
+ x->x_cluster = (t_cluster *)pdp_alloc(size);
+ memcpy(x->x_cluster, c, size);
+ }
+ /* or perform tracking */
+ else{
+ int i,j;
+ /* find best matches for the first couple of clusters */
+ for (i=0; i<x->x_nb_clusters - 1; i++){
+ int closest = 0;
+ float d_min = cluster_dsquared(x->x_cluster+i, c);
+
+ /* get closest cluster */
+ for (j=1; j<nb_clusters; j++){
+ float dj = cluster_dsquared(x->x_cluster+i, c+j);
+ if (dj < d_min){
+ closest = j;
+ d_min = dj;
+ }
+ }
+
+ /* replace reference cluster with closest match */
+ cluster_copy(x->x_cluster+i, c+closest);
+
+ /* shrink matrix (like above) */
+ nb_clusters--;
+ cluster_copy(c+closest, c+nb_clusters);
+
+ }
+ /* copy the last cluster */
+ cluster_copy(x->x_cluster + x->x_nb_clusters - 1, c);
+ }
+
+ /* print the clusters */
+ post("clusters:");
+ post("\tN\tcx\tcy");
+ for (i=0; i<x->x_nb_clusters; i++){
+ post("\t%d\t%0.2f\t%0.2f",
+ (int)x->x_cluster[i].N,
+ x->x_cluster[i].cx,
+ x->x_cluster[i].cy);
+ }
+
+
+
+}
+
+static void dump_to_array(t_pdp_histo *x)
+{
+ float *vec;
+ int nbpoints;
+ t_garray *a;
+ int i;
+ int *histo = x->x_histo;
+ int N = 1 << (x->x_logN);
+ float scale = 1.0f / (float)(x->x_nb_pixels);
+
+
+ /* dump to array if possible */
+ if (!x->x_array_sym){
+ }
+
+ /* check if array is valid */
+ else if (!(a = (t_garray *)pd_findbyclass(x->x_array_sym, garray_class))){
+ post("pdp_histo: %s: no such array", x->x_array_sym->s_name);
+ }
+ /* get data */
+ else if (!garray_getfloatarray(a, &nbpoints, &vec)){
+ post("pdp_histo: %s: bad template", x->x_array_sym->s_name);
+ }
+ /* scale and dump in array */
+ else{
+
+ N = (nbpoints < N) ? nbpoints : N;
+ for (i=0; i<N; i++) vec[i] = (float)(histo[i]) * scale * x->x_scale;
+ //garray_redraw(a);
+ }
+
+}
+
+static void get_sampleset(t_pdp_histo *x, int log_tmp_size, int threshold)
+{
+ int N = 1 << log_tmp_size;
+ int mask = N-1;
+ int index, nbpoints, i;
+ t_atom a[2];
+ float scalex = 1.0f / (float)(x->x_width);
+ float scaley = 1.0f / (float)(x->x_height);
+ t_symbol *s = gensym("list");
+
+ /* store the offsets of the points in a in an oversized array
+ the oversizing is to eliminate a division and to limit the
+ searching for a free location after a random index is generated */
+
+ int offset[N];
+
+ /* float versions of the coordinates */
+ float fx[x->x_sample_size];
+ float fy[x->x_sample_size];
+ float max_x, min_x, max_y, min_y;
+
+ /* reset the array */
+ memset(offset, -1, N * sizeof(int));
+
+ /* get the coordinates of the tempsize brightest points
+ and store them in a random location in the hash */
+ for (i=0; i<x->x_nb_pixels; i++){
+ if (x->x_data[i] >= threshold){
+ /* get a random index */
+ int ri = random();
+ //int ri = 0;
+ /* find an empty spot to store it */
+ while (-1 != offset[ri & mask]) ri++;
+ offset[ri & mask] = i;
+ }
+ }
+
+
+ /* repack the array to get the requested
+ sample size at the start */
+ index = 0;
+ nbpoints = 0;
+ while (nbpoints < x->x_sample_size){
+ while (-1 == offset[index]) index++; // ffwd to next nonepty slot
+ offset[nbpoints++] = offset[index++]; // move slot
+ }
+
+ /* mark output packet samples */
+ memset(x->x_data, 0, 2*x->x_nb_pixels);
+ for (i=0; i<x->x_sample_size; i++){
+ x->x_data[offset[i]] = 0x7fff;
+ }
+
+ /* send packet to left outlet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+
+
+ /* run the clustering algo */
+ x->x_pixel_offset = offset;
+ compute_clusters(x);
+
+
+}
+
+static void get_brightest(t_pdp_histo *x)
+{
+ int i;
+ int *histo = x->x_histo;
+ int N = 1 << (x->x_logN);
+
+ int index, nsamps;
+
+ /* check requested size */
+ if (x->x_sample_size > x->x_nb_pixels){
+ post("WARNING: more samples requested than pixels in image");
+ x->x_sample_size = x->x_nb_pixels;
+ }
+
+
+ /* find limiting index */
+ index = N;
+ nsamps = 0;
+ while (nsamps < x->x_sample_size){
+ index--;
+ nsamps += histo[index];
+ }
+
+ /* status report */
+ if (x->x_debug){
+ post("found %d samples between h[%d] and h[%d]", nsamps, index, N-1);
+ }
+
+ /* get a representative set from the candidates
+ the tempbuf is the rounded log of the nb of samples + 1
+ so it is at least 50% sparse */
+ get_sampleset(x, round_up_2log(nsamps) + 1, index << (15-x->x_logN));
+
+}
+
+
+static void _pdp_histo_perform(t_pdp_histo *x)
+{
+ short int *pp;
+ int N = 1 << x->x_logN;
+ int nbpixels = x->x_width * x->x_height, i;
+
+ int histo[N];
+
+ /* init */
+ for (i=0; i<N; i++) histo[i] = 0;
+
+ /* build histo */
+ for (i=0; i<nbpixels; i++){
+ int index = x->x_data[i] >> (15 - x->x_logN);
+ if (index < 0) index = 0; /* negative -> zero */
+ histo[index]++;
+ }
+
+ /* save the histo stack location */
+ x->x_histo = histo;
+
+ /* print it */
+ if (x->x_debug){
+ post("histogram:");
+ for (i=0; i<N; i++){
+ fprintf(stderr, "%d\t", histo[i]);
+ if (!(i % 10)) post("");
+ }
+ post("");
+ }
+
+ /* call the processor */
+ x->x_process_method(x);
+
+
+}
+
+
+// packet is an image/*/* packet or invalid */
+static void pdp_histo_perform(t_pdp_histo *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data(x->x_packet0);
+ if (!header0 || !data0) return;
+
+ x->x_width = header0->info.image.width;
+ x->x_height = header0->info.image.height;
+ x->x_nb_pixels = x->x_width * x->x_height;
+ x->x_data = data0;
+
+ _pdp_histo_perform(x);
+}
+
+
+
+static void pdp_histo_input_0(t_pdp_histo *x, t_symbol *s, t_floatarg f)
+{
+ int packet = (int)f;
+
+ /* register */
+ if (s == gensym("register_ro")){
+ /* replace if not compatible or we are not interpolating */
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = pdp_packet_convert_rw(packet, pdp_gensym("image/grey/*"));
+
+ }
+
+ if (s == gensym("process")){
+ pdp_histo_perform(x);
+ }
+
+}
+
+
+
+static void pdp_histo_samplesize(t_pdp_histo *x, t_floatarg f)
+{
+ int i = (int)f;
+ if (i >= x->x_nb_clusters ) x->x_sample_size = i;
+}
+
+static void pdp_histo_clusters(t_pdp_histo *x, t_floatarg f)
+{
+ int i = (int)f;
+ if (i>=2 && i<= x->x_sample_size){
+ x->x_nb_clusters = i;
+ if (x->x_cluster) pdp_dealloc(x->x_cluster);
+ x->x_cluster = 0;
+ }
+}
+static void pdp_histo_scale(t_pdp_histo *x, t_floatarg f){x->x_scale = f;}
+
+
+
+static void pdp_histo_size(t_pdp_histo *x, t_floatarg f)
+{
+ int i = (int)f;
+ if (i < 1) return;
+ x->x_logN = round_up_2log(i);
+}
+
+
+static void pdp_histo_array(t_pdp_histo *x, t_symbol *s)
+{
+ //post("setting symbol %x", s);
+ x->x_array_sym = s;
+}
+
+
+static void pdp_histo_free(t_pdp_histo *x)
+{
+ pdp_packet_mark_unused(x->x_packet0);
+ if (x->x_cluster) pdp_dealloc(x->x_cluster);
+}
+
+
+t_class *pdp_histo_class;
+
+
+
+void *pdp_histo_new(t_floatarg f)
+{
+
+ t_pdp_histo *x = (t_pdp_histo *)pd_new(pdp_histo_class);
+ if (f == 0.0f) f = 64;
+ pdp_histo_size(x, f);
+ x->x_packet0 = -1;
+ x->x_debug = 0;
+ x->x_sample_size = 16;
+ x->x_nb_clusters = 3;
+ x->x_cluster = 0;
+ return (void *)x;
+}
+
+
+void *pdp_histo_array_new(t_symbol *s, t_float f, t_float f2)
+{
+ t_pdp_histo *x = (t_pdp_histo *)pdp_histo_new(f);
+ if (f2 == 0.0f) f2 = 1.0f;
+ pdp_histo_scale(x, f2);
+ pdp_histo_array(x, s);
+ x->x_process_method = dump_to_array;
+ return (void *)x;
+}
+
+void *pdp_histo_sample_new(t_float nbsamples, t_float histosize)
+{
+ t_pdp_histo *x;
+ if (histosize == 0.0f) histosize = 256.0f;
+ x = (t_pdp_histo *)pdp_histo_new(histosize);
+ if (nbsamples == 0.0f) nbsamples = 16.0f;
+ pdp_histo_samplesize(x, nbsamples);
+ x->x_process_method = get_brightest;
+ x->x_outlet0 = outlet_new(&x->x_obj, gensym("anything"));
+ //x->x_outlet1 = outlet_new(&x->x_obj, gensym("anything"));
+
+ inlet_new((t_object *)x, (t_pd *)&x->x_obj, gensym("float"), gensym("nbpoints"));
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_histo_setup(void)
+{
+
+ pdp_histo_class = class_new(gensym("pdp_histo"), (t_newmethod)pdp_histo_array_new,
+ (t_method)pdp_histo_free, sizeof(t_pdp_histo), 0, A_DEFSYMBOL, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+
+ class_addcreator((t_newmethod)pdp_histo_sample_new, gensym("pdp_pointcloud"), A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_histo_class, (t_method)pdp_histo_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_histo_class, (t_method)pdp_histo_size, gensym("size"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_histo_class, (t_method)pdp_histo_size, gensym("scale"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_histo_class, (t_method)pdp_histo_array, gensym("array"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_histo_class, (t_method)pdp_histo_samplesize, gensym("nbpoints"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_histo_class, (t_method)pdp_histo_clusters, gensym("nbclusters"), A_FLOAT, A_NULL);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/modules/matrix_basic/pdp_mat_lu.c b/modules/matrix_basic/pdp_mat_lu.c new file mode 100644 index 0000000..af8931d --- /dev/null +++ b/modules/matrix_basic/pdp_mat_lu.c @@ -0,0 +1,143 @@ +/* + * Pure Data Packet module. LU decomposition module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +//#include <gsl/gsl_block.h> +//#include <gsl/gsl_vector.h> +//#include <gsl/gsl_matrix.h> +//#include <gsl/gsl_blas.h> +#include "pdp.h" +#include "pdp_base.h" + + +typedef struct pdp_mat_LU_struct +{ + t_pdp_base x_base; + +} t_pdp_mat_LU; + + + +static void pdp_mat_LU_process_LU_inverse(t_pdp_mat_LU *x) +{ + int p = pdp_base_get_packet(x, 0); + int p_LU = pdp_packet_matrix_LU_to_inverse(p); + pdp_base_set_packet(x, 0, p_LU); // replace packet +} + +static void pdp_mat_LU_process_LU(t_pdp_mat_LU *x) +{ + int p = pdp_base_get_packet(x, 0); + int p_LU = pdp_packet_matrix_LU(p); + pdp_base_set_packet(x, 0, p_LU); // replace packet +} + +static void pdp_mat_LU_process_LU_solve(t_pdp_mat_LU *x) +{ + int p0 = pdp_base_get_packet(x, 0); + int p1 = pdp_base_get_packet(x, 1); + int pvr, pm, pv; + + /* determine which is vector and which is matrix */ + if (pdp_packet_matrix_ismatrix(p0) && pdp_packet_matrix_isvector(p1)){ + pm = p0; + pv = p1; + } + else { + pm = p1; + pv = p0; + } + + /* create the result vector */ + pvr = pdp_packet_matrix_LU_solve(pm, pv); + + /* replace the active packet */ + pdp_base_set_packet(x, 0, pvr); +} + +static void pdp_mat_LU_free(t_pdp_mat_LU *x) +{ + /* remove process method from queue before deleting data */ + pdp_base_free(x); +} + +t_class *pdp_mat_LU_class; + + +/* common new methods */ +t_pdp_mat_LU *pdp_mat_LU_base_new(void) +{ + t_pdp_mat_LU *x = (t_pdp_mat_LU *)pd_new(pdp_mat_LU_class); + pdp_base_init(x); + pdp_base_add_pdp_outlet(x); + return x; +} + +void *pdp_mat_LU_inverse_new(void) +{ + t_pdp_mat_LU *x = pdp_mat_LU_base_new(); + pdp_base_set_process_method(x,(t_pdp_method)pdp_mat_LU_process_LU_inverse); + pdp_base_readonly_active_inlet(x); + return (void *)x; +} + + +void *pdp_mat_LU_new(void) +{ + t_pdp_mat_LU *x = pdp_mat_LU_base_new(); + pdp_base_set_process_method(x,(t_pdp_method)pdp_mat_LU_process_LU); + pdp_base_readonly_active_inlet(x); + return (void *)x; +} + +void *pdp_mat_LU_solve_new(void) +{ + t_pdp_mat_LU *x = pdp_mat_LU_base_new(); + pdp_base_set_process_method(x,(t_pdp_method)pdp_mat_LU_process_LU_solve); + pdp_base_readonly_active_inlet(x); + pdp_base_add_pdp_inlet(x); + return (void *)x; +} + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_mat_lu_setup(void) +{ + + + pdp_mat_LU_class = class_new(gensym("pdp_m_LU_inverse"), (t_newmethod)pdp_mat_LU_inverse_new, + (t_method)pdp_mat_LU_free, sizeof(t_pdp_mat_LU), 0, A_NULL); + + pdp_base_setup(pdp_mat_LU_class); + + + class_addcreator((t_newmethod)pdp_mat_LU_new, gensym("pdp_m_LU"), A_NULL); + class_addcreator((t_newmethod)pdp_mat_LU_solve_new, gensym("pdp_m_LU_solve"), A_NULL); + + + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/matrix_basic/pdp_mat_mul.c b/modules/matrix_basic/pdp_mat_mul.c new file mode 100644 index 0000000..329813f --- /dev/null +++ b/modules/matrix_basic/pdp_mat_mul.c @@ -0,0 +1,308 @@ +/* + * Pure Data Packet module. Matrix multiplication module + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +//#include <gsl/gsl_block.h> +//#include <gsl/gsl_vector.h> +//#include <gsl/gsl_matrix.h> +//#include <gsl/gsl_blas.h> +#include "pdp.h" +#include "pdp_base.h" + + +typedef struct pdp_mat_mm_struct +{ + t_pdp_base x_base; + CBLAS_TRANSPOSE_t x_T0; + CBLAS_TRANSPOSE_t x_T1; + int x_M0; + int x_M1; + + float x_scale_r; + float x_scale_i; + +} t_pdp_mat_mm; + + +static void pdp_mat_mm_rscale(t_pdp_mat_mm *x, t_floatarg r) +{ + x->x_scale_r = r; + x->x_scale_i = 0.0f; +} + +static void pdp_mat_mm_cscale(t_pdp_mat_mm *x, t_floatarg r, t_floatarg i) +{ + x->x_scale_r = r; + x->x_scale_i = i; +} + + +/* matrix multilpy */ +static void pdp_mat_mv_process_mul(t_pdp_mat_mm *x) +{ + int pA = pdp_base_get_packet(x, 0); + int pB = pdp_base_get_packet(x, 1); + int p0, p1, pR; + + /* determine which one is the vector */ + if (pdp_packet_matrix_isvector(pA)){ + p0 = pB; + p1 = pA; + } + else { + p1 = pB; + p0 = pA; + } + + pR = pdp_packet_new_matrix_product_result(x->x_T0, CblasNoTrans, p0, p1); + + if (-1 != pR){ + pdp_packet_matrix_setzero(pR); + if (pdp_packet_matrix_blas_mv(x->x_T0, p0, p1, pR, x->x_scale_r, x->x_scale_i)){ + //post("pdp_packet_matrix_blas_mm failed"); + pdp_packet_mark_unused(pR); + pR = -1; + } + } + else { + //post("pdp_packet_new_matrix_product_result failed"); + } + + /* replace with result */ + pdp_base_set_packet(x, 0, pR); + +} + +/* matrix vector multilpy */ +static void pdp_mat_mm_process_mul(t_pdp_mat_mm *x) +{ + int pA = pdp_base_get_packet(x, 0); + int pB = pdp_base_get_packet(x, 1); + int p0, p1, pR; + + p0 = (x->x_M0) ? pB : pA; + p1 = (x->x_M1) ? pB : pA; + + pR = pdp_packet_new_matrix_product_result(x->x_T0, x->x_T1, p0, p1); + + if (-1 != pR){ + pdp_packet_matrix_setzero(pR); + if (pdp_packet_matrix_blas_mm(x->x_T0, x->x_T1, p0, p1, pR, x->x_scale_r, x->x_scale_i)){ + //post("pdp_packet_matrix_blas_mm failed"); + pdp_packet_mark_unused(pR); + pR = -1; + } + } + else { + //post("pdp_packet_new_matrix_product_result failed"); + } + + /* replace with result */ + pdp_base_set_packet(x, 0, pR); + +} +/* matrix macc */ +static void pdp_mat_mm_process_mac(t_pdp_mat_mm *x) +{ + int pC = pdp_base_get_packet(x, 0); + int pA = pdp_base_get_packet(x, 1); + int pB = pdp_base_get_packet(x, 2); + int p0, p1; + + p0 = (x->x_M0) ? pB : pA; + p1 = (x->x_M1) ? pB : pA; + + if (pdp_packet_matrix_blas_mm(x->x_T0, x->x_T1, p0, p1, pC, x->x_scale_r, x->x_scale_i)){ + //post("pdp_packet_matrix_blas_mm failed"); + pdp_base_set_packet(x, 0, -1); // delete packet + } + +} + + +static void pdp_mat_mm_free(t_pdp_mat_mm *x) +{ + /* remove process method from queue before deleting data */ + pdp_base_free(x); +} + +t_class *pdp_mat_mm_class; + + +/* common new method */ +void *pdp_mat_mm_new(void) +{ + int i; + t_pdp_mat_mm *x = (t_pdp_mat_mm *)pd_new(pdp_mat_mm_class); + + /* super init */ + pdp_base_init(x); + + /* outlet */ + pdp_base_add_pdp_outlet(x); + + + return (void *)x; +} + + +static int pdp_mat_mm_setup_routing_M0(t_pdp_mat_mm *x, t_symbol *s0) +{ + if ('A' == s0->s_name[0]){x->x_M0 = 0;} else if ('B' == s0->s_name[0]) {x->x_M0 = 1;} else return 0; + + if ((gensym("A") == s0) || (gensym("B") == s0)) x->x_T0 = CblasNoTrans; + else if ((gensym("A^T") == s0) || (gensym("B^T") == s0)) x->x_T0 = CblasConjTrans; + else if ((gensym("A^H") == s0) || (gensym("B^H") == s0)) x->x_T0 = CblasConjTrans; + else return 0; + + return 1; +} + +static int pdp_mat_mm_setup_routing_M1(t_pdp_mat_mm *x, t_symbol *s1) +{ + + if ('A' == s1->s_name[0]){x->x_M1 = 0;} else if ('B' == s1->s_name[0]) {x->x_M1 = 1;} else return 0; + + /* setup second matrix transpose operation */ + if ((gensym("A") == s1) || (gensym("B") == s1)) x->x_T1 = CblasNoTrans; + else if ((gensym("A^T") == s1) || (gensym("B^T") == s1)) x->x_T1 = CblasConjTrans; + else if ((gensym("A^H") == s1) || (gensym("B^H") == s1)) x->x_T1 = CblasConjTrans; + else return 0; + + return 1; +} + + +static int pdp_mat_mm_setup_scaling(t_pdp_mat_mm *x, t_symbol *scale) +{ + int success = 1; + + /* setup scaling inlet */ + if ((gensym ("rscale") == scale) || (gensym("r") == scale)){ + pdp_base_add_gen_inlet(x, gensym("float"), gensym("rscale")); + } + else if ((gensym ("cscale") == scale) || (gensym("c") == scale)){ + pdp_base_add_gen_inlet(x, gensym("list"), gensym("cscale")); + } + else if (gensym ("") != scale) success = 0; + + return success; +} + +void *pdp_mat_mm_new_mul_common(t_symbol *s0, t_symbol *s1, t_symbol *scale, int ein) +{ + t_pdp_mat_mm *x = pdp_mat_mm_new(); + + /* add extra pdp inlets */ + while (ein--) pdp_base_add_pdp_inlet(x); + + /* setup routing */ + if (!pdp_mat_mm_setup_routing_M0(x, s0)) goto error; + if (!pdp_mat_mm_setup_routing_M1(x, s1)) goto error; + if (!pdp_mat_mm_setup_scaling(x, scale)) goto error; + + /* default scale = 1 */ + pdp_mat_mm_cscale(x, 1.0f, 0.0f); + return (void *)x; + + error: + pd_free((void *)x); + return 0; +} + +void *pdp_mat_mv_new_mul_common(t_symbol *s0, t_symbol *scale, int ein) +{ + t_pdp_mat_mm *x = pdp_mat_mm_new(); + + /* add extra pdp inlets */ + while (ein--) pdp_base_add_pdp_inlet(x); + + /* setup routing */ + if (!pdp_mat_mm_setup_routing_M0(x, s0)) goto error; + if (!pdp_mat_mm_setup_scaling(x, scale)) goto error; + + /* default scale = 1 */ + pdp_mat_mm_cscale(x, 1.0f, 0.0f); + return (void *)x; + + error: + pd_free((void *)x); + return 0; +} + +void *pdp_mat_mm_new_mul(t_symbol *s0, t_symbol *s1, t_symbol *scale) +{ + t_pdp_mat_mm *x = pdp_mat_mm_new_mul_common(s0, s1, scale, 1); + if(x){ + pdp_base_set_process_method(x, (t_pdp_method)pdp_mat_mm_process_mul); + pdp_base_readonly_active_inlet(x); + } + return x; +} + +void *pdp_mat_mv_new_mul(t_symbol *s0, t_symbol *scale) +{ + t_pdp_mat_mm *x = pdp_mat_mv_new_mul_common(s0, scale, 1); + if(x){ + pdp_base_set_process_method(x, (t_pdp_method)pdp_mat_mv_process_mul); + pdp_base_readonly_active_inlet(x); + } + return x; +} + +void *pdp_mat_mm_new_mac(t_symbol *s0, t_symbol *s1, t_symbol *scale) +{ + t_pdp_mat_mm *x = pdp_mat_mm_new_mul_common(s0, s1, scale, 2); + if (x){ + pdp_base_set_process_method(x, (t_pdp_method)pdp_mat_mm_process_mac); + } + return x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_mat_mul_setup(void) +{ + + + pdp_mat_mm_class = class_new(gensym("pdp_m_mm"), (t_newmethod)pdp_mat_mm_new_mul, + (t_method)pdp_mat_mm_free, sizeof(t_pdp_mat_mm), 0, A_SYMBOL, A_SYMBOL, A_DEFSYMBOL, A_NULL); + + pdp_base_setup(pdp_mat_mm_class); + + class_addcreator((t_newmethod)pdp_mat_mm_new_mac, gensym("pdp_m_+=mm"), + A_SYMBOL, A_SYMBOL, A_DEFSYMBOL, A_NULL); + + class_addcreator((t_newmethod)pdp_mat_mv_new_mul, gensym("pdp_m_mv"), + A_SYMBOL, A_DEFSYMBOL, A_NULL); + + + class_addmethod(pdp_mat_mm_class, (t_method)pdp_mat_mm_rscale, gensym("rscale"), A_FLOAT, A_NULL); + class_addmethod(pdp_mat_mm_class, (t_method)pdp_mat_mm_cscale, gensym("cscale"), A_FLOAT, A_FLOAT, A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/matrix_basic/pdp_mat_vec.c b/modules/matrix_basic/pdp_mat_vec.c new file mode 100644 index 0000000..16257c8 --- /dev/null +++ b/modules/matrix_basic/pdp_mat_vec.c @@ -0,0 +1,213 @@ +/* + * Pure Data Packet module. Vector modules. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +//#include <gsl/gsl_block.h> +//#include <gsl/gsl_vector.h> +//#include <gsl/gsl_matrix.h> +//#include <gsl/gsl_blas.h> +#include "pdp.h" +#include "pdp_base.h" + + +typedef struct pdp_mat_vec_struct +{ + t_pdp_base x_base; + int x_type; + t_outlet *x_out; + int x_accept_list; + int x_list_size; + t_atom *x_list; + +} t_pdp_mat_vec; + + +#define GETFLOAT(x) ((x)->a_type == A_FLOAT ? (x)->a_w.w_float : 0.0f) +#define GETDOUBLE(x) (double)GETFLOAT(x) + + +static void pdp_mat_vec_list_in(t_pdp_mat_vec *x, t_symbol *s, int argc, t_atom *argv) +{ + int i; + int vp = -1; + int f; + int dim = argc; + + if (!x->x_accept_list) return; //check if this handler is enabled + if (!argc) return; //reject empty list + + switch(x->x_type){ + case PDP_MATRIX_TYPE_CFLOAT: + if (argc & 1) return; //reject odd nb elements + dim >>= 1; //halve dimension + case PDP_MATRIX_TYPE_RFLOAT: + vp = pdp_packet_new_matrix(dim, 1, x->x_type); + if (-1 != vp){ + float *data = (float *)pdp_packet_data(vp); + for (i=0; i<argc; i++) data[i] = GETFLOAT(&argv[i]); + } + break; + case PDP_MATRIX_TYPE_CDOUBLE: + if (argc & 1) return; //reject odd nb elements + dim >>= 1; //halve dimension + case PDP_MATRIX_TYPE_RDOUBLE: + vp = pdp_packet_new_matrix(dim, 1, x->x_type); + if (-1 != vp){ + double *data = (double *)pdp_packet_data(vp); + for (i=0; i<argc; i++) data[i] = GETDOUBLE(&argv[i]); + } + break; + default: + break; + } + + if (-1 != vp){ + /* store vector packet */ + pdp_base_set_packet(x, 0, vp); + pdp_base_bang(x); + } +} + +static void pdp_mat_vec_list_out(t_pdp_mat_vec *x) +{ + int p = pdp_base_move_packet(x, 0); + int type = pdp_packet_matrix_get_type(p); + int outlist_size; + float *fdata = 0; + double *ddata = 0; + int i; + + /* check if it's a vector */ + gsl_vector *m = (gsl_vector *)pdp_packet_matrix_get_gsl_vector(p, type); + if (!pdp_packet_matrix_isvector(p)) return; + + /* get list size */ + outlist_size = m->size; + if ((type == PDP_MATRIX_TYPE_CFLOAT) + || (type == PDP_MATRIX_TYPE_CDOUBLE)) + outlist_size <<= 1; + + /* realloc list if necessary */ + if (outlist_size > x->x_list_size){ + free(x->x_list); + x->x_list = (t_atom *)pdp_alloc(sizeof(t_atom) * outlist_size); + x->x_list_size = outlist_size; + } + + /* copy data */ + switch(type){ + case PDP_MATRIX_TYPE_RFLOAT: + case PDP_MATRIX_TYPE_CFLOAT: + fdata = (float *)pdp_packet_data(p); + for (i=0; i<outlist_size; i++) + SETFLOAT(&x->x_list[i], fdata[i]); + break; + + case PDP_MATRIX_TYPE_RDOUBLE: + case PDP_MATRIX_TYPE_CDOUBLE: + ddata = (double *)pdp_packet_data(p); + for (i=0; i<outlist_size; i++) + SETFLOAT(&x->x_list[i], (float)ddata[i]); + break; + + } + + /* dispose of vector packet and output list */ + pdp_packet_mark_unused(p); + outlet_list(x->x_out, &s_list, outlist_size, x->x_list); +} + +static void pdp_mat_vec_free(t_pdp_mat_vec *x) +{ + /* remove process method from queue before deleting data */ + pdp_base_free(x); + + /* delete list */ + if (x->x_list) pdp_dealloc (x->x_list); +} + +t_class *pdp_mat_vec_class; + + +/* common new methods */ +t_pdp_mat_vec *pdp_mat_vec_base_new(void) +{ + t_pdp_mat_vec *x = (t_pdp_mat_vec *)pd_new(pdp_mat_vec_class); + pdp_base_init(x); + x->x_type = PDP_MATRIX_TYPE_CFLOAT; + x->x_accept_list = 0; + x->x_list_size = 0; + x->x_list = 0; + return x; +} + +void *pdp_mat_vec_list2vec_new(t_symbol *type) +{ + t_pdp_mat_vec *x = pdp_mat_vec_base_new(); + pdp_base_disable_active_inlet(x); + pdp_base_add_pdp_outlet(x); + x->x_accept_list = 1; + if ((gensym ("") == type) || (gensym ("double/real") == type)) x->x_type = PDP_MATRIX_TYPE_RDOUBLE; + else if (gensym ("double/complex") == type) x->x_type = PDP_MATRIX_TYPE_CDOUBLE; + else if (gensym ("float/real") == type) x->x_type = PDP_MATRIX_TYPE_RFLOAT; + else if (gensym ("float/complex") == type) x->x_type = PDP_MATRIX_TYPE_CFLOAT; + else { + pd_free((t_pd *)x); + x = 0; + } + return (void *)x; +} + + +void *pdp_mat_vec_vec2list_new(t_symbol *type) +{ + t_pdp_mat_vec *x = pdp_mat_vec_base_new(); + x->x_out = outlet_new((t_object *)x, &s_anything); + pdp_base_set_postproc_method(x,(t_pdp_method)pdp_mat_vec_list_out); + pdp_base_readonly_active_inlet(x); + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_mat_vec_setup(void) +{ + + + pdp_mat_vec_class = class_new(gensym("pdp_m_list2vec"), (t_newmethod)pdp_mat_vec_list2vec_new, + (t_method)pdp_mat_vec_free, sizeof(t_pdp_mat_vec), 0, A_DEFSYMBOL, A_NULL); + + pdp_base_setup(pdp_mat_vec_class); + + + class_addcreator((t_newmethod)pdp_mat_vec_vec2list_new, gensym("pdp_m_vec2list"), A_NULL); + + class_addlist(pdp_mat_vec_class, (t_method)pdp_mat_vec_list_in); + + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/test/Makefile b/modules/test/Makefile new file mode 100644 index 0000000..12819a3 --- /dev/null +++ b/modules/test/Makefile @@ -0,0 +1,13 @@ +#current: all_modules +current: clean +include ../../Makefile.config + +all_modules: pdp_forthtest.o + +# build test modules +# all_modules: $(PDP_MOD) + +clean: + rm -f *~ + rm -f *.o + diff --git a/modules/test/README b/modules/test/README new file mode 100644 index 0000000..eb35faa --- /dev/null +++ b/modules/test/README @@ -0,0 +1 @@ +This directory contains test modules. diff --git a/modules/test/pdp_dpd_test.c b/modules/test/pdp_dpd_test.c new file mode 100644 index 0000000..1d85bde --- /dev/null +++ b/modules/test/pdp_dpd_test.c @@ -0,0 +1,104 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_dpd_base.h" + +typedef struct pdp_dpd_test_struct +{ + t_pdp_dpd_base x_base; + +} t_pdp_dpd_test; + + + +/* outlet methods */ +static void pdp_dpd_test_1(t_pdp_dpd_test *x){post("%x: one", x);} +static void pdp_dpd_test_2(t_pdp_dpd_test *x){post("%x: two", x);} +static void pdp_dpd_test_3(t_pdp_dpd_test *x){post("%x: three", x);} +static void pdp_dpd_test_cleanup(t_pdp_dpd_test *x){post("%x: cleanup", x);} +static void pdp_dpd_test_inspect(t_pdp_dpd_test *x){post("%x: inspect", x);} + + + +static void pdp_dpd_test_bang(t_pdp_dpd_test *x) +{ + /* store a dummy packet */ + pdp_dpd_base_set_context_packet(x, pdp_packet_new(PDP_IMAGE, 4096)); + + /* bang base */ + pdp_dpd_base_bang(x); +} + + +static void pdp_dpd_test_free(t_pdp_dpd_test *x) +{ + pdp_dpd_base_free(x); + +} + +t_class *pdp_dpd_test_class; + + +void *pdp_dpd_test_new(void) +{ + /* allocate */ + t_pdp_dpd_test *x = (t_pdp_dpd_test *)pd_new(pdp_dpd_test_class); + + /* init super: this is mandatory */ + pdp_dpd_base_init(x); + + /* set the dpd processing methods & outlets */ + pdp_dpd_base_add_outlet(x, (t_pdp_method)pdp_dpd_test_1); + pdp_dpd_base_add_outlet(x, (t_pdp_method)pdp_dpd_test_2); + pdp_dpd_base_add_outlet(x, (t_pdp_method)pdp_dpd_test_3); + + pdp_dpd_base_add_cleanup(x, (t_pdp_method)pdp_dpd_test_cleanup); + pdp_dpd_base_add_inspector(x, (t_pdp_method)pdp_dpd_test_inspect); + + return (void *)x; +} + + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_dpd_test_setup(void) +{ + /* create a standard pd class */ + pdp_dpd_test_class = class_new(gensym("pdp_dpd_test"), (t_newmethod)pdp_dpd_test_new, + (t_method)pdp_dpd_test_free, sizeof(t_pdp_dpd_test), 0, A_NULL); + + /* inherit pdp base class methods */ + pdp_dpd_base_setup(pdp_dpd_test_class); + + /* add bang method */ + class_addbang(pdp_dpd_test_class, pdp_dpd_test_bang); +} + +#ifdef __cplusplus +} +#endif diff --git a/opengl/Makefile b/opengl/Makefile new file mode 100644 index 0000000..d62358e --- /dev/null +++ b/opengl/Makefile @@ -0,0 +1,27 @@ +include Makefile.config + +all: $(TARGET) + +linux: pdp_opengl.pd_linux + +darwin: pdp_opengl.pd_darwin + +subdirs: + make -C system + make -C modules + make -C include + +clean: + make -C system clean + make -C modules clean + make -C include clean + rm -f pdp_opengl.pd_linux + rm -f *~ + +pdp_opengl.pd_linux: subdirs + rm -f pdp_opengl.pd_linux + $(CC) -export_dynamic -shared -o pdp_opengl.pd_linux modules/*.o system/*.o $(LDFLAGS) -g + +pdp_opengl.pd_darwin: subdirs + rm -f pdp_opengl.pd_linux + $(CC) -o pdp_opengl.pd_pd_darwin modules/*.o system/*.o $(LDFLAGS) -g -bundle -bundle_loader $(PD_EXECUTABLE) diff --git a/opengl/Makefile.config b/opengl/Makefile.config new file mode 100644 index 0000000..4e59a4c --- /dev/null +++ b/opengl/Makefile.config @@ -0,0 +1,25 @@ +PD_DIR = /home/tom/pd/distro/pd/src +PDP_DIR = /home/tom/pd/packet/include +PDP_OGL_DIR = /home/tom/pd/packet/opengl/include + + + +CFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer -ffast-math \ + -Wall -W -Wstrict-prototypes -Werror \ + -Wno-unused -Wno-parentheses -Wno-switch -g + +CPPFLAGS = -I$(PD_DIR) -I$(PDP_DIR) -I$(PDP_OGL_DIR) -I/usr/X11R6/include +LDFLAGS = -lGL -lglut + +TARGET=linux + +#uncomment these for darwin: +#TARGET=darwin +#CPPFLAGS+=-I/sw/include +#PD_EXECUTABLE=/usr/local/bin/pd +#LDFLAGS = -lGL -lGLU -lglut -lX11 -L/sw/lib -L/usr/X11R6/lib + + + +.c.o: + $(CC) $(CFLAGS) $(CPPFLAGS) -o $*.o -c $*.c diff --git a/opengl/README b/opengl/README new file mode 100644 index 0000000..2e06708 --- /dev/null +++ b/opengl/README @@ -0,0 +1,248 @@ +pdp_opengl (3dp): opengl extensions for pdp +warning: this is still experimental and incomplete + +this library extends pdp with texture and render context packets, +to use some of the power of current video hardware. + +it is very much like gem (sort of a redesign, filled with my own +idiosyncrasies). gem, like it is now, is not very suited for interaction +with pdp image processing because of its hardcoded window centric rendering, +so i thought i'd write some gem like stuff on top of pdp myself. (3dp right +now only supports window centric rendering itself, but adding pbuffer +or pixmap rendering is easy enough, though it requires a rather new glx +library) + +so, 3dp is an experimental gem clone with tight pdp integration. unless +you like experiments, use gem, since it is better supported, has more +features and runs on linux, windows and mac osx. + +requires glx (opengl on x window). + +building: + +edit Makefile.config to reflect your system and run make. the library is +pdp_opengl.pd_linux + +some of the examples use the abstractions in opengl/abstractions. best to +add this to your pd path. + + +there are some fatal X bugs floating around, so be careful with resizing +windows and closing patches. there are a lot of other, non-fatal bugs +or badly implemented features. if you have remarks, just let me know. + + +i'll move to autoconf once i no longer consider it experimental. + + +TIPS & TRICKS + + +* the 3dp_windowcontext creates a window to draw in. the window packet +will be be output to the left outlet when a bang is received. control +flow for context is right to left, this means if a 3dp object has 2 +context outlets, the rightmost will be propagated before the leftmost. +there is no fanout. all operations are accumulative, including the +geometric transformations. if you need to branch use a 3dp_push object. + + +* geometric transformations can be done using the 3dp_view object. +the first argument is the kind of transformation: scale, scalex, +scaley, scalez, rotx, roty, rotz, rota, transx, transy, transz, +transxyz. + +repectively this scales the object, the x, y, z axis, rotates +around the x, y, z axis, rotates around an arbitrary axis, translates +in the x, y, z directions and translates along a vector. the initial +parameters can be specified as creation arguments, i.e.: + +[3dp_view rota 1 1 1 90] rotates by 90 degrees around axis (1,1,1). + + +* some simple objects can be drawn using the pdp_draw object. the +first argument is the object: square, cube, sphere, torus, cone, +teapot, dodeca, icosa, octa, tetra. prepending the names with a w +draws the wireframe version. (i.e. wcube is a wireframe cube). the +first inlet of the object is a texture inlet. not all objects support +this, but cube, square and sphere do. other inlets set some parameters +like size, nb of segments for sphere, etc.. they can be specified +by creation arguments too. + + +* saving a (matrix) state can be accomplished by the 3dp_push object. +the default matrix is the modelview matrix. it works as follows: both +the right and the left outlet propagate the same matrix state as the +input. so in short you can use 3dp_push to split your rendering tree +into parallel branches. the matrix types that can be pushed are: +modelview, texture, color, projection. + +* setting a current matrix can be done using the 3dp_mode object. +i.e. [3dp_mode texture] will map all geometric transforms to the +texture matrix, for texture coordinate animation. the left outlet +restores the current matrix back to the modelview matrix. + +* it is possible to send a render context trough a drawing/view +transforming object multiple times. the easy way is to use 3dp_for, +but other ways are legal too. this can be done to draw different +versions of the same object. have a look at example01 how this can +be done. + +it is also possible to send multiple render contexts trought the same +rendering tree (i.e. multiple windows). if you use different viewing +transformations on the top of the rendering chain, you can view a scene +trough different angles. + + +* light sources can be introduces using 3dp_light. they can be moved +with oridinary 3dp_view objects. + + +* 3dp_color changes the current color. right outlet is new color, +left outlet is the previous color. + +* 3dp_toggle toggles a boolean opengl switch. enabled now are: +depth_test, blend_add, blend_mix. more to come later. + + + +* couping 3dp and pdp can be done using 3dp_snap and pdp_convert. +the correct way to do it is to put 3dp_snap in a rendering +chain and give it arguments like this: + +[3dp_snap image/*/* 320 240] + +if you specify the subtype to be image/multi/*, the packet +will not be colour space converted: it will stay rgb. +if you want to make a snapshot to store as a high quality +png image, snap to bitmap/rgb/* and store it in pdp_reg to save. +to convert an image back to a texture, use + +[pdp_convert texture/*/*] + +if you snap to a texture (which is the default) +the dimensions don't need to be specified. a texture will be +allocated that can contain the entire screen. this is because +texture coordinates are relative and data is always interpolated. + +snapping only works correctly when the window is not covered +by other windows. + + +* textures can have any dimensions, but only those which have +dimensions that are integral powers of two will be tiled correctly. +i.e. by using pdp_mode to change to texture mode and doing some +coordinate transforms using pdp_view (see example06: this +uses a tilable animated cellular automata texture) + + +* multipass rendering is supported trough the objects +3dp_subcontext, "3dp_draw clear" and "3dp_view reset". the idea +is as follows: before rendering the final scene, you use +(a part of) the drawing buffer to render some things and store +them in a texture to be used in your final drawing pass. have +a look at examples 11, 12 and 13. in theory you could build a +"texture processing" framework on top of 3dp, by using the window +buffer as an accumulator and using textures as auxilary registers, +and drawing your final texture result using i.e. +3dp_display_texture. while this can be much faster than ordinary +pdp image processing, it also requires you to do more bookkeping +yourself, since you can only use a "serial" approach because +you can't modify textures directly, only trough the use of the +render buffer. + + +* 3dp has it's own thread, which is enabled by default. you +can enable/disable this by sending a "3dthread 0/1" message +to pdp_control. in most cases there's no reason to disable +the thread processing, except when you are doing a lot of +pdp<->3dp conversions. in that case the delay introduced by +the thread processing might become problematic. (the same +goes for pdp btw. feedback and threads don't mix too well). +it's a tradeoff. thread processing gives priority to the audio, +so you can obtain low latency, and you don't have to care +about locking up pd by doing too much processing. (instead +frames will be dropped). the drawback is of course that video +timing becomes unpredictable because it is governed by the system +scheduler. so sometimes it can be useful to disable threads +and increase the audio latency, so you can have snappy audio +and video at the same time. getting this to work well usually +requires some experimenting. + + +* if you have an nvidia card, you can set the environment +variable __GL_SYNC_TO_VBLANK to 1 to prevent tearing, until +3dp has default support for it. i.e.: + +export __GL_SYNC_TO_VBLANK=1 + + + +enjoy, + +tom + + + + +--- +some political ranting: gem vs. pdp/3dp + +first a disclaimer. i'm not into dissing people. i respect and appreciate +all the work that has gone into gem, but at the same time i'm not too happy +with what gem has become. not so much the functionality, but the way it is +built. the original design as a 3d processing extension is not flexible enough +to incorporate what's in there now and what could be added in the future.. + +instead of complaining about it, i decided to be pragmatic and write something +from scratch. i think, sometimes this has to be done. for me writing pdp/3dp +has been an extremely interesting learning experience. i think i understand +the trade-offs better now, and i know now it's not too easy to get it all +to work. maybe these remarks can be useful... + +opengl is not a pure dataflow language. it operates on a global machine +state next to the obvious drawing buffer that is passed around. +representing opengl code with a graphic tree view has some advantages, +though it has a different "feel" than normal pd patches. the fact that +opengl transforms object coordinates to screen coordinates, and not vice +versa, gives graphicly represented opengl code an "upside down" feel. + +one of the things i don't like about gem is that it has both the opengl +"upside down drawing and coordinate transformation tree" and the pix +"data flow image processing tree" in the same network, which i find +counterintuitive. it is too monolytic to be truly flexible. in pdp/3dp +i try to separate the two explicitly: dataflow where possible (image +processing), and serial context based processing where needed (opengl). + +another disadvantage of gem is its window centric context. by building +3dp around explicit context passing, with explicit context creation objects, +i try to avoid this. an advantage of this is the possibility to send +multiple contexts trough a rendering tree, i.e. to have 2 different views +of the same scene. + +pdp has implicit fanout for all packets. i think that is its great +strength. it enables you to use any kind of media packet like you would +use floats. it is very intuitive. however, 3d rendering does not fit +this shoe. at least not when you just wrap opengl in the most straightforward +way. 3dp is a test case for pdp's "accumulation packets", which is a formal +abstraction of a context. pdp processors are nothing more than serial programs +working on a context, so in fact it's nothing special. in fact, i'm still +in doubt if it is useful besides being able to support opengl.. + +so, the idea was to improve upon gem a bit, from different angles. i did +not succeed in my primary goal: making 3dp more intuitive than gem. it seems +this is only possible if you limit some of the flexibility. just wrapping +opengl keeps a lot of flexibility, but get's infected with the opengl +paradigm. by separating pdp (image processing) and 3dp (drawing and geometry +processing) as much as possible i think i've solved some intuition problems, +but 3dp itself is still basicly gem, with imho a better overall design, +but due to its more low level approach, maybe harder to understand. it seems +to me that knowing how opengl works is rather necessary to use 3dp. the same +is true for gem. + +one last philo remark: to me it seems the biggest drawback of gem's design is +the processor centric aproach: the only objects are processors, the data is +implicit and seemingly global. in pdp/3dp processors and objects are 2 separate +entities. i tried to unify them in one object model, but to me it seems the two +should really be treated as different complementary entities, to stay close to +the dataflow paradigm which makes pd such an intuitive tool. + diff --git a/opengl/TODO b/opengl/TODO new file mode 100644 index 0000000..58996fc --- /dev/null +++ b/opengl/TODO @@ -0,0 +1,124 @@ +bugs: WARNING: there are still quite a few fatal bugs lurking around. + +* segfault when combining 3dp_windowcontext and pdp_xv. probably a mistake +in the teture<->image conversion or window event handling. +* 3dp is not robust against running out of video card resources. if you +manage to crash it please consider sending a bug report. +* 3dp_dlist triggered a segfault in pdp_mutex(un?)lock. can't reproduce. +this also happens on some other occasions where a post() statement is involved: +crash in pdp_mutex_lock, called by putc() -> happens in pdp too when calling post from +thread (like in pdp_netsend/receive) +* pd hangs on save? what happens during save?? -> 0.35 prob? 0.36 seems to work fine. +* segfaults when deleting 3dp objects. very unpredictable. + + + + +todo: + +* fix flow control for texture conversion +* finish mesh object + + +general: + +* prevent display list recursion: add some state data to the context packet to solve this. + +redesign: +* unify pbuf & window contexts (postponed pbufs because of subcontexts) +* cube mapping +* bubble object (model + wave equation) +* finish 3dp light + +performance: +* why is texture upload so slow? and is there a way to work around it? +* (why) is context switching slow? and how to introduce the render context differently. (direct to window?) + + + +DESIGN NOTES + +3dp is basicly my idea of gem on top of pdp. it is a simple layer around opengl. +3dp_* render and transform objects accept a reference to a rendering context and pass this along. + +3dp_* objects DO NOT SUPPORT FANOUT. they do support fanin. multiple contexts can be sent to an object, which +will result in drawing in (or other manipulations of) the respective contexts. + +texture packets can be used to pass bitmap data around. 3dp_tdraw accepts a texture on its +second inlet. 3dp_snap dumps the current state of the buffer into a texture packet. + +object classes: + +-drawing objects + +[3dp_draw cube] [3dp_draw sphere] .. + +-manipulation objects + +[3dp_view rot2d] + +-opengl stack objects + +[3dp_push color view texture] + +3dp vs pdp design: + +a context packet is an accumulation packet, and the order of operations on it (serial) is important. it has +elements from a readonly packet (only one instance is passed around) and from a rw packet (it is legal to change it's +state and pass it on). + +opengl in dataflow formulation seems to be read bottom to top. i first thought +this was a big drawback of gem, but now that i finally understand how opengl works i think it is +ok. it suddenly dawned on me, usually the number of eyes is much smaller than the number of objects +in a scene, so it is much more straghtforward to start at the eye instead of the objects. since a +simple serial stack mechanism can be used. + +so opengl is really serial, while pd "looks" parallel, but is serial too. i still think this +is a good thing, since it keeps things simple, but for some reason the "upside down & serial" +thing about opengl in pd is rather strange.. + +once you get used to it, and think about rendering a set as a tree rooted at the "context source" +like is done in gem,it seems to work out.. + +i think i'm going to stick to the depth first backtracking a tree serial rendering +way of looking at it. since i don't see a way of making this more intuitive without complicating +it too much. so no legal fanout of a context packet. + +------------------ + +accumulation packets (buckets) & backtracking + +buckets add support for "context based" single threaded programs. it +basicly allows you to construct data processors represented as a control +flow tree. i.e. function calls can be represented by branches in a tree, +with each branch rooted at an object's outlet, executed from right to +left. a "context packet" (or accumulation packet or bucket) is passed +along and acted upon. + +* fanout is illegal for bucket processors (at least, if they are non +cummutative, as is usually the case). this is not explicitly prohibited, +since it is hard to check in pd and it allows some hacks. the reason for +this is obvious: if you do not know which branch of a tree is executed +first, results are undefined. + +* a new communication protocol needs to be introduced, incompatible +with the existing 3 phase protocol: + +(1) register_ro +(2) register_rw +(3) process + +the new dpd (bucket / accumulation packet) protocol is 2 phase: +(1) inspect +(2) accumulate + +(1) is only present to give priority to bucket inspectors over +accumulators (processors) + +an accumulation packet will be owned by its creator all the time. +accumulation processors do not increase the reference count. only ro +inspectors will. + +note: it is legal for a packet to have a broken register_rw (missing +copy constructor, i.e. if a copy is too expensive or impossible. this +must be set in the pdp packet header flags by the packet constructor) diff --git a/opengl/abstractions/3dp_basicscene.pd b/opengl/abstractions/3dp_basicscene.pd new file mode 100644 index 0000000..af79d51 --- /dev/null +++ b/opengl/abstractions/3dp_basicscene.pd @@ -0,0 +1,27 @@ +#N canvas 500 522 450 300 10; +#X obj 54 72 metro 40; +#X obj 54 140 3dp_push; +#X floatatom 375 162 5 0 0 0 - - -; +#X text 19 12 a basic 3d scene with a light source and mouse view rotation +; +#X obj 54 218 outlet; +#X obj 54 46 inlet; +#X floatatom 340 129 5 0 0 0 - - -; +#X floatatom 115 49 5 0 0 0 - - -; +#X obj 254 216 3dp_light 0; +#X obj 254 158 3dp_view roty; +#X obj 254 192 3dp_view transz 10; +#X obj 54 169 3dp_mouserotate; +#X obj 54 111 3dp_windowcontext; +#X connect 0 0 12 0; +#X connect 1 0 11 0; +#X connect 1 1 9 0; +#X connect 2 0 10 1; +#X connect 5 0 0 0; +#X connect 6 0 9 1; +#X connect 7 0 0 1; +#X connect 9 0 10 0; +#X connect 10 0 8 0; +#X connect 11 0 4 0; +#X connect 12 0 1 0; +#X connect 12 1 11 1; diff --git a/opengl/abstractions/3dp_blend.pd b/opengl/abstractions/3dp_blend.pd new file mode 100644 index 0000000..e7768d7 --- /dev/null +++ b/opengl/abstractions/3dp_blend.pd @@ -0,0 +1,13 @@ +#N canvas 554 145 570 225 10; +#X obj 25 124 3dp_toggle depth_test 0; +#X obj 181 159 3dp_toggle blend_add 1; +#X obj 25 90 inlet; +#X obj 330 199 outlet; +#X text 38 11 use this object for quick and dirty blending effects. +it has the depth test disabled and accumulated blending enabled.; +#X text 128 60 NOTE: proper transparency is quite hard to do \, because +it requires manual depth sorting. there is no real support for this +in 3dp yet.; +#X connect 0 1 1 0; +#X connect 1 1 3 0; +#X connect 2 0 0 0; diff --git a/opengl/abstractions/3dp_display_texture.pd b/opengl/abstractions/3dp_display_texture.pd new file mode 100644 index 0000000..63e602b --- /dev/null +++ b/opengl/abstractions/3dp_display_texture.pd @@ -0,0 +1,31 @@ +#N canvas 277 275 874 339 10; +#X obj 244 246 3dp_view scale_aspect; +#X obj 37 131 inlet; +#X obj 222 130 inlet; +#X obj 351 131 inlet; +#X text 27 107 context inlet; +#X text 198 106 texture inlet; +#X text 328 106 scaling inlet; +#X text 406 244 <- scale the square to the window aspect ratio; +#X obj 37 269 outlet; +#X text 40 16 this abstraction can be used for texture display. i.e. +if you use a subcontext at a fixed resolution to create a texture \, +this abstraction stretches the texture to the full size of the window +.; +#X obj 244 274 3dp_draw square 8; +#X obj 244 220 3dp_view scale 1; +#X text 405 219 <- extra scaling (i.e. to clip off garbage boundaries) +; +#X obj 37 162 3dp_toggle depth_test 0; +#X text 404 164 <- disable depth test so the draw will overwrite; +#X obj 193 190 3dp_push; +#X text 405 193 <- save modelview; +#X text 27 295 context outlet; +#X connect 0 0 10 0; +#X connect 1 0 13 0; +#X connect 2 0 10 1; +#X connect 3 0 11 1; +#X connect 11 0 0 0; +#X connect 13 0 8 0; +#X connect 13 1 15 0; +#X connect 15 1 11 0; diff --git a/opengl/abstractions/3dp_fixedsizewindowcontext.pd b/opengl/abstractions/3dp_fixedsizewindowcontext.pd new file mode 100644 index 0000000..5dd5180 --- /dev/null +++ b/opengl/abstractions/3dp_fixedsizewindowcontext.pd @@ -0,0 +1,31 @@ +#N canvas 634 346 592 397 10; +#X obj 27 64 inlet; +#X obj 27 105 3dp_windowcontext; +#X obj 27 138 3dp_subcontext \$1 \$2; +#X obj 220 211 outlet; +#X obj 370 211 outlet; +#X text 350 236 event outlet; +#X obj 162 267 3dp_snap; +#X obj 27 318 3dp_display_texture; +#X text 150 23 a fixed size (window size independent) rendering context +that can be used as 3dp_windowcontext replacement.; +#X text 151 56 creation arguments are the context dimensions.; +#X text 175 87 NOTE: the general subcontext rule applies: if the actual +window size is small than the subcontext \, or is covered by other +windows \, the results might not be what you expect.; +#X text 176 236 context outlet (1); +#X text 241 266 <- when the render chain connected to (1) is done; +#X text 261 281 it will be snapped to texture; +#X text 241 316 <- this texture will then be drawn to cover; +#X text 263 332 the entire window size; +#X obj 162 177 pdp_t p p; +#X obj 184 300 inlet; +#X connect 0 0 1 0; +#X connect 1 0 2 0; +#X connect 1 1 4 0; +#X connect 2 0 7 0; +#X connect 2 1 16 0; +#X connect 6 1 7 1; +#X connect 16 0 6 0; +#X connect 16 1 3 0; +#X connect 17 0 7 2; diff --git a/opengl/abstractions/3dp_mouserotate.pd b/opengl/abstractions/3dp_mouserotate.pd new file mode 100644 index 0000000..b81e27e --- /dev/null +++ b/opengl/abstractions/3dp_mouserotate.pd @@ -0,0 +1,37 @@ +#N canvas 534 483 533 399 10; +#X obj 27 19 inlet; +#X obj 27 363 outlet; +#X obj 70 152 - 0.5; +#X obj 135 151 - 0.5; +#X obj 82 214 *; +#X obj 135 212 *; +#X obj 135 186 t f f; +#X obj 82 184 t f f; +#X obj 82 243 +; +#X obj 113 271 sqrt; +#X obj 92 19 inlet; +#X obj 113 298 * 360; +#X obj 27 329 3dp_view rota; +#X text 216 138 convert mouse coordinates to axis and angle; +#X obj 70 118 unpack 0 0; +#X obj 92 49 route drag1 press1; +#X connect 0 0 12 0; +#X connect 2 0 7 0; +#X connect 2 0 12 2; +#X connect 3 0 6 0; +#X connect 3 0 12 1; +#X connect 4 0 8 0; +#X connect 5 0 8 1; +#X connect 6 0 5 0; +#X connect 6 1 5 1; +#X connect 7 0 4 0; +#X connect 7 1 4 1; +#X connect 8 0 9 0; +#X connect 9 0 11 0; +#X connect 10 0 15 0; +#X connect 11 0 12 4; +#X connect 12 0 1 0; +#X connect 14 0 2 0; +#X connect 14 1 3 0; +#X connect 15 0 14 0; +#X connect 15 1 14 0; diff --git a/opengl/abstractions/3dp_screenshot.pd b/opengl/abstractions/3dp_screenshot.pd new file mode 100644 index 0000000..9cbe07f --- /dev/null +++ b/opengl/abstractions/3dp_screenshot.pd @@ -0,0 +1,21 @@ +#N canvas 550 41 714 494 10; +#X obj 193 284 pdp_reg; +#X obj 193 203 pdp_t b p; +#X obj 193 233 symbol \$1; +#X msg 193 257 save_png \$1; +#X obj 195 110 loadbang; +#X msg 195 135 autosnap 0; +#X obj 51 111 inlet; +#X obj 51 176 3dp_snap bitmap/rgb/*; +#X obj 51 285 outlet; +#X text 41 22 make a screenshot of a 3dp context. creation argument +is filename. send a bang to take a snapshot.; +#X connect 1 0 2 0; +#X connect 1 1 0 1; +#X connect 2 0 3 0; +#X connect 3 0 0 0; +#X connect 4 0 5 0; +#X connect 5 0 7 0; +#X connect 6 0 7 0; +#X connect 7 0 8 0; +#X connect 7 1 1 0; diff --git a/opengl/abstractions/elbat.pd b/opengl/abstractions/elbat.pd new file mode 100644 index 0000000..211da15 --- /dev/null +++ b/opengl/abstractions/elbat.pd @@ -0,0 +1,41 @@ +#N canvas 431 78 581 572 10; +#X obj 23 63 inlet; +#X obj 168 211 outlet; +#X obj 168 150 tabread \$0-vec; +#X msg 15 210 \; \$1 const 0; +#X msg 15 159 bang; +#X obj 15 183 symbol \$0-vec; +#X obj 119 373 until; +#X msg 118 270 bang; +#X obj 155 414 f 0; +#X obj 191 414 + 1; +#X msg 163 338 0; +#X obj 119 318 t b b; +#X obj 156 519 tabwrite \$0-vec; +#X obj 155 443 t b f; +#X obj 154 478 randomnormal; +#X obj 119 348 f \$1; +#X obj 23 86 route reset normal; +#X text 168 274 fill table with normal distributed random variables +; +#X text 19 16 a tabread-like abstraction (with internal table); +#X obj 320 108 table \$0-vec \$1; +#X connect 0 0 16 0; +#X connect 2 0 1 0; +#X connect 4 0 5 0; +#X connect 5 0 3 0; +#X connect 6 0 8 0; +#X connect 7 0 11 0; +#X connect 8 0 9 0; +#X connect 8 0 13 0; +#X connect 9 0 8 1; +#X connect 10 0 8 1; +#X connect 11 0 15 0; +#X connect 11 1 10 0; +#X connect 13 0 14 0; +#X connect 13 1 12 1; +#X connect 14 0 12 0; +#X connect 15 0 6 0; +#X connect 16 0 4 0; +#X connect 16 1 7 0; +#X connect 16 2 2 0; diff --git a/opengl/abstractions/randomnormal.pd b/opengl/abstractions/randomnormal.pd new file mode 100644 index 0000000..bf1d4fa --- /dev/null +++ b/opengl/abstractions/randomnormal.pd @@ -0,0 +1,39 @@ +#N canvas 614 389 451 505 10; +#X obj 48 58 inlet; +#X obj 48 88 t b b; +#X obj 173 167 * 6.28; +#X obj 129 221 cos; +#X obj 173 222 sin; +#X obj 173 143 / 1e+06; +#X obj 173 121 random 1e+06; +#X obj 48 220 * -2; +#X obj 48 170 / 1e+06; +#X obj 48 125 random 1e+06; +#X obj 48 148 + 1; +#X obj 48 194 log; +#X obj 48 327 *; +#X obj 108 328 *; +#X obj 48 292 t f f; +#X obj 48 365 outlet; +#X obj 108 365 outlet; +#X text 35 10 normal gausian random number generator (box-muller); +#X obj 48 253 sqrt; +#X connect 0 0 1 0; +#X connect 1 0 9 0; +#X connect 1 1 6 0; +#X connect 2 0 4 0; +#X connect 2 0 3 0; +#X connect 3 0 12 1; +#X connect 4 0 13 1; +#X connect 5 0 2 0; +#X connect 6 0 5 0; +#X connect 7 0 18 0; +#X connect 8 0 11 0; +#X connect 9 0 10 0; +#X connect 10 0 8 0; +#X connect 11 0 7 0; +#X connect 12 0 15 0; +#X connect 13 0 16 0; +#X connect 14 0 12 0; +#X connect 14 1 13 0; +#X connect 18 0 14 0; diff --git a/opengl/abstractions/randomwalk2D.pd b/opengl/abstractions/randomwalk2D.pd new file mode 100644 index 0000000..58cf2df --- /dev/null +++ b/opengl/abstractions/randomwalk2D.pd @@ -0,0 +1,51 @@ +#N canvas 502 172 600 400 10; +#X obj 228 221 tabread \$0-x; +#X obj 334 213 tabread \$0-y; +#X obj 228 310 tabwrite \$0-x; +#X obj 350 330 tabwrite \$0-y; +#X obj 244 259 cos; +#X obj 350 266 sin; +#X obj 351 241 * 0.0628; +#X obj 351 185 random 100; +#X obj 228 284 +; +#X obj 334 291 +; +#X obj 228 144 t f b f; +#X msg 53 237 \; \$1 const 0; +#X obj 20 199 symbol \$0-x; +#X obj 108 199 symbol \$0-y; +#X msg 88 173 bang; +#X obj 228 172 t f f; +#X obj 214 337 outlet; +#X obj 334 354 outlet; +#X obj 156 82 inlet; +#X obj 156 106 route reset; +#X obj 351 82 table \$0-x \$1; +#X obj 351 116 table \$0-y \$1; +#X text 37 20 a 2D unit step random walk abstraction for use with 3dp_for +; +#X text 335 45 creation argument = nb of vectors; +#X text 64 44 inlet = vector to update; +#X connect 0 0 8 0; +#X connect 1 0 9 0; +#X connect 4 0 8 1; +#X connect 5 0 9 1; +#X connect 6 0 4 0; +#X connect 6 0 5 0; +#X connect 7 0 6 0; +#X connect 8 0 2 0; +#X connect 8 0 16 0; +#X connect 9 0 3 0; +#X connect 9 0 17 0; +#X connect 10 0 15 0; +#X connect 10 1 7 0; +#X connect 10 2 3 1; +#X connect 10 2 2 1; +#X connect 12 0 11 0; +#X connect 13 0 11 0; +#X connect 14 0 12 0; +#X connect 14 0 13 0; +#X connect 15 0 0 0; +#X connect 15 1 1 0; +#X connect 18 0 19 0; +#X connect 19 0 14 0; +#X connect 19 1 10 0; diff --git a/opengl/abstractions/smoothupdate.pd b/opengl/abstractions/smoothupdate.pd new file mode 100644 index 0000000..19df278 --- /dev/null +++ b/opengl/abstractions/smoothupdate.pd @@ -0,0 +1,49 @@ +#N canvas 112 570 450 387 10; +#X obj 225 64 inlet; +#X text 195 40 element to update; +#X obj 23 63 inlet; +#X text 39 39 new value; +#X obj 55 302 outlet; +#X obj 331 173 table \$0-vec; +#X obj 168 121 f 0; +#X obj 168 150 tabread \$0-vec; +#X text 350 41 smooth step; +#X obj 354 65 inlet; +#X obj 354 90 moses 0; +#X obj 366 116 moses 1; +#X msg 331 114 0; +#X msg 410 140 1; +#X obj 135 182 -; +#X obj 57 114 t f b; +#X obj 332 144 f; +#X obj 135 246 +; +#X obj 146 282 tabwrite \$0-vec; +#X obj 23 86 route reset; +#X msg 15 210 \; \$1 const 0; +#X msg 15 159 bang; +#X obj 15 183 symbol \$0-vec; +#X obj 136 215 * 0.1; +#X connect 0 0 6 1; +#X connect 2 0 19 0; +#X connect 6 0 7 0; +#X connect 6 0 18 1; +#X connect 7 0 14 1; +#X connect 7 0 17 1; +#X connect 9 0 10 0; +#X connect 10 0 12 0; +#X connect 10 1 11 0; +#X connect 11 0 16 0; +#X connect 11 1 13 0; +#X connect 12 0 16 0; +#X connect 13 0 16 0; +#X connect 14 0 23 0; +#X connect 15 0 14 0; +#X connect 15 1 6 0; +#X connect 16 0 23 1; +#X connect 17 0 4 0; +#X connect 17 0 18 0; +#X connect 19 0 21 0; +#X connect 19 1 15 0; +#X connect 21 0 22 0; +#X connect 22 0 20 0; +#X connect 23 0 17 0; diff --git a/opengl/doc/examples/arm.pd b/opengl/doc/examples/arm.pd new file mode 100644 index 0000000..36a8f48 --- /dev/null +++ b/opengl/doc/examples/arm.pd @@ -0,0 +1,40 @@ +#N canvas 475 534 572 380 10; +#X obj 43 10 inlet; +#X obj 43 227 outlet; +#X obj 43 141 3dp_push; +#X obj 208 200 3dp_view transx 0.5; +#X obj 43 113 3dp_view rotz; +#X obj 260 11 inlet; +#X obj 208 174 3dp_view scalex \$1; +#X obj 43 186 3dp_view transx \$1; +#X obj 260 275 r texture; +#X obj 43 83 3dp_view roty; +#X obj 129 61 r roty; +#X obj 329 91 r scale; +#X obj 43 37 3dp_draw cube 1; +#X obj 143 11 r cubesize; +#X obj 208 334 3dp_draw torus 0.25 0.5 6; +#X obj 208 256 spigot; +#X obj 245 232 r drawtorus; +#X obj 276 307 r torusr1; +#X obj 353 307 r torusr2; +#X text 375 27 draw one arm segment; +#X connect 0 0 12 0; +#X connect 2 0 7 0; +#X connect 2 1 6 0; +#X connect 3 0 15 0; +#X connect 4 0 2 0; +#X connect 5 0 4 1; +#X connect 6 0 3 0; +#X connect 7 0 1 0; +#X connect 8 0 14 1; +#X connect 9 0 4 0; +#X connect 10 0 9 1; +#X connect 11 0 6 1; +#X connect 11 0 7 1; +#X connect 12 0 9 0; +#X connect 13 0 12 2; +#X connect 15 0 14 0; +#X connect 16 0 15 1; +#X connect 17 0 14 2; +#X connect 18 0 14 3; diff --git a/opengl/doc/examples/example01.pd b/opengl/doc/examples/example01.pd new file mode 100644 index 0000000..969ee17 --- /dev/null +++ b/opengl/doc/examples/example01.pd @@ -0,0 +1,257 @@ +#N canvas 426 142 799 779 10; +#X floatatom 126 37 5 0 0 0 - - -; +#X obj 56 20 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 83 19 stop; +#X floatatom 360 431 5 0 0 0 - - -; +#X obj 59 103 3dp_push; +#X floatatom 672 189 5 0 0 0 - - -; +#X obj 546 244 3dp_view transx 3; +#X obj 546 270 3dp_light; +#X obj 612 97 f; +#X floatatom 641 98 5 0 0 0 - - -; +#X floatatom 669 370 5 0 0 0 - - -; +#X obj 182 491 arm 3; +#X obj 182 514 arm 3; +#X obj 182 537 arm 3; +#X obj 182 467 arm 3; +#X floatatom 360 455 5 0 0 0 - - -; +#X floatatom 359 478 5 0 0 0 - - -; +#X floatatom 358 501 5 0 0 0 - - -; +#X floatatom 358 524 5 0 0 0 - - -; +#X obj 182 584 arm 3; +#X obj 182 607 arm 3; +#X obj 182 630 arm 3; +#X obj 182 560 arm 3; +#X floatatom 358 548 5 0 0 0 - - -; +#X floatatom 358 571 5 0 0 0 - - -; +#X floatatom 358 594 5 0 0 0 - - -; +#X obj 59 224 3dp_view roty; +#X obj 284 449 * 1; +#X obj 284 589 * -1; +#X obj 182 653 arm 3; +#X floatatom 358 617 5 0 0 0 - - -; +#X obj 284 635 * -1.5; +#X obj 663 686 s roty; +#X floatatom 615 611 5 0 0 0 - - -; +#X floatatom 671 585 5 0 0 0 - - -; +#X obj 673 616 s scale; +#X floatatom 359 388 5 0 0 0 - - -; +#X obj 284 473 * -1.01; +#X obj 284 496 * 0.99; +#X obj 284 519 * -1.01; +#X obj 284 542 * 2.1; +#X obj 284 566 * -1.7; +#X obj 182 425 3dp_draw cube 1.4; +#X obj 182 809 3dp_draw cube 1.4; +#X msg 597 536 4; +#X obj 59 151 3dp_view transz -3; +#X obj 546 216 3dp_view roty 54; +#X obj 669 392 s cubesize; +#X msg 360 345 3.15; +#X msg 126 17 20; +#X obj 284 612 * 0.11; +#X floatatom 672 220 5 0 0 0 - - -; +#X msg 612 72 0; +#X obj 342 311 * 1; +#X obj 59 201 3dp_view rotx; +#X floatatom 164 187 5 0 0 0 - - -; +#X floatatom 358 641 5 0 0 0 - - -; +#X obj 182 700 arm 3; +#X obj 182 724 arm 3; +#X obj 182 748 arm 3; +#X obj 182 677 arm 3; +#X floatatom 359 664 5 0 0 0 - - -; +#X floatatom 359 688 5 0 0 0 - - -; +#X floatatom 360 712 5 0 0 0 - - -; +#X obj 284 706 * -1; +#X obj 182 771 arm 3; +#X floatatom 360 735 5 0 0 0 - - -; +#X obj 283 753 * -1.5; +#X obj 284 659 * 2.1; +#X obj 284 682 * -1.7; +#X obj 283 730 * 0.11; +#X obj 9 334 3dp_push; +#X obj 182 399 3dp_view transz; +#X floatatom 282 369 5 0 0 0 - - -; +#X obj 131 371 3dp_view transz; +#X obj 231 338 * -1; +#X msg 282 341 2; +#X obj 564 401 s drawtorus; +#X obj 564 374 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X obj 674 496 s torusr1; +#X floatatom 672 473 5 0 0 0 - - -; +#X floatatom 667 419 5 0 0 0 - - -; +#X obj 669 442 s torusr2; +#X msg 564 349 1; +#X obj 597 645 *; +#X obj 59 126 3dp_push; +#X obj 9 364 3dp_push; +#X obj 9 437 3dp_view rotx; +#X floatatom 96 416 5 0 0 0 - - -; +#X obj 9 471 3dp_draw sphere 30 40; +#X obj 9 593 3dp_snap; +#X obj 473 487 / 1000; +#X floatatom 473 461 5 0 0 0 - - -; +#X obj 430 8 loadbang; +#X obj 430 31 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 59 77 3dp_windowcontext; +#X obj 59 274 3dp_push; +#X obj 110 303 pdp_t p b; +#X obj 9 307 pdp_t p b; +#X msg 349 252 400; +#X msg 311 252 -400; +#X obj 342 287 +; +#X msg 473 434 3; +#X text 544 189 light source; +#X obj 59 248 3dp_view scale 0.4; +#X obj 640 157 s counter; +#X obj 245 169 r counter; +#X text 694 98 speed; +#X obj 59 54 metro 20; +#X obj 238 207 * 0.05; +#X obj 9 570 spigot; +#X obj 76 546 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 612 122 + 1; +#X text 28 521 texture feedback; +#X text 486 751 "no-bots in no-sphere"; +#X text 459 768 a double dance of 13 segments; +#X text 549 734 ---; +#X text 549 787 ---; +#X obj 59 176 3dp_mouserotate; +#X connect 0 0 108 1; +#X connect 1 0 108 0; +#X connect 2 0 108 0; +#X connect 3 0 27 1; +#X connect 4 0 85 0; +#X connect 4 1 46 0; +#X connect 5 0 46 1; +#X connect 6 0 7 0; +#X connect 8 0 112 0; +#X connect 9 0 112 1; +#X connect 10 0 47 0; +#X connect 11 0 12 0; +#X connect 12 0 13 0; +#X connect 13 0 22 0; +#X connect 14 0 11 0; +#X connect 15 0 37 1; +#X connect 16 0 38 1; +#X connect 17 0 39 1; +#X connect 18 0 40 1; +#X connect 19 0 20 0; +#X connect 20 0 21 0; +#X connect 21 0 29 0; +#X connect 22 0 19 0; +#X connect 23 0 41 1; +#X connect 24 0 28 1; +#X connect 25 0 50 1; +#X connect 26 0 104 0; +#X connect 27 0 37 0; +#X connect 27 0 14 1; +#X connect 28 0 50 0; +#X connect 28 0 20 1; +#X connect 29 0 60 0; +#X connect 30 0 31 1; +#X connect 31 0 29 1; +#X connect 31 0 68 0; +#X connect 33 0 84 1; +#X connect 34 0 35 0; +#X connect 36 0 42 2; +#X connect 36 0 43 2; +#X connect 37 0 38 0; +#X connect 37 0 11 1; +#X connect 38 0 39 0; +#X connect 38 0 12 1; +#X connect 39 0 40 0; +#X connect 39 0 13 1; +#X connect 40 0 41 0; +#X connect 40 0 22 1; +#X connect 41 0 28 0; +#X connect 41 0 19 1; +#X connect 42 0 14 0; +#X connect 44 0 34 0; +#X connect 45 0 118 0; +#X connect 46 0 6 0; +#X connect 48 0 36 0; +#X connect 48 0 102 0; +#X connect 48 0 76 0; +#X connect 48 0 83 0; +#X connect 49 0 0 0; +#X connect 50 0 31 0; +#X connect 50 0 21 1; +#X connect 51 0 6 1; +#X connect 52 0 8 0; +#X connect 53 0 27 0; +#X connect 54 0 26 0; +#X connect 55 0 54 1; +#X connect 56 0 68 1; +#X connect 57 0 58 0; +#X connect 58 0 59 0; +#X connect 59 0 65 0; +#X connect 60 0 57 0; +#X connect 61 0 69 1; +#X connect 62 0 64 1; +#X connect 63 0 70 1; +#X connect 64 0 70 0; +#X connect 64 0 58 1; +#X connect 65 0 43 0; +#X connect 66 0 67 1; +#X connect 67 0 65 1; +#X connect 68 0 69 0; +#X connect 68 0 60 1; +#X connect 69 0 64 0; +#X connect 69 0 57 1; +#X connect 70 0 67 0; +#X connect 70 0 59 1; +#X connect 71 0 86 0; +#X connect 71 1 74 0; +#X connect 72 0 42 0; +#X connect 73 0 72 1; +#X connect 73 0 75 0; +#X connect 74 0 42 0; +#X connect 75 0 74 1; +#X connect 76 0 73 0; +#X connect 78 0 77 0; +#X connect 80 0 79 0; +#X connect 81 0 82 0; +#X connect 83 0 78 0; +#X connect 84 0 32 0; +#X connect 85 0 45 0; +#X connect 86 0 87 0; +#X connect 87 0 89 0; +#X connect 88 0 87 1; +#X connect 89 0 110 0; +#X connect 90 1 89 1; +#X connect 91 0 33 0; +#X connect 92 0 91 0; +#X connect 93 0 94 0; +#X connect 94 0 1 0; +#X connect 94 0 48 0; +#X connect 95 0 4 0; +#X connect 95 1 118 1; +#X connect 96 0 98 0; +#X connect 96 1 97 0; +#X connect 97 0 72 0; +#X connect 97 1 100 0; +#X connect 98 0 71 0; +#X connect 98 1 99 0; +#X connect 99 0 101 0; +#X connect 100 0 101 0; +#X connect 101 0 53 0; +#X connect 102 0 92 0; +#X connect 102 0 44 0; +#X connect 104 0 96 0; +#X connect 106 0 109 0; +#X connect 108 0 95 0; +#X connect 108 0 8 0; +#X connect 109 0 26 1; +#X connect 110 0 90 0; +#X connect 111 0 110 1; +#X connect 112 0 8 1; +#X connect 112 0 84 0; +#X connect 112 0 101 1; +#X connect 112 0 105 0; +#X connect 118 0 54 0; diff --git a/opengl/doc/examples/example02.pd b/opengl/doc/examples/example02.pd new file mode 100644 index 0000000..d5023d9 --- /dev/null +++ b/opengl/doc/examples/example02.pd @@ -0,0 +1,46 @@ +#N canvas 696 306 480 535 10; +#X obj 102 73 3dp_windowcontext; +#X obj 102 36 metro 20; +#X obj 102 122 3dp_push; +#X obj 102 11 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 56 40 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 253 32 cursor \$1; +#X obj 253 12 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X obj 102 209 3dp_mouserotate; +#X obj 153 322 3dp_draw cube 1; +#X obj 265 139 3dp_view transxyz -4 3 4; +#X obj 102 270 3dp_push; +#X obj 102 348 3dp_push; +#X obj 102 425 3dp_push; +#X obj 153 296 3dp_view transx 2; +#X obj 153 374 3dp_view transy 2; +#X obj 153 451 3dp_view transz 2; +#X obj 153 400 3dp_draw cube 1; +#X obj 153 477 3dp_draw cube 1; +#X obj 102 506 3dp_draw dodeca 1; +#X text 25 231 use the mouse to rotate the model (but not the light +source since it is rendered before the rotation is applied.); +#X obj 265 161 3dp_light; +#X connect 0 0 2 0; +#X connect 0 1 7 1; +#X connect 1 0 0 0; +#X connect 2 0 7 0; +#X connect 2 1 9 0; +#X connect 3 0 1 0; +#X connect 4 0 0 0; +#X connect 5 0 0 0; +#X connect 6 0 5 0; +#X connect 7 0 10 0; +#X connect 9 0 20 0; +#X connect 10 0 11 0; +#X connect 10 1 13 0; +#X connect 11 0 12 0; +#X connect 11 1 14 0; +#X connect 12 0 18 0; +#X connect 12 1 15 0; +#X connect 13 0 8 0; +#X connect 14 0 16 0; +#X connect 15 0 17 0; diff --git a/opengl/doc/examples/example03.pd b/opengl/doc/examples/example03.pd new file mode 100644 index 0000000..48d714b --- /dev/null +++ b/opengl/doc/examples/example03.pd @@ -0,0 +1,65 @@ +#N canvas 382 102 480 535 10; +#X obj 102 73 3dp_windowcontext; +#X obj 102 36 metro 20; +#X obj 102 139 3dp_push; +#X obj 261 185 3dp_light; +#X obj 102 11 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 56 40 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 253 32 cursor \$1; +#X obj 253 12 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 102 209 3dp_mouserotate; +#X obj 261 163 3dp_view transxyz -4 3 4; +#X obj 102 427 arm 3; +#X obj 371 230 loadbang; +#X obj 102 333 pdp_t p p p p; +#X obj 102 304 pdp_t p p p p; +#X floatatom 199 386 5 0 0; +#X obj 318 378 s roty; +#X floatatom 318 327 5 0 0; +#X obj 371 378 s drawtorus; +#X obj 371 355 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X obj 102 256 pdp_t p b; +#X obj 212 273 f 0; +#X obj 302 352 *; +#X obj 183 409 *; +#X obj 212 307 + 0.1; +#X obj 102 105 3dp_view transz -5; +#X text 41 471 it is possible to send the rendercontext to the same +rendering/transforming chain multiple times. (in other words: 3dp objects +do not support fanout \, but they do support fanin.); +#X connect 0 0 24 0; +#X connect 0 1 8 1; +#X connect 1 0 0 0; +#X connect 2 0 8 0; +#X connect 2 1 9 0; +#X connect 4 0 1 0; +#X connect 5 0 0 0; +#X connect 6 0 0 0; +#X connect 7 0 6 0; +#X connect 8 0 19 0; +#X connect 9 0 3 0; +#X connect 11 0 18 0; +#X connect 12 0 10 0; +#X connect 12 1 10 0; +#X connect 12 2 10 0; +#X connect 12 3 10 0; +#X connect 13 0 12 0; +#X connect 13 1 12 0; +#X connect 13 2 12 0; +#X connect 13 3 12 0; +#X connect 14 0 22 1; +#X connect 16 0 21 1; +#X connect 18 0 17 0; +#X connect 19 0 13 0; +#X connect 19 1 20 0; +#X connect 20 0 23 0; +#X connect 21 0 15 0; +#X connect 22 0 10 1; +#X connect 23 0 20 1; +#X connect 23 0 22 0; +#X connect 23 0 21 0; +#X connect 24 0 2 0; diff --git a/opengl/doc/examples/example04.pd b/opengl/doc/examples/example04.pd new file mode 100644 index 0000000..5d22270 --- /dev/null +++ b/opengl/doc/examples/example04.pd @@ -0,0 +1,25 @@ +#N canvas 288 311 566 284 10; +#X obj 54 156 3dp_windowcontext; +#X obj 54 43 metro 40; +#X obj 54 19 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X obj 54 76 t b b; +#X obj 134 120 pdp_convert texture/*/*; +#X obj 54 183 3dp_mouserotate; +#X floatatom 180 202 5 0 0 0 - - -; +#X msg 134 68 open /dev/video1; +#X obj 54 227 3dp_draw sphere 5; +#X text 132 18 convert pdp image packets to textures and map them on +a sphere; +#X obj 134 93 pdp_v4l; +#X connect 0 0 5 0; +#X connect 0 1 5 1; +#X connect 1 0 3 0; +#X connect 2 0 1 0; +#X connect 3 0 0 0; +#X connect 3 1 10 0; +#X connect 4 0 8 1; +#X connect 5 0 8 0; +#X connect 6 0 8 2; +#X connect 7 0 10 0; +#X connect 10 0 4 0; diff --git a/opengl/doc/examples/example05.pd b/opengl/doc/examples/example05.pd new file mode 100644 index 0000000..7996355 --- /dev/null +++ b/opengl/doc/examples/example05.pd @@ -0,0 +1,41 @@ +#N canvas 352 162 732 325 10; +#X obj 54 43 metro 40; +#X obj 54 19 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 314 120 pdp_convert texture/*/*; +#X floatatom 343 212 5 0 0; +#X obj 286 247 3dp_draw sphere 5; +#X obj 314 95 pdp_plasma; +#X obj 408 48 loadbang; +#X msg 408 70 dim 512 256; +#X obj 314 65 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 181 144 3dp_windowcontext; +#X obj 181 203 3dp_view roty; +#X floatatom 267 176 5 0 0; +#X obj 31 144 3dp_windowcontext; +#X obj 31 203 3dp_view roty; +#X floatatom 117 176 5 0 0; +#X obj 286 278 3dp_draw cube 2; +#X obj 336 164 pdp_del 3; +#X text 414 164 <- textures can be stored in a delay line; +#X text 133 9 convert pdp image packets to textures and map them on +a sphere and cube. create 2 independent viewing windows.; +#X connect 0 0 9 0; +#X connect 0 0 12 0; +#X connect 1 0 0 0; +#X connect 2 0 4 1; +#X connect 2 0 16 0; +#X connect 3 0 4 2; +#X connect 4 0 15 0; +#X connect 5 0 2 0; +#X connect 6 0 7 0; +#X connect 7 0 5 0; +#X connect 8 0 5 0; +#X connect 9 0 10 0; +#X connect 10 0 4 0; +#X connect 11 0 10 1; +#X connect 12 0 13 0; +#X connect 13 0 4 0; +#X connect 14 0 13 1; +#X connect 16 0 15 1; diff --git a/opengl/doc/examples/example06.pd b/opengl/doc/examples/example06.pd new file mode 100644 index 0000000..8d8595a --- /dev/null +++ b/opengl/doc/examples/example06.pd @@ -0,0 +1,85 @@ +#N canvas 516 361 634 497 10; +#X obj 23 119 metro 40; +#X obj 23 89 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 360 397 pdp_convert texture/*/*; +#X obj 23 387 3dp_mouserotate; +#X obj 155 255 3dp_light 0; +#X obj 23 193 3dp_push; +#X floatatom 269 198 5 0 0; +#X obj 23 161 3dp_windowcontext; +#X obj 360 299 pdp_convert image/grey/*; +#X obj 360 184 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 478 163 random; +#X msg 479 186 rule gameoflife; +#X msg 478 114 rule fire; +#X obj 360 270 pdp_ca; +#X obj 360 371 pdp_motion_phase; +#X floatatom 479 343 5 0 0; +#X obj 478 88 loadbang; +#X msg 479 322 0.33; +#X obj 328 473 3dp_draw sphere 2.6; +#X floatatom 463 434 5 0 0; +#X obj 155 227 3dp_view transz 5; +#X floatatom 480 237 5 0 0; +#X msg 517 322 1; +#X obj 360 347 pdp_gain; +#X floatatom 411 323 5 0 0; +#X msg 478 139 dim 256 128; +#X obj 179 393 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 328 419 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X obj 23 416 3dp_toggle depth_test 0; +#X obj 179 445 3dp_toggle blend_add 1; +#X msg 480 213 1; +#X obj 23 316 3dp_mode texture; +#X floatatom 281 310 5 0 0; +#X obj 156 339 3dp_view scale 1; +#X floatatom 280 340 5 0 0; +#X obj 156 366 3dp_view rotz; +#X text 141 197 move light source; +#X text 143 294 transform texture coords; +#X text 31 12 blending with depth test disabled using 3dp_toggle object. +together with a cellular automata texture (you need pdp_scaf for this) +and texture coordinate transformation.; +#X connect 0 0 7 0; +#X connect 0 0 9 0; +#X connect 1 0 0 0; +#X connect 2 0 18 1; +#X connect 3 0 28 0; +#X connect 5 0 31 0; +#X connect 5 1 20 0; +#X connect 6 0 20 1; +#X connect 7 0 5 0; +#X connect 7 1 3 1; +#X connect 8 0 23 0; +#X connect 9 0 13 0; +#X connect 10 0 13 0; +#X connect 11 0 13 0; +#X connect 12 0 13 0; +#X connect 12 0 25 0; +#X connect 13 0 8 0; +#X connect 14 0 2 0; +#X connect 15 0 14 1; +#X connect 16 0 12 0; +#X connect 17 0 15 0; +#X connect 19 0 18 2; +#X connect 20 0 4 0; +#X connect 21 0 13 2; +#X connect 22 0 15 0; +#X connect 23 0 14 0; +#X connect 24 0 23 1; +#X connect 25 0 13 0; +#X connect 25 0 10 0; +#X connect 26 0 28 1; +#X connect 27 0 29 1; +#X connect 28 1 29 0; +#X connect 29 1 18 0; +#X connect 30 0 21 0; +#X connect 31 0 3 0; +#X connect 31 1 33 0; +#X connect 32 0 33 1; +#X connect 33 0 35 0; +#X connect 34 0 35 1; diff --git a/opengl/doc/examples/example07.pd b/opengl/doc/examples/example07.pd new file mode 100644 index 0000000..cd3618c --- /dev/null +++ b/opengl/doc/examples/example07.pd @@ -0,0 +1,25 @@ +#N canvas 400 454 637 428 10; +#X obj 18 131 3dp_windowcontext; +#X obj 18 159 3dp_push; +#X obj 201 70 metro 40; +#X obj 201 42 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 201 99 pdp_v4l; +#X obj 201 131 pdp_convert texture/*/*; +#X floatatom 258 265 5 0 0; +#X obj 18 218 3dp_view scalex 1.33333; +#X obj 18 187 3dp_mouserotate; +#X text 15 10 using a square scaled by an aspect ratio to construct +an an alternative pdp_glx; +#X obj 144 290 3dp_draw square 8; +#X connect 0 0 1 0; +#X connect 0 1 8 1; +#X connect 1 0 8 0; +#X connect 2 0 0 0; +#X connect 2 0 4 0; +#X connect 3 0 2 0; +#X connect 4 0 5 0; +#X connect 5 0 10 1; +#X connect 6 0 10 2; +#X connect 7 0 10 0; +#X connect 8 0 7 0; diff --git a/opengl/doc/examples/example08.pd b/opengl/doc/examples/example08.pd new file mode 100644 index 0000000..a5f7e9d --- /dev/null +++ b/opengl/doc/examples/example08.pd @@ -0,0 +1,94 @@ +#N canvas 96 78 756 667 10; +#X obj 18 131 3dp_windowcontext; +#X obj 18 159 3dp_push; +#X obj 327 80 metro 40; +#X obj 327 52 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 327 224 pdp_v4l; +#X obj 431 463 pdp_convert texture/*/*; +#X floatatom 488 554 5 0 0; +#X obj 18 215 3dp_view scalex 1.33333; +#X obj 18 189 3dp_mouserotate; +#X floatatom 83 308 5 0 0; +#X msg 83 287 10; +#X obj 69 428 3dp_view rotx; +#X obj 69 475 3dp_view roty; +#X obj 69 523 3dp_view rotz; +#X obj 155 398 random 360; +#X obj 155 453 random 360; +#X obj 155 500 random 360; +#X obj 155 371 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 18 366 3dp_push; +#X text 132 305 nb of squares; +#X floatatom 220 369 5 0 0; +#X obj 431 309 pdp_plasma; +#X obj 431 256 loadbang; +#X obj 327 192 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 397 279 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 417 55 200; +#X floatatom 510 364 5 0 0; +#X msg 378 55 40; +#X obj 327 126 spigot; +#X obj 385 106 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X obj 431 395 pdp_gain 0.3; +#X obj 18 333 3dp_for 10; +#X text 21 12 another example of accumulated blending combined with +a 3dp_for object to render multiple randomly rotated squares.; +#X msg 386 186 open /dev/video1; +#X obj 18 246 3dp_blend; +#X text 411 106 switch between video textures and stills; +#X msg 386 160 open /dev/video0; +#X text 87 246 <-- click for more info; +#X msg 431 281 dim 64 64 \, bang; +#X obj 548 228 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 548 256 metro 2000; +#X obj 374 583 3dp_draw square 8; +#X connect 0 0 1 0; +#X connect 0 1 8 1; +#X connect 1 0 8 0; +#X connect 2 0 0 0; +#X connect 2 0 28 0; +#X connect 3 0 2 0; +#X connect 4 0 30 0; +#X connect 5 0 41 1; +#X connect 6 0 41 2; +#X connect 7 0 34 0; +#X connect 8 0 7 0; +#X connect 9 0 31 1; +#X connect 10 0 9 0; +#X connect 11 0 12 0; +#X connect 12 0 13 0; +#X connect 13 0 41 0; +#X connect 14 0 11 1; +#X connect 15 0 12 1; +#X connect 16 0 13 1; +#X connect 17 0 14 0; +#X connect 17 0 15 0; +#X connect 17 0 16 0; +#X connect 18 1 11 0; +#X connect 20 0 14 1; +#X connect 20 0 15 1; +#X connect 20 0 16 1; +#X connect 21 0 30 0; +#X connect 22 0 38 0; +#X connect 23 0 4 0; +#X connect 24 0 21 0; +#X connect 25 0 2 1; +#X connect 26 0 30 1; +#X connect 27 0 2 1; +#X connect 28 0 23 0; +#X connect 29 0 28 1; +#X connect 30 0 5 0; +#X connect 31 0 18 0; +#X connect 31 1 17 0; +#X connect 33 0 4 0; +#X connect 34 0 31 0; +#X connect 36 0 4 0; +#X connect 38 0 21 0; +#X connect 39 0 40 0; +#X connect 40 0 21 0; diff --git a/opengl/doc/examples/example09.pd b/opengl/doc/examples/example09.pd new file mode 100644 index 0000000..3333d3a --- /dev/null +++ b/opengl/doc/examples/example09.pd @@ -0,0 +1,90 @@ +#N canvas 96 78 756 667 10; +#X obj 18 111 3dp_windowcontext; +#X obj 18 139 3dp_push; +#X obj 18 169 3dp_mouserotate; +#X floatatom 141 370 5 0 0; +#X msg 141 349 10; +#X obj 127 490 3dp_view rotx; +#X obj 127 537 3dp_view roty; +#X obj 127 585 3dp_view rotz; +#X obj 213 460 random 360; +#X obj 213 515 random 360; +#X obj 213 562 random 360; +#X obj 213 433 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 76 428 3dp_push; +#X floatatom 278 431 5 0 0; +#X obj 76 395 3dp_for 10; +#X obj 18 226 3dp_blend; +#X text 87 226 <-- click for more info; +#X obj 18 365 3dp_color; +#X floatatom 32 311 5 0 0; +#X floatatom 78 311 5 0 0; +#X floatatom 123 311 5 0 0; +#X floatatom 167 311 5 0 0; +#X obj 415 193 3dp_view transz 5; +#X obj 415 217 3dp_light; +#X obj 18 78 metro 40; +#X obj 18 50 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X floatatom 529 166 5 0 0; +#X obj 32 252 vsl 15 50 0 1 0 1 empty empty empty 0 -8 0 8 -262144 +-1 -1 2200 1; +#X obj 78 251 vsl 15 50 0 1 0 1 empty empty empty 0 -8 0 8 -262144 +-1 -1 2100 1; +#X obj 123 251 vsl 15 50 0 1 0 1 empty empty empty 0 -8 0 8 -262144 +-1 -1 3800 1; +#X obj 169 250 vsl 15 50 0 1 0 1 empty empty empty 0 -8 0 8 -262144 +-1 -1 1100 1; +#X text 209 275 in this blending mode \, alpha is interpreted as a +color gain; +#X floatatom 515 137 5 0 0; +#X floatatom 144 178 5 0 0; +#X obj 127 633 3dp_draw tetra 4; +#X text 14 13 similar to as example08.; +#X obj 415 168 3dp_view roty 5; +#X obj 18 199 3dp_view scale 4; +#X msg 278 406 18; +#X msg 515 112 75; +#X connect 0 0 1 0; +#X connect 0 1 2 1; +#X connect 1 0 2 0; +#X connect 1 1 36 0; +#X connect 2 0 37 0; +#X connect 3 0 14 1; +#X connect 4 0 3 0; +#X connect 5 0 6 0; +#X connect 6 0 7 0; +#X connect 7 0 34 0; +#X connect 8 0 5 1; +#X connect 9 0 6 1; +#X connect 10 0 7 1; +#X connect 11 0 8 0; +#X connect 11 0 9 0; +#X connect 11 0 10 0; +#X connect 12 1 5 0; +#X connect 13 0 8 1; +#X connect 13 0 9 1; +#X connect 13 0 10 1; +#X connect 14 0 12 0; +#X connect 14 1 11 0; +#X connect 15 0 17 0; +#X connect 17 1 14 0; +#X connect 18 0 17 1; +#X connect 19 0 17 2; +#X connect 20 0 17 3; +#X connect 21 0 17 4; +#X connect 22 0 23 0; +#X connect 24 0 0 0; +#X connect 25 0 24 0; +#X connect 26 0 22 1; +#X connect 27 0 18 0; +#X connect 28 0 19 0; +#X connect 29 0 20 0; +#X connect 30 0 21 0; +#X connect 32 0 36 1; +#X connect 33 0 37 1; +#X connect 36 0 22 0; +#X connect 37 0 15 0; +#X connect 38 0 13 0; +#X connect 39 0 32 0; diff --git a/opengl/doc/examples/example10.pd b/opengl/doc/examples/example10.pd new file mode 100644 index 0000000..2216fb3 --- /dev/null +++ b/opengl/doc/examples/example10.pd @@ -0,0 +1,39 @@ +#N canvas 592 340 647 499 10; +#X obj 231 344 pdp_xv; +#X obj 54 72 metro 40; +#X obj 54 47 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 54 140 3dp_push; +#X obj 248 158 3dp_view transz 5; +#X floatatom 362 126 5 0 0; +#X obj 248 182 3dp_light 0; +#X obj 54 169 3dp_mouserotate; +#X obj 54 111 3dp_windowcontext; +#X obj 231 311 pdp_blur; +#X obj 285 291 hsl 128 15 0 1 0 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 8100 1; +#X text 104 7 connect 3dp and basic pdp image processing with 3dp_snap +; +#X text 105 26 3dp_snap defaults to texture packets \, but you can +specify the desired type as a creation argument; +#X obj 107 377 pdp_convert texture/*/*; +#X obj 54 412 3dp_draw cube 10; +#X text 247 233 <- specify packet type and capture area; +#X obj 54 200 3dp_draw cube 2; +#X obj 54 234 3dp_snap image/*/* 320 240; +#X connect 1 0 8 0; +#X connect 2 0 1 0; +#X connect 3 0 7 0; +#X connect 3 1 4 0; +#X connect 4 0 6 0; +#X connect 5 0 4 1; +#X connect 7 0 16 0; +#X connect 8 0 3 0; +#X connect 8 1 7 1; +#X connect 9 0 13 0; +#X connect 9 0 0 0; +#X connect 10 0 9 1; +#X connect 13 0 14 1; +#X connect 16 0 17 0; +#X connect 17 0 14 0; +#X connect 17 1 9 0; diff --git a/opengl/doc/examples/example11.pd b/opengl/doc/examples/example11.pd new file mode 100644 index 0000000..c902408 --- /dev/null +++ b/opengl/doc/examples/example11.pd @@ -0,0 +1,77 @@ +#N canvas 542 122 669 675 10; +#X obj 23 70 metro 40; +#X obj 23 40 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 23 517 3dp_mouserotate; +#X obj 171 520 3dp_light 0; +#X obj 23 444 3dp_push; +#X obj 171 492 3dp_view transz 5; +#X obj 23 112 3dp_windowcontext; +#X obj 205 311 3dp_snap; +#X obj 205 213 3dp_draw clear; +#X obj 23 406 3dp_draw clear; +#X obj 60 347 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 23 157 3dp_subcontext 64 64; +#X obj 23 380 spigot; +#X text 384 210 <- clear it; +#X text 380 309 <- snap to texture; +#X obj 205 261 3dp_view rota 1 1 0; +#X floatatom 333 236 5 0 0; +#X text 69 10 multipass rendering to texture using a subcontext (subwindow) +; +#X text 381 285 <- draw a wireframe sphere; +#X text 383 235 <- rotate around (1 \, 1 \, 0); +#X text 135 406 <- clear the window; +#X obj 205 286 3dp_draw wsphere 3 10 10; +#X obj 323 429 3dp_draw clear; +#X obj 323 405 3dp_view reset; +#X obj 323 507 3dp_draw wdodeca; +#X obj 323 532 3dp_snap; +#X obj 22 613 3dp_draw cube 10; +#X obj 360 348 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X obj 323 381 spigot; +#X text 381 346 <- enable/disable second pass; +#X text 87 345 <- enable/disable third pass; +#X text 443 404 <- reset context; +#X text 442 427 <- clear context; +#X text 442 507 <- draw wire dodecahedron; +#X text 441 532 <- snap to texture; +#X obj 323 483 3dp_view rota 1 1 0; +#X floatatom 451 458 5 0 0; +#X text 501 457 <- rotate around (1 \, 1 \, 0); +#X obj 23 562 3dp_draw cube 2; +#X text 204 142 NOTE: the part you use as a subcontext must be visible +for the texture snap to work.; +#X text 203 91 use the lower left 64x64 part of the window as a subcontext +(right outlet) the left outlet is a new full window context reset to +default.; +#X connect 0 0 6 0; +#X connect 1 0 0 0; +#X connect 2 0 38 0; +#X connect 4 0 2 0; +#X connect 4 1 5 0; +#X connect 5 0 3 0; +#X connect 6 0 11 0; +#X connect 6 1 2 1; +#X connect 7 0 28 0; +#X connect 7 1 38 1; +#X connect 8 0 15 0; +#X connect 9 0 4 0; +#X connect 10 0 12 1; +#X connect 11 0 12 0; +#X connect 11 1 8 0; +#X connect 12 0 9 0; +#X connect 15 0 21 0; +#X connect 16 0 15 4; +#X connect 21 0 7 0; +#X connect 22 0 35 0; +#X connect 23 0 22 0; +#X connect 24 0 25 0; +#X connect 25 1 26 1; +#X connect 27 0 28 1; +#X connect 28 0 23 0; +#X connect 35 0 24 0; +#X connect 36 0 35 4; +#X connect 38 0 26 0; diff --git a/opengl/doc/examples/example12.pd b/opengl/doc/examples/example12.pd new file mode 100644 index 0000000..14f8afd --- /dev/null +++ b/opengl/doc/examples/example12.pd @@ -0,0 +1,90 @@ +#N canvas 529 191 669 751 10; +#X obj 55 68 metro 40; +#X obj 55 38 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 55 515 3dp_mouserotate; +#X obj 184 514 3dp_light 0; +#X obj 55 442 3dp_push; +#X obj 184 486 3dp_view transz 5; +#X obj 55 110 3dp_windowcontext; +#X obj 343 481 3dp_snap; +#X obj 55 404 3dp_draw clear; +#X obj 436 272 3dp_light 0; +#X obj 436 244 3dp_view transxyz 5 5 0; +#X obj 285 226 3dp_push; +#X obj 343 449 3dp_draw sphere 7 10 10; +#X text 69 10 another multipass rendering example; +#X obj 55 576 3dp_draw cube 7; +#X obj 55 155 3dp_subcontext 256 256; +#X obj 285 260 3dp_mouserotate; +#X obj 343 413 3dp_draw icosa 1; +#X obj 285 342 3dp_color; +#X obj 343 387 3dp_view scale 1; +#X floatatom 450 358 5 0 0; +#N canvas 0 0 291 420 coord_to_color 0; +#X obj 97 85 route drag; +#X obj 97 147 *; +#X obj 134 146 *; +#X obj 97 174 +; +#X obj 97 281 sqrt; +#X obj 97 225 - 1; +#X obj 97 249 * -1; +#X obj 97 114 unpack 0 0; +#X obj 98 45 inlet; +#X obj 53 337 outlet; +#X obj 181 332 outlet; +#X obj 116 336 outlet; +#X connect 0 0 7 0; +#X connect 1 0 3 0; +#X connect 2 0 3 1; +#X connect 3 0 5 0; +#X connect 4 0 11 0; +#X connect 5 0 6 0; +#X connect 6 0 4 0; +#X connect 7 0 1 1; +#X connect 7 0 1 0; +#X connect 7 0 9 0; +#X connect 7 1 2 1; +#X connect 7 1 2 0; +#X connect 7 1 10 0; +#X connect 8 0 0 0; +#X restore 304 305 pd coord_to_color; +#X obj 453 337 hsl 128 15 1 3 0 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 7900 1; +#X obj 285 196 3dp_draw clear; +#X obj 92 622 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 55 662 3dp_screenshot /tmp/screenshot.png; +#X msg 227 71 dim 1023 768; +#X connect 0 0 6 0; +#X connect 1 0 0 0; +#X connect 2 0 14 0; +#X connect 4 0 2 0; +#X connect 4 1 5 0; +#X connect 5 0 3 0; +#X connect 6 0 15 0; +#X connect 6 1 2 1; +#X connect 6 1 21 0; +#X connect 6 1 16 1; +#X connect 7 1 12 1; +#X connect 7 1 14 1; +#X connect 8 0 4 0; +#X connect 10 0 9 0; +#X connect 11 0 16 0; +#X connect 11 1 10 0; +#X connect 12 0 7 0; +#X connect 14 0 25 0; +#X connect 15 0 8 0; +#X connect 15 1 23 0; +#X connect 16 0 18 0; +#X connect 17 0 12 0; +#X connect 18 1 19 0; +#X connect 19 0 17 0; +#X connect 20 0 19 1; +#X connect 21 0 18 1; +#X connect 21 1 18 2; +#X connect 21 2 18 3; +#X connect 22 0 20 0; +#X connect 23 0 11 0; +#X connect 24 0 25 0; +#X connect 26 0 6 0; diff --git a/opengl/doc/examples/example13.pd b/opengl/doc/examples/example13.pd new file mode 100644 index 0000000..a8c5f75 --- /dev/null +++ b/opengl/doc/examples/example13.pd @@ -0,0 +1,81 @@ +#N canvas 478 168 669 751 10; +#X obj 55 68 metro 40; +#X obj 55 38 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 55 110 3dp_windowcontext; +#X obj 262 479 3dp_snap; +#X obj 355 270 3dp_light 0; +#X obj 355 242 3dp_view transxyz 5 5 0; +#X obj 204 224 3dp_push; +#X obj 262 447 3dp_draw sphere 7 10 10; +#X obj 204 258 3dp_mouserotate; +#X obj 262 411 3dp_draw icosa 1; +#X obj 204 340 3dp_color; +#X obj 262 385 3dp_view scale 1; +#X floatatom 369 356 5 0 0; +#N canvas 0 0 291 420 coord_to_color 0; +#X obj 97 85 route drag; +#X obj 97 147 *; +#X obj 134 146 *; +#X obj 97 174 +; +#X obj 97 281 sqrt; +#X obj 97 225 - 1; +#X obj 97 249 * -1; +#X obj 97 114 unpack 0 0; +#X obj 98 45 inlet; +#X obj 53 337 outlet; +#X obj 181 332 outlet; +#X obj 116 336 outlet; +#X connect 0 0 7 0; +#X connect 1 0 3 0; +#X connect 2 0 3 1; +#X connect 3 0 5 0; +#X connect 4 0 11 0; +#X connect 5 0 6 0; +#X connect 6 0 4 0; +#X connect 7 0 1 1; +#X connect 7 0 1 0; +#X connect 7 0 9 0; +#X connect 7 1 2 1; +#X connect 7 1 2 0; +#X connect 7 1 10 0; +#X connect 8 0 0 0; +#X restore 223 303 pd coord_to_color; +#X obj 372 335 hsl 128 15 1 3 0 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 7900 1; +#X obj 204 194 3dp_draw clear; +#X text 209 658 <- stretch the texture to cover the entire window (click +for info); +#X text 119 13 fixed resolution processing (independent of the display +window size) using multipass rendering; +#X floatatom 210 631 5 0 0; +#X obj 55 658 3dp_display_texture; +#X text 338 480 <- snap the result to a texture; +#X text 228 154 <- create a subcontext to do some drawing; +#X text 402 76 see also; +#X obj 405 97 3dp_fixedsizewindowcontext 64 64; +#X obj 55 155 3dp_subcontext 320 240; +#X connect 0 0 2 0; +#X connect 1 0 0 0; +#X connect 2 0 24 0; +#X connect 2 1 13 0; +#X connect 2 1 8 1; +#X connect 3 1 7 1; +#X connect 3 1 19 1; +#X connect 5 0 4 0; +#X connect 6 0 8 0; +#X connect 6 1 5 0; +#X connect 7 0 3 0; +#X connect 8 0 10 0; +#X connect 9 0 7 0; +#X connect 10 1 11 0; +#X connect 11 0 9 0; +#X connect 12 0 11 1; +#X connect 13 0 10 1; +#X connect 13 1 10 2; +#X connect 13 2 10 3; +#X connect 14 0 12 0; +#X connect 15 0 6 0; +#X connect 18 0 19 2; +#X connect 24 0 19 0; +#X connect 24 1 15 0; diff --git a/opengl/doc/examples/example14.pd b/opengl/doc/examples/example14.pd new file mode 100644 index 0000000..fa0cabb --- /dev/null +++ b/opengl/doc/examples/example14.pd @@ -0,0 +1,66 @@ +#N canvas 586 145 669 674 10; +#X obj 67 71 3dp_windowcontext; +#X obj 67 46 metro 40; +#X obj 67 23 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X obj 67 155 3dp_blend; +#X obj 176 423 3dp_view transxyz; +#X msg 226 296 reset; +#X obj 197 374 *; +#X obj 304 375 *; +#X floatatom 320 347 5 0 0; +#X obj 274 154 vsl 15 30 0 1 0 1 empty empty empty 0 -8 0 8 -262144 +-1 -1 700 1; +#X obj 316 154 vsl 15 30 0 1 0 1 empty empty empty 0 -8 0 8 -262144 +-1 -1 1100 1; +#X obj 295 154 vsl 15 30 0 1 0 1 empty empty empty 0 -8 0 8 -262144 +-1 -1 1200 1; +#X obj 337 154 vsl 15 30 0 1 0 1 empty empty empty 0 -8 0 8 -262144 +-1 -1 400 1; +#X obj 125 253 3dp_push; +#X obj 67 95 3dp_mouserotate; +#X obj 67 124 3dp_view scale 1; +#X floatatom 206 99 5 0 0; +#X obj 209 79 hsl 128 15 0.2 5 1 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 7000 1; +#X obj 323 326 hsl 128 15 0.1 2 1 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 2100 1; +#X obj 67 187 3dp_color; +#X obj 226 223 route press3; +#X text 329 223 <- right click mouse to reset; +#X text 211 253 <- remove 3dp_push object to accumulate the translations +; +#X obj 197 326 randomwalk2D 100; +#X obj 125 224 3dp_for 100; +#X text 287 130 R G B I; +#X obj 176 460 3dp_draw cube 1; +#X text 227 13 using 3dp_for and the randomwalk2D abstraction to create +random walking blended cubes.; +#X connect 0 0 14 0; +#X connect 0 1 14 1; +#X connect 0 1 20 0; +#X connect 1 0 0 0; +#X connect 2 0 1 0; +#X connect 3 0 19 0; +#X connect 4 0 26 0; +#X connect 5 0 23 0; +#X connect 6 0 4 1; +#X connect 7 0 4 2; +#X connect 8 0 7 1; +#X connect 8 0 6 1; +#X connect 9 0 19 1; +#X connect 10 0 19 3; +#X connect 11 0 19 2; +#X connect 12 0 19 4; +#X connect 13 1 4 0; +#X connect 14 0 15 0; +#X connect 15 0 3 0; +#X connect 16 0 15 1; +#X connect 17 0 16 0; +#X connect 18 0 8 0; +#X connect 19 1 24 0; +#X connect 20 0 5 0; +#X connect 23 0 6 0; +#X connect 23 1 7 0; +#X connect 24 0 13 0; +#X connect 24 1 23 0; diff --git a/opengl/doc/examples/example15.pd b/opengl/doc/examples/example15.pd new file mode 100644 index 0000000..281c91a --- /dev/null +++ b/opengl/doc/examples/example15.pd @@ -0,0 +1,126 @@ +#N canvas 269 234 933 697 10; +#X obj 67 46 metro 40; +#X obj 67 23 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 67 224 3dp_blend; +#X obj 176 673 3dp_view transxyz; +#X msg 260 342 reset; +#X obj 197 497 *; +#X obj 304 498 *; +#X obj 272 218 vsl 15 30 0 1 0 1 empty empty empty 0 -8 0 8 -262144 +-1 -1 1000 1; +#X obj 314 218 vsl 15 30 0 1 0 1 empty empty empty 0 -8 0 8 -262144 +-1 -1 0 1; +#X obj 293 218 vsl 15 30 0 1 0 1 empty empty empty 0 -8 0 8 -262144 +-1 -1 100 1; +#X obj 335 218 vsl 15 30 0 1 0 1 empty empty empty 0 -8 0 8 -262144 +-1 -1 200 1; +#X obj 125 304 3dp_push; +#X obj 67 119 3dp_mouserotate; +#X obj 67 176 3dp_view scale 1; +#X floatatom 241 145 5 0 0 0 - - -; +#X obj 244 125 hsl 128 15 0.2 5 1 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 3800 1; +#X obj 523 456 hsl 128 15 0.01 2 1 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 7900 1; +#X obj 67 251 3dp_color; +#X obj 402 231 route press3; +#X text 211 304 <- remove 3dp_push object to accumulate the translations +; +#X obj 197 392 randomwalk2D 100; +#X obj 125 275 3dp_for 100; +#X text 285 185 R G B I; +#X obj 197 533 smoothupdate 100; +#X obj 304 567 smoothupdate 100; +#X obj 524 490 hsl 128 15 0.01 1 1 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 1300 1; +#X obj 67 93 3dp_push; +#X obj 476 111 3dp_view transz 5; +#X obj 476 171 3dp_light; +#X obj 219 351 s i; +#X obj 250 511 r i; +#X obj 357 543 r i; +#X obj 419 716 smoothupdate 100; +#X obj 472 692 r i; +#X obj 197 325 t f f b; +#X obj 419 639 random 100; +#X obj 419 662 - 50; +#X obj 529 675 hsl 128 15 0.01 1 1 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 600 1; +#X obj 419 688 / 10; +#X msg 418 424 reset; +#X obj 148 201 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 67 200 pdp_route; +#X obj 176 765 3dp_draw torus 1 2 5 5; +#X obj 176 709 pdp_route; +#X obj 265 711 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 194 741 3dp_draw cube 2; +#X text 315 344 <- reset random walk; +#X text 532 554 <- reset smoothed points to origin; +#X text 227 13 like example14 but with coordinate smoothing and lighting +; +#X text 505 246 <- route mouse buttons; +#X obj 481 265 route press2; +#X text 666 453 <- walk radius; +#X text 667 488 <- walk smoothing; +#X obj 67 70 3dp_fixedsizewindowcontext 320 240; +#X floatatom 199 250 5 0 0 0 - - -; +#X connect 0 0 53 0; +#X connect 1 0 0 0; +#X connect 2 0 17 0; +#X connect 3 0 43 0; +#X connect 4 0 20 0; +#X connect 5 0 23 0; +#X connect 6 0 24 0; +#X connect 7 0 17 1; +#X connect 8 0 17 3; +#X connect 9 0 17 2; +#X connect 10 0 17 4; +#X connect 11 1 3 0; +#X connect 12 0 13 0; +#X connect 13 0 41 0; +#X connect 14 0 13 1; +#X connect 15 0 14 0; +#X connect 16 0 6 1; +#X connect 16 0 5 1; +#X connect 17 1 21 0; +#X connect 18 0 4 0; +#X connect 18 1 50 0; +#X connect 20 0 5 0; +#X connect 20 1 6 0; +#X connect 21 0 11 0; +#X connect 21 1 34 0; +#X connect 23 0 3 1; +#X connect 24 0 3 2; +#X connect 25 0 23 2; +#X connect 25 0 24 2; +#X connect 26 0 12 0; +#X connect 26 1 27 0; +#X connect 27 0 28 0; +#X connect 30 0 23 1; +#X connect 31 0 24 1; +#X connect 32 0 3 3; +#X connect 33 0 32 1; +#X connect 34 0 20 0; +#X connect 34 1 29 0; +#X connect 34 2 35 0; +#X connect 35 0 36 0; +#X connect 36 0 38 0; +#X connect 37 0 32 2; +#X connect 38 0 32 0; +#X connect 39 0 23 0; +#X connect 39 0 24 0; +#X connect 39 0 32 0; +#X connect 40 0 41 1; +#X connect 41 0 2 0; +#X connect 41 1 17 0; +#X connect 43 0 42 0; +#X connect 43 1 45 0; +#X connect 44 0 43 1; +#X connect 50 0 39 0; +#X connect 53 0 26 0; +#X connect 53 1 12 1; +#X connect 53 1 18 0; +#X connect 54 0 21 1; diff --git a/opengl/doc/examples/example16.pd b/opengl/doc/examples/example16.pd new file mode 100644 index 0000000..e9495aa --- /dev/null +++ b/opengl/doc/examples/example16.pd @@ -0,0 +1,107 @@ +#N canvas 196 0 772 525 10; +#X obj 57 25 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 57 153 3dp_blend; +#X floatatom 101 237 5 0 0 0 - - -; +#X floatatom 149 237 5 0 0 0 - - -; +#X floatatom 199 236 5 0 0 0 - - -; +#X floatatom 247 236 5 0 0 0 - - -; +#X obj 167 364 3dp_push; +#X obj 218 434 3dp_view transxyz; +#X msg 276 354 normal; +#X obj 422 255 f; +#X floatatom 484 264 5 0 0 0 - - -; +#X msg 422 220 0; +#X obj 57 177 pdp_t p b; +#X obj 392 185 t b b; +#X msg 591 238 0.2; +#X msg 484 239 0; +#X obj 57 72 3dp_windowcontext; +#X obj 392 112 route press3; +#X obj 57 49 metro 40; +#X obj 167 328 3dp_for 100; +#X obj 227 125 3dp_view transz 5; +#X obj 227 159 3dp_light; +#X obj 57 96 3dp_push; +#X obj 422 289 + 0.2; +#X obj 497 112 loadbang; +#X msg 519 238 0.01; +#N canvas 0 0 577 190 coordinates 0; +#X obj 51 100 *; +#X obj 51 72 elbat 100; +#X obj 165 99 *; +#X obj 165 71 elbat 100; +#X obj 276 97 *; +#X obj 276 69 elbat 100; +#X obj 51 19 inlet; +#X obj 125 18 inlet; +#X text 354 69 <- table read abstraction; +#X obj 51 130 outlet; +#X obj 165 127 outlet; +#X obj 276 125 outlet; +#X connect 0 0 9 0; +#X connect 1 0 0 0; +#X connect 2 0 10 0; +#X connect 3 0 2 0; +#X connect 4 0 11 0; +#X connect 5 0 4 0; +#X connect 6 0 1 0; +#X connect 6 0 3 0; +#X connect 6 0 5 0; +#X connect 7 0 0 1; +#X connect 7 0 2 1; +#X connect 7 0 4 1; +#X restore 239 403 pd coordinates; +#X msg 392 136 bang; +#X text 459 219 <- reset scaling to 0 (infinite density); +#X text 469 290 <- increment scaling for each new frame; +#X text 340 354 <- compute a new normal distributed set of points; +#X text 506 371 (velocity vectors); +#X text 545 264 <- diffusion speed; +#X msg 559 238 0.1; +#X text 182 12 explosion using 100 spheres with normal distributed +velocity vectors; +#X floatatom 367 441 5 0 0 0 - - -; +#X obj 57 125 3dp_mouserotate; +#X obj 57 278 3dp_color 0.1 0.1 0.1 0.27; +#X obj 218 478 3dp_draw sphere 1 8 8; +#X connect 0 0 18 0; +#X connect 1 0 12 0; +#X connect 2 0 37 1; +#X connect 3 0 37 2; +#X connect 4 0 37 3; +#X connect 5 0 37 4; +#X connect 6 1 7 0; +#X connect 7 0 38 0; +#X connect 8 0 26 0; +#X connect 9 0 23 0; +#X connect 10 0 23 1; +#X connect 11 0 9 0; +#X connect 12 0 37 0; +#X connect 12 1 9 0; +#X connect 13 0 8 0; +#X connect 13 1 11 0; +#X connect 14 0 10 0; +#X connect 15 0 10 0; +#X connect 16 0 22 0; +#X connect 16 1 17 0; +#X connect 16 1 36 1; +#X connect 17 0 27 0; +#X connect 18 0 16 0; +#X connect 19 0 6 0; +#X connect 19 1 26 0; +#X connect 20 0 21 0; +#X connect 22 0 36 0; +#X connect 22 1 20 0; +#X connect 23 0 9 1; +#X connect 23 0 26 1; +#X connect 24 0 13 0; +#X connect 25 0 10 0; +#X connect 26 0 7 1; +#X connect 26 1 7 2; +#X connect 26 2 7 3; +#X connect 27 0 13 0; +#X connect 33 0 10 0; +#X connect 35 0 38 2; +#X connect 36 0 1 0; +#X connect 37 1 19 0; diff --git a/opengl/doc/objects/3dp_for.pd b/opengl/doc/objects/3dp_for.pd new file mode 100644 index 0000000..ccaf22d --- /dev/null +++ b/opengl/doc/objects/3dp_for.pd @@ -0,0 +1,91 @@ +#N canvas 545 167 607 718 10; +#X obj 22 40 3dp_windowcontext; +#X obj 22 15 metro 40; +#X obj 22 -5 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 22 67 3dp_push; +#X obj 180 126 3dp_light; +#X floatatom 301 85 5 0 0 0 - - -; +#X obj 22 97 3dp_mouserotate; +#X floatatom 151 228 5 0 0 0 - - -; +#X obj 180 104 3dp_view transz 10; +#X floatatom 81 165 5 0 0 0 - - -; +#X obj 23 191 3dp_for 3; +#X obj 23 251 3dp_view transx 1.5; +#X floatatom 130 280 5 0 0 0 - - -; +#X obj 23 302 3dp_view roty 45; +#X obj 23 389 3dp_draw sphere 1; +#X obj 81 365 + 1; +#X obj 81 343 *; +#X floatatom 129 327 5 0 0 0 - - -; +#X text 135 159 3dp_for sends a rendering context trough a chain multiple +times. the second outlet is the current number \, starting from zero +\, and can be used to change the parameters parameters of the chain. +(i.e. by reading from a table); +#X text 222 252 all the geometry operations are accumulative \,; +#X text 222 266 if you don't want that \, insert a 3dp_push object: +; +#X obj 314 313 3dp_for 3; +#X obj 314 336 3dp_push; +#X obj 365 400 3dp_draw cube 0.5; +#X obj 23 140 3dp_push; +#X obj 365 374 3dp_view transy; +#X obj 465 343 * 1; +#X floatatom 481 319 5 0 0 0 - - -; +#X obj 86 569 pdp_t p p p; +#X obj 86 606 3dp_view transy 1; +#X obj 86 630 3dp_draw cube 0.5; +#X obj 177 465 3dp_for 3; +#X text 72 492 so \, in short \,; +#X text 313 492 is equivalent to; +#X obj 177 491 3dp_view transy 1; +#X obj 177 515 3dp_draw cube 0.5; +#X obj 354 539 3dp_view transy 1; +#X obj 354 563 3dp_draw cube 0.5; +#X obj 354 589 3dp_view transy 1; +#X obj 354 613 3dp_draw cube 0.5; +#X obj 354 638 3dp_view transy 1; +#X obj 354 662 3dp_draw cube 0.5; +#X text 256 596 and; +#X obj 180 84 3dp_view roty; +#X floatatom 266 66 5 0 0 0 - - -; +#X connect 0 0 3 0; +#X connect 0 1 6 1; +#X connect 1 0 0 0; +#X connect 2 0 1 0; +#X connect 3 0 6 0; +#X connect 3 1 43 0; +#X connect 5 0 8 1; +#X connect 6 0 24 0; +#X connect 7 0 11 1; +#X connect 8 0 4 0; +#X connect 9 0 10 1; +#X connect 10 0 11 0; +#X connect 10 1 16 0; +#X connect 11 0 13 0; +#X connect 12 0 13 1; +#X connect 13 0 14 0; +#X connect 15 0 14 2; +#X connect 16 0 15 0; +#X connect 17 0 16 1; +#X connect 21 0 22 0; +#X connect 21 1 26 0; +#X connect 22 1 25 0; +#X connect 24 0 10 0; +#X connect 24 1 21 0; +#X connect 25 0 23 0; +#X connect 26 0 25 1; +#X connect 27 0 26 1; +#X connect 28 0 29 0; +#X connect 28 1 29 0; +#X connect 28 2 29 0; +#X connect 29 0 30 0; +#X connect 31 0 34 0; +#X connect 34 0 35 0; +#X connect 36 0 37 0; +#X connect 37 0 38 0; +#X connect 38 0 39 0; +#X connect 39 0 40 0; +#X connect 40 0 41 0; +#X connect 43 0 8 0; +#X connect 44 0 43 1; diff --git a/opengl/include/Makefile b/opengl/include/Makefile new file mode 100644 index 0000000..f2075ee --- /dev/null +++ b/opengl/include/Makefile @@ -0,0 +1,5 @@ +all: + +clean: + rm -rf *~ + diff --git a/opengl/include/pdp_3Dcontext.h b/opengl/include/pdp_3Dcontext.h new file mode 100644 index 0000000..adef304 --- /dev/null +++ b/opengl/include/pdp_3Dcontext.h @@ -0,0 +1,94 @@ +/* + * pdp system module - 3d render context packet type + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +/* the 3d render context packet: platform independent data structure + and method prototypes */ + + +#ifndef PDP_3DCONTEXT_H +#define PDP_3DCONTEXT_H + +#include "pdp.h" + + + + +typedef struct _3dcontext +{ + u32 encoding; /* the kind of render context */ + u32 width; /* context width */ + u32 height; /* context height */ + u32 sub_width; /* portion that is currently used */ + u32 sub_height; + void *drawable; /* context's drawable (i.e. Window, GLXPbuffer, ...) */ + void *context; /* context's context object */ + +} t_3Dcontext; + +#define PDP_3DCONTEXT 5 /* 3d context packet id */ +#define PDP_3DCONTEXT_WINDOW 1 /* window context packet id */ +#define PDP_3DCONTEXT_PBUFFER 2 /* pbuf context packet id */ + +/* all symbols are C-style */ +#ifdef __cplusplus +extern "C" +{ +#endif + + /* info methods */ + u32 pdp_packet_3Dcontext_width(int packet); + u32 pdp_packet_3Dcontext_subwidth(int packet); + u32 pdp_packet_3Dcontext_height(int packet); + u32 pdp_packet_3Dcontext_subheight(int packet); + float pdp_packet_3Dcontext_subaspect(int packet); + int pdp_packet_3Dcontext_isvalid(int packet); + t_3Dcontext *pdp_packet_3Dcontext_info(int packet); + + + /* setters */ + void pdp_packet_3Dcontext_set_subwidth(int packet, u32 w); + void pdp_packet_3Dcontext_set_subheight(int packet, u32 h); + + + /* render context activation and initialization */ + void pdp_packet_3Dcontext_set_rendering_context(int packet); + void pdp_packet_3Dcontext_unset_rendering_context(int packet); + void pdp_packet_3Dcontext_setup_3d_context(int p); + void pdp_packet_3Dcontext_setup_2d_context(int p); + + /* constructors */ + int pdp_packet_new_3Dcontext_pbuf(u32 width, u32 height, u32 depth); + int pdp_packet_new_3Dcontext_win(void); + + /* window specific methods */ + void pdp_packet_3Dcontext_win_resize(int packet, int width, int height); + t_pdp_list *pdp_packet_3Dcontext_win_get_eventlist(int packet); + void pdp_packet_3Dcontext_win_cursor(int packet, bool toggle); + void pdp_packet_3Dcontext_win_swapbuffers(int packet); + + /* converters */ + int pdp_packet_3Dcontext_snap_to_bitmap(int packet, int w, int h); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/opengl/include/pdp_3dp_base.h b/opengl/include/pdp_3dp_base.h new file mode 100644 index 0000000..16d5013 --- /dev/null +++ b/opengl/include/pdp_3dp_base.h @@ -0,0 +1,36 @@ +#include "pdp_opengl.h" +#include "pdp_dpd_base.h" + + +typedef struct _pdp_3dp_base +{ + t_pdp_dpd_base b_base; + +} t_pdp_3dp_base; + +/* destructor */ +void pdp_3dp_base_free(void *x); + +/* init method */ +void pdp_3dp_base_init(void *x); + +/* class setup method */ +void pdp_3dp_base_setup(t_class *class); + + +/* base class methods */ +#define pdp_3dp_base_get_context_packet pdp_dpd_base_get_context_packet +#define pdp_3dp_base_set_context_packet pdp_dpd_base_set_context_packet +#define pdp_3dp_base_add_outlet pdp_dpd_base_add_outlet +#define pdp_3dp_base_add_cleanup pdp_dpd_base_add_cleanup +#define pdp_3dp_base_add_inspect pdp_dpd_base_add_inspect +#define pdp_3dp_base_disable_active_inlet pdp_dpd_base_disable_active_inlet +#define pdp_3dp_base_move_context_packet pdp_dpd_base_move_context_packet +#define pdp_3dp_base_bang pdp_dpd_base_bang +#define pdp_3dp_base_get_queue pdp_dpd_base_get_queue +#define pdp_3dp_base_enable_outlet pdp_dpd_base_enable_outlet +#define pdp_3dp_base_register_complete_notify pdp_dpd_base_register_complete_notify +#define pdp_3dp_base_register_get_command_object pdp_dpd_base_register_get_command_object +#define pdp_3dp_base_queue_wait pdp_dpd_base_queue_wait +#define pdp_3dp_base_queue_command pdp_dpd_base_queue_command + diff --git a/opengl/include/pdp_mesh.h b/opengl/include/pdp_mesh.h new file mode 100644 index 0000000..8fd6dff --- /dev/null +++ b/opengl/include/pdp_mesh.h @@ -0,0 +1,210 @@ +/* + * Pure Data Packet module. mesh object specification + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +/* a very naive approach to triangular meshes */ + +#ifndef PDP_MESH_H +#define PDP_MESH_H +#include "pdp_list.h" + + +/* VERTEX type + a vertex has a coordinate and normal vector + a list of triangles it is connected to + and a list of vertexes it is connected to (these count as links) */ + +typedef struct _vertex +{ + float c[3]; // coordinates + float n[3]; // normal (or force vector) + t_pdp_list *trilist; + t_pdp_list *vertlist; +} t_vertex; + + +/* TRIANGLE type: + a triangle consist of + - 3 vertices + - 3 optional median vertices (subdivision intermediates) */ +typedef struct _triangle +{ + t_vertex *v[3]; // vertices + t_vertex *m[3]; // median vertices + float n[3]; //triangle normal +} t_triangle; + + +/* MESH type: + a mesh is a list of vertices + and a list of triangles (connections) */ +typedef struct _mesh +{ + t_pdp_list *triangles; + t_pdp_list *vertices; + int normal_type; + int refine_type; +} t_mesh; + + + +/* object configuratie */ +#define MESH_NORMAL_SPHERE 1 // normal = origin -> vertex +#define MESH_NORMAL_PRISM 2 // normal = center of gravity of prism base -> vertex +#define MESH_NORMAL_RANDOM 3 // normal = random vector +#define MESH_NORMAL_AVERAGE 4 // normal = average of surrounding triangles + +/* refinement method */ +#define MESH_REFINE_THREE 1 // triangle -> 3 triangles connecting center of gravity +#define MESH_REFINE_FOUR 2 // triangle -> 4 triangles connecting link medians + +// vector utility stuff + +// fixed size iterators for the lazy +#define I3(i) for(i=0; i<3; i++) +#define I4(i) for(i=0; i<4; i++) + +static inline float _vector3_dot(float *v0, float *v1) +{ + float d; + d = v0[0] * v1[0]; + d += v0[1] * v1[1]; + d += v0[2] * v1[2]; + return d; +} + +static inline void _vector3_scale(float *v, float s) +{ + int k; + I3(k) v[k] *= s; +} + +static inline float _vector3_normalize(float *v) +{ + float length = 0; + float scale = 0; + int k; + length = sqrt(_vector3_dot(v,v)); + scale = 1.0f / length; + _vector3_scale(v, scale); + return length; +} + +static inline void _vector3_cross(float *a, float *b, float *r) +{ + r[0] = a[1]*b[2] - a[2]*b[1]; + r[1] = a[2]*b[0] - a[0]*b[2]; + r[2] = a[0]*b[1] - a[1]*b[0]; +} + +static inline float _rand(void) +{ + long int r = random(); + float f; + r -= (RAND_MAX >> 1); + f = (float)r; + f *= (2.0f / (float)RAND_MAX); + return f; +} + + + + +/* VERTEX methods */ +void vertex_add_triangle(t_vertex *v, t_triangle *t); +void vertex_remove_triangle(t_vertex *v, t_triangle *t); +void vertex_add_neighbour(t_vertex *v, t_vertex *neighbour); + + +/* constructor/destructors are "private" + they may only be called by the mesh object to ensure + the vector list stays sound (i.e. without duplicates) */ +void _vertex_free(t_vertex *v); +t_vertex *_vertex_new(float *c, float *n); + + +void vertex_compute_normal_random(t_vertex *v); +void vertex_compute_normal_sphere(t_vertex *v); +void vertex_compute_normal_prism(t_vertex *v); +float vertex_normalize(t_vertex *v); + + +/* TRIANGLE methods */ + +/* create triangle (a connection between 3 vertices): + counterclockwize with facing front + this method is "private" + you can only create triangles as part of a mesh */ +t_triangle *_triangle_new(t_vertex *v0, t_vertex *v1, t_vertex *v2); + +/* delete a triangle, disconnecting the vertices */ +void _triangle_free(t_triangle *t); + +/* get triangle that shares the link between v0 and v1 */ +t_triangle *triangle_neighbour(t_triangle *t, t_vertex *v0, t_vertex *v1); + +/* add a median vector to a link in a triangle + note: vertices must be in triangle, or behaviour is undefined */ +void triangle_add_median(t_triangle *t, t_vertex *v0, t_vertex *v1, t_vertex *median); + +/* MESH methods */ + +/* add and remove methods for vertices and triangles */ +t_vertex *mesh_vertex_add(t_mesh *m, float *c, float *n); +void mesh_vertex_remove(t_mesh *m, t_vertex *v); +t_triangle *mesh_triangle_add(t_mesh *m, t_vertex *v0, t_vertex *v1, t_vertex *v2); +void mesh_triangle_remove(t_mesh *m, t_triangle *t); + +/* calculate normals */ +void mesh_calculate_normals(t_mesh *m); + +/* split a triangle in 4, using the intermedia median vertex storage */ +void mesh_split_four(t_mesh *m, t_triangle *old_t); + +/* split a triangle in 3 */ +void mesh_split_three(t_mesh *m, t_triangle *old_t); + +void mesh_split_all_four(t_mesh *m); + +void mesh_split_all_three(t_mesh *m); + +void mesh_split_random_three(t_mesh *m); + +void mesh_free(t_mesh *m); + +t_mesh *_mesh_new(void); + +/* new tetra */ +t_mesh *mesh_new_tetra(void); + + + +void _mesh_relax_compute_resultant_spring(t_mesh *m, float *center, float d0, float r0); +void _mesh_relax_apply_force(t_mesh *m, float k); +void mesh_compute_center(t_mesh *m, float *c); +void mesh_translate(t_mesh *m, float *c); + +/* relax a mesh (move toward equal link length) */ +void mesh_relax(t_mesh *m, float step, float d0, float r0); + +/* print some debug information */ +void mesh_debug(t_mesh *m); + + +#endif diff --git a/opengl/include/pdp_opengl.h b/opengl/include/pdp_opengl.h new file mode 100644 index 0000000..c32735d --- /dev/null +++ b/opengl/include/pdp_opengl.h @@ -0,0 +1,33 @@ +/* + * OpenGL Extension Module for pdp - Main header file + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +#ifndef PDP_OPENGL_H +#define PDP_OPENGL_H + + + +#include "pdp.h" +#include "pdp_texture.h" +#include "pdp_3Dcontext.h" + +t_pdp_procqueue* pdp_opengl_get_queue(void); + + +#endif diff --git a/opengl/include/pdp_texture.h b/opengl/include/pdp_texture.h new file mode 100644 index 0000000..7a40cdd --- /dev/null +++ b/opengl/include/pdp_texture.h @@ -0,0 +1,93 @@ +/* + * pdp system module - texture packet type + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +#ifndef PDP_TEXTURE_H +#define PDP_TEXTURE_H + +//#include <GL/gl.h> +//#include <GL/glu.h> +//#include <GL/glx.h> +//#include <GL/glut.h> +#include "pdp.h" + + + + + +/* TEXTURE PACKET */ + +typedef struct +{ + u32 tex_obj; /* gl texture object */ + s32 format; /* texture format */ + u32 width; /* dims */ + u32 height; + + u32 sub_width; /* portion of texture used */ + u32 sub_height; + +} t_texture; + +#define PDP_TEXTURE 4 /* opengl texture object */ + + +/* all symbols are C-style */ +#ifdef __cplusplus +extern "C" +{ +#endif + + +/* check if valid texture packet. all other methods assume packet is valid */ +bool pdp_packet_texture_isvalid(int packet); + +/* returns a pointer to the packet subheader whem the packet contains a texture */ +/* try not to use the header directly, use clone and copy methods instead */ +t_texture *pdp_packet_texture_info(int packet); + +/* texture constructors */ +int pdp_packet_new_texture(u32 width, u32 height, s32 format); /* create a texture packet */ + + +/* texture operators */ +void pdp_packet_texture_make_current(int packet); /* make a texture the current texture context */ +u32 pdp_packet_texture_total_width(int packet); /* width of texture */ +u32 pdp_packet_texture_total_height(int packet); /* get heigth of texture */ +u32 pdp_packet_texture_sub_width(int packet); /* width of subtexture */ +u32 pdp_packet_texture_sub_height(int packet); /* heigth of subtexture */ +float pdp_packet_texture_fracx(int packet); /* x fraction */ +float pdp_packet_texture_fracy(int packet); /* y fraction */ +float pdp_packet_texture_sub_aspect(int packet); + +/* some utility methods */ +void pdp_packet_texture_make_current_enable(int packet); /* make current & enable with default texture settings (for the lazy)*/ +void pdp_packet_texture_setup_2d_context(int packet); /* set up 2d context (viewport, projection, modelview) from texture dims */ + + + + + + + +#ifdef __cplusplus +} +#endif + +#endif //PDP_TEXTURE_H diff --git a/opengl/modules/Makefile b/opengl/modules/Makefile new file mode 100644 index 0000000..a11fa1d --- /dev/null +++ b/opengl/modules/Makefile @@ -0,0 +1,10 @@ +include ../Makefile.config + +all: pdp_3d_windowcontext.o pdp_3d_draw.o pdp_3d_view.o \ + pdp_3d_push.o pdp_3d_light.o pdp_3d_dlist.o pdp_3d_color.o \ + pdp_3d_snap.o pdp_3d_drawmesh.o pdp_3d_for.o pdp_3d_state.o \ + pdp_3d_subcontext.o + +clean: + rm -rf *~ *.o + diff --git a/opengl/modules/README b/opengl/modules/README new file mode 100644 index 0000000..613661e --- /dev/null +++ b/opengl/modules/README @@ -0,0 +1,3 @@ + +This directory contains opengl modules for the pdp_opengl library. + diff --git a/opengl/modules/pdp_3d_color.c b/opengl/modules/pdp_3d_color.c new file mode 100644 index 0000000..b237e9a --- /dev/null +++ b/opengl/modules/pdp_3d_color.c @@ -0,0 +1,167 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +#include <GL/gl.h> +#include "pdp_3dp_base.h" +#include "pdp_opengl.h" + + +typedef struct _color_command +{ + t_pdp_dpd_command x_base; + int x_context; + float x_newcolor[4]; + float x_oldcolor[4]; +} t_color_command; + +typedef struct _pdp_3d_color +{ + t_pdp_3dp_base x_base; + t_pdp_dpd_commandfactory x_cfact; + + float x_red; + float x_green; + float x_blue; + float x_alpha; + +} t_pdp_3d_color; + + + +/* COMMAND METHODS */ +static void pdp_3d_color_process_right(t_color_command *x) +{ + int p = x->x_context; + if (pdp_packet_3Dcontext_isvalid(p)){ + pdp_packet_3Dcontext_set_rendering_context(p); + + /* save old color*/ + glGetFloatv(GL_CURRENT_COLOR, x->x_oldcolor); + + /* set new color */ + glColor4fv(x->x_newcolor); + } + +} + +static void pdp_3d_color_process_left(t_color_command *x) +{ + int p = x->x_context; + if (pdp_packet_3Dcontext_isvalid(p)){ + pdp_packet_3Dcontext_set_rendering_context(p); + + /* restore old color */ + glColor4fv(x->x_oldcolor); + //glColor4f(1,1,1,1); + } + /* kill self */ + pdp_dpd_command_suicide(x); +} + + +/* PD OBJECT METHODS */ +static void *pdp_3d_color_get_new_command(t_pdp_3d_color *x) +{ + t_color_command *c = (t_color_command *)pdp_dpd_commandfactory_get_new_command(&x->x_cfact); + c->x_newcolor[0] = x->x_red; + c->x_newcolor[1] = x->x_green; + c->x_newcolor[2] = x->x_blue; + c->x_newcolor[3] = x->x_alpha; + c->x_context = pdp_3dp_base_get_context_packet(x); + return (void *)c; +} + + +static void pdp_3d_color_set_r(t_pdp_3d_color *x, t_floatarg f) {x->x_red = f;} +static void pdp_3d_color_set_g(t_pdp_3d_color *x, t_floatarg f) {x->x_green = f;} +static void pdp_3d_color_set_b(t_pdp_3d_color *x, t_floatarg f) {x->x_blue = f;} +static void pdp_3d_color_set_a(t_pdp_3d_color *x, t_floatarg f) {x->x_alpha = f;} + + +t_class *pdp_3d_color_class; + + +void pdp_3d_color_free(t_pdp_3d_color *x) +{ + pdp_3dp_base_free(x); +} + +void *pdp_3d_color_new(t_floatarg r, t_floatarg g, t_floatarg b, t_floatarg a) +{ + t_pdp_3d_color *x = (t_pdp_3d_color *)pd_new(pdp_3d_color_class); + + /* super init */ + pdp_3dp_base_init(x); + + + /* input */ + pdp_base_add_gen_inlet(x, gensym("float"), gensym("r")); + pdp_base_add_gen_inlet(x, gensym("float"), gensym("g")); + pdp_base_add_gen_inlet(x, gensym("float"), gensym("b")); + pdp_base_add_gen_inlet(x, gensym("float"), gensym("a")); + + /* output */ + pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_color_process_left, 0); + pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_color_process_right, 0); + + x->x_red = r; + x->x_green = g; + x->x_blue = b; + x->x_alpha = a; + + /* init factory */ + pdp_dpd_commandfactory_init(&x->x_cfact, sizeof(t_color_command)); + + /* register command factory method */ + pdp_dpd_base_register_command_factory_method(x, (t_pdp_newmethod)pdp_3d_color_get_new_command); + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_3d_color_setup(void) +{ + + + pdp_3d_color_class = class_new(gensym("3dp_color"), (t_newmethod)pdp_3d_color_new, + (t_method)pdp_3d_color_free, sizeof(t_pdp_3d_color), 0, + A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_NULL); + + + pdp_3dp_base_setup(pdp_3d_color_class); + + class_addmethod(pdp_3d_color_class, (t_method)pdp_3d_color_set_r, gensym("r"), A_FLOAT, A_NULL); + class_addmethod(pdp_3d_color_class, (t_method)pdp_3d_color_set_g, gensym("g"), A_FLOAT, A_NULL); + class_addmethod(pdp_3d_color_class, (t_method)pdp_3d_color_set_b, gensym("b"), A_FLOAT, A_NULL); + class_addmethod(pdp_3d_color_class, (t_method)pdp_3d_color_set_a, gensym("a"), A_FLOAT, A_NULL); + + +} + +#ifdef __cplusplus +} +#endif diff --git a/opengl/modules/pdp_3d_context.c b/opengl/modules/pdp_3d_context.c new file mode 100644 index 0000000..9e9c08f --- /dev/null +++ b/opengl/modules/pdp_3d_context.c @@ -0,0 +1,163 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp.h" +#include "pdp_base.h" +#include "pdp_opengl.h" + + +typedef struct pdp_3d_context_struct +{ + t_pdp_base x_base; + + t_outlet *x_outlet0; + + int x_packet0; + + t_symbol *x_type; + + unsigned int x_width; + unsigned int x_height; + + void *x_constant; + +} t_pdp_3d_context; + + + + + +static void pdp_3d_context_preproc(t_pdp_3d_context *x) +{ + int p; + int i; + + /* create new packet */ + p = pdp_packet_new_pbuf(x->x_width, x->x_height, 0); + x->x_packet0 = p; + + if (-1 == p) return; + + pdp_pbuf_set_rendering_context(p); + pdp_pbuf_setup_3d_context(p); + + /* clear buffer */ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); + glEnable(GL_AUTO_NORMAL); + glEnable(GL_NORMALIZE); + glShadeModel(GL_SMOOTH); + + + /* disable everything that is enabled in other modules */ + glDisable(GL_LIGHTING); + for (i=0; i<8; i++) glDisable(GL_LIGHT0 + i); + glDisable(GL_COLOR_MATERIAL); + + +} + +static void pdp_3d_context_process(t_pdp_3d_context *x) +{ +} + +static void pdp_3d_context_postproc(t_pdp_3d_context *x) +{ + pdp_pass_if_valid(x->x_outlet0, &x->x_packet0); +} + +static void pdp_3d_context_bang(t_pdp_3d_context *x) +{ + pdp_base_bang(x); +} + +static void pdp_3d_context_dim(t_pdp_3d_context *x, t_floatarg w, t_floatarg h) +{ + x->x_width = pdp_imageproc_legalwidth((int)w); + x->x_height = pdp_imageproc_legalheight((int)h); + //post("dims %d %d", x->x_width, x->x_height); +} + + +static void pdp_3d_context_free(t_pdp_3d_context *x) +{ + pdp_base_free(x); + pdp_packet_mark_unused(x->x_packet0); + +} + +t_class *pdp_3d_context_class; + + + +void *pdp_3d_context_new(void) +{ + int i; + t_pdp_3d_context *x = (t_pdp_3d_context *)pd_new(pdp_3d_context_class); + + /* super init */ + pdp_base_init(x); + + /* in/out*/ + x->x_outlet0 = pdp_base_add_pdp_outlet(x); + + /* base callbacks */ + pdp_base_disable_active_inlet(x); + pdp_base_set_process_method(x, (t_pdp_method)pdp_3d_context_process); + pdp_base_set_preproc_method(x, (t_pdp_method)pdp_3d_context_preproc); + pdp_base_set_postproc_method(x, (t_pdp_method)pdp_3d_context_postproc); + + /* data init */ + x->x_packet0 = -1; + pdp_3d_context_dim(x, 320, 240); + + + return (void *)x; +} + + + +#ifdef __cplusplus +extern "C" +{ +#endif + + + +void pdp_3d_context_setup(void) +{ + + + pdp_3d_context_class = class_new(gensym("pdp_3d_context"), (t_newmethod)pdp_3d_context_new, + (t_method)pdp_3d_context_free, sizeof(t_pdp_3d_context), 0, A_NULL); + class_addcreator((t_newmethod)pdp_3d_context_new, gensym("3dp_context"), A_NULL); + + pdp_base_setup(pdp_3d_context_class); + + class_addmethod(pdp_3d_context_class, (t_method)pdp_3d_context_dim, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_3d_context_class, (t_method)pdp_3d_context_bang, gensym("bang"), A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/opengl/modules/pdp_3d_dlist.c b/opengl/modules/pdp_3d_dlist.c new file mode 100644 index 0000000..9f087e0 --- /dev/null +++ b/opengl/modules/pdp_3d_dlist.c @@ -0,0 +1,183 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +#include <GL/gl.h> + +#include "pdp_opengl.h" +#include "pdp_3dp_base.h" + +/* gl display list compilation & execution */ + +typedef struct pdp_3d_dlist_struct +{ + t_pdp_3dp_base x_base; + + GLuint x_dlist; + int x_compile; + +} t_pdp_3d_dlist; + + + +static void pdp_3d_dlist_complete_notify(t_pdp_3d_dlist *x) +{ + /* disable the second outlet */ + pdp_3dp_base_enable_outlet(x, 0, 0); +} + +static void pdp_3d_dlist_compile(t_pdp_3d_dlist *x) +{ + //x->x_compile = 1; + /* enable the second outlet */ + pdp_3dp_base_enable_outlet(x, 0, 1); +} + +static void pdp_3d_dlist_process_start(t_pdp_3d_dlist *x) +{ + int p = pdp_3dp_base_get_context_packet(x); + if (-1 != p){ + + /* check if pbuf */ + if (pdp_packet_3Dcontext_isvalid(p)){ + + /* set context */ + //pdp_pbuf_set_rendering_context(p); + + /* display list needs to be created in the correct context + if we don't have one yet, create it */ + if (!x->x_dlist) x->x_dlist = glGenLists(1); + + + + /* start the list */ /* $$$TODO: error checking for recursion */ + x->x_compile = 1; + glNewList(x->x_dlist, GL_COMPILE_AND_EXECUTE); + //glNewList(x->x_dlist, GL_COMPILE); + + //post("compiling"); + + + } + } +} + +static void pdp_3d_dlist_process_cleanup(t_pdp_3d_dlist *x) +{ + int p = pdp_3dp_base_get_context_packet(x); + if (-1 != p){ + + /* check if pbuf */ + if (pdp_packet_3Dcontext_isvalid(p)){ + + /* end list if we're compiling */ + if (x->x_compile){ + + /* end the list */ + glEndList(); + + /* use the list next time */ + x->x_compile = 0; + + //post("ending compile"); + + } + + /* or execute the old one */ + else { + if (x->x_dlist) { + //post("calling dlist %d", x->x_dlist); + glCallList(x->x_dlist); + } + + } + + + } + } +} + + + + +t_class *pdp_3d_dlist_class; + + + +void pdp_3d_dlist_free(t_pdp_3d_dlist *x) +{ + pdp_3dp_base_free(x); + if (x->x_dlist) glDeleteLists(x->x_dlist, 1); +} + +void *pdp_3d_dlist_new(t_symbol *s) +{ + t_pdp_3d_dlist *x = (t_pdp_3d_dlist *)pd_new(pdp_3d_dlist_class); + + /* super init */ + pdp_3dp_base_init(x); + + + /* io & callbacks */ + pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_dlist_process_start, 0); + pdp_3dp_base_add_cleanup(x, (t_pdp_method)pdp_3d_dlist_process_cleanup, 0); + pdp_3dp_base_register_complete_notify(x, (t_pdp_method)pdp_3d_dlist_complete_notify); + + /* disable the second outlet */ + pdp_3dp_base_enable_outlet(x, 1, 0); + + + /* create dlist */ + x->x_dlist = 0; + x->x_compile = 0; + + /* compile the first packet */ + pdp_3d_dlist_compile(x); + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_3d_dlist_setup(void) +{ + + + pdp_3d_dlist_class = class_new(gensym("pdp_3d_dlist"), (t_newmethod)pdp_3d_dlist_new, + (t_method)pdp_3d_dlist_free, sizeof(t_pdp_3d_dlist), 0, A_DEFSYMBOL, A_NULL); + + class_addcreator((t_newmethod)pdp_3d_dlist_new, gensym("3dp_dlist"), A_DEFSYMBOL, A_NULL); + + pdp_3dp_base_setup(pdp_3d_dlist_class); + + class_addmethod(pdp_3d_dlist_class, (t_method)pdp_3d_dlist_compile, gensym("compile"), A_NULL); + + + +} + +#ifdef __cplusplus +} +#endif diff --git a/opengl/modules/pdp_3d_draw.c b/opengl/modules/pdp_3d_draw.c new file mode 100644 index 0000000..39434cb --- /dev/null +++ b/opengl/modules/pdp_3d_draw.c @@ -0,0 +1,500 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +//#include "GL/gl.h" +#include <GL/glut.h> +#include <math.h> + +#include "pdp_opengl.h" +#include "pdp_3dp_base.h" + +typedef struct _drawcommand +{ + t_pdp_dpd_command x_head; + int x_context_packet; + int x_texture_packet; + float x_p0; + float x_p1; + float x_p2; + float x_p3; + t_pdp_method x_method; + GLUquadric* x_quadric; + int x_have_texture; /* is there a valid texture ? */ + +} t_drawcommand; + + +typedef struct _pdp_3d_draw +{ + t_pdp_3dp_base x_base; + t_pdp_dpd_commandfactory x_clist; + + int x_inlets; + float x_p0; + float x_p1; + float x_p2; + float x_p3; + + t_pdp_method x_method; + + int x_tex_in; /* the number of texture inlets */ + GLUquadric* x_quadric; +} t_pdp_3d_draw; + + +void pdp_3d_draw_delete_texture(t_pdp_3d_draw *x) +{ + pdp_base_move_packet(x, 1); +} + +/* return a new command object */ +void *pdp_3d_draw_get_command_object(t_pdp_3d_draw *x) +{ + t_drawcommand *c = (t_drawcommand *)pdp_dpd_commandfactory_get_new_command(&x->x_clist); + c->x_p0 = x->x_p0; + c->x_p1 = x->x_p1; + c->x_p2 = x->x_p2; + c->x_p3 = x->x_p3; + c->x_context_packet = pdp_3dp_base_get_context_packet(x); + c->x_texture_packet = pdp_packet_copy_ro(pdp_base_get_packet(x, 1)); + + c->x_quadric = x->x_quadric; /* $$$TODO: this assumes quadric doesn't change */ + + c->x_method = x->x_method; + //post("o: %x, vc %x, n %d, u %d", x, c, x->x_clist.nb_commands, c->x_head.used); + return c; +} + +/* object drawing methods */ + +static void draw_clear(t_drawcommand *x) +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + +} + +static void draw_square(t_drawcommand *x) +{ + float f = x->x_p0 * 0.5f; + float z = x->x_p1 * 0.5f; + /* draw a square */ + glBegin(GL_QUADS); + glNormal3f(0.0f, 0.0f, 1.0f); + glTexCoord2f(1, 0); + glVertex3f(f,-f, z); + glTexCoord2f(1, 1); + glVertex3f(f, f, z); + glTexCoord2f(0, 1); + glVertex3f(-f, f, z); + glTexCoord2f(0, 0); + glVertex3f(-f,-f, z); + glEnd(); +} + +static void draw_wsquare(t_drawcommand *x) +{ + float f = x->x_p0; + float z = x->x_p1; + /* draw a square */ + glBegin(GL_LINE_LOOP); + glVertex3f(f,-f, z); + glVertex3f(f, f, z); + glVertex3f(-f, f, z); + glVertex3f(-f,-f, z); + glEnd(); +} + +static void draw_triangle(t_drawcommand *x) +{ + float f = x->x_p0 * 0.5f; + float f2 = f * 0.5f; + float f3 = f * (sqrt(3.0f) / 2.0f); + float z = x->x_p1 * 0.5f; + /* draw a triangle */ + glBegin(GL_TRIANGLES); + glNormal3f(0.0f, 0.0f, 1.0f); + + glTexCoord2f(0.5f, 1.0f); + glVertex3f(0, f, z); + + glTexCoord2f(0.5f * (1.0f - sqrt(3.0f)/2.0f), 0.25f); + glVertex3f(-f3, -f2, z); + + glTexCoord2f(0.5f * (1.0f + sqrt(3.0f)/2.0f), 0.25f); + glVertex3f(f3, -f2, z); + glEnd(); +} + +static void draw_wtriangle(t_drawcommand *x) +{ + float f = x->x_p0 * 0.5f; + float f2 = f * 0.5f; + float f3 = f * (sqrt(3.0f) / 2.0f); + float z = x->x_p1 * 0.5f; + + /* draw a wire triangle */ + glBegin(GL_LINE_LOOP); + glNormal3f(0.0f, 0.0f, 1.0f); + glVertex3f(0, f, z); + glVertex3f(-f3, -f2, z); + glVertex3f(f3, -f2, z); + glEnd(); +} + + +static void draw_wcube(t_drawcommand *x) +{ + glutWireCube(x->x_p0); +} + +static void draw_cube(t_drawcommand *x) +{ + x->x_p1 = x->x_p0; // set square z coord; + + //glutSolidCube(x->x_p0); + + //glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + draw_square(x); + glRotatef(90, 0,1,0); + draw_square(x); + glRotatef(90, 0,1,0); + draw_square(x); + glRotatef(90, 0,1,0); + draw_square(x); + glPopMatrix(); + + glPushMatrix(); + glRotatef(90, 1, 0, 0); + draw_square(x); + glRotatef(180, 1, 0, 0); + draw_square(x); + glPopMatrix(); + +} + +static void draw_wtorus(t_drawcommand *x) +{ + float ri = x->x_p0; + float ro = x->x_p1; + int n = (int)x->x_p2; + int m = (int)x->x_p3; + + if (n < 1) n = 20; + if (m < 1) m = n; + + glutWireTorus(ri, ro, n, m); + +} + +static void draw_torus(t_drawcommand *x) +{ + float ri = x->x_p0; + float ro = x->x_p1; + int n = (int)x->x_p2; + int m = (int)x->x_p3; + + if (n < 1) n = 20; + if (m < 1) m = n; + + glutSolidTorus(ri, ro, n, m); + +} + +static void draw_cone(t_drawcommand *x) +{ + float base = x->x_p0; + float height = x->x_p1; + int n = (int)x->x_p2; + int m = (int)x->x_p3; + + if (n < 1) n = 20; + if (m < 1) m = n; + + glutSolidCone(base, height, n, m); + +} + +static void draw_wcone(t_drawcommand *x) +{ + float base = x->x_p0; + float height = x->x_p1; + int n = (int)x->x_p2; + int m = (int)x->x_p3; + + if (n < 1) n = 20; + if (m < 1) m = n; + + glutWireCone(base, height, n, m); + +} + +static void draw_wteapot(t_drawcommand *x) +{ + float f = x->x_p0; + glutWireTeapot(f); + +} + +static void draw_teapot(t_drawcommand *x) +{ + float f = x->x_p0; + glutSolidTeapot(f); + +} + +static void draw_wsphere(t_drawcommand *x) +{ + float f = x->x_p0; + int n = (int)x->x_p1; + int m = (int)x->x_p2; + + if (n < 1) n = 20; + if (m < 1) m = n; + + glutWireSphere(f, n, m); + +} + +static void draw_sphere(t_drawcommand *x) +{ + float f = x->x_p0; + int n = (int)x->x_p1; + int m = (int)x->x_p2; + + if (n < 1) n = 20; + if (m < 1) m = n; + + gluSphere(x->x_quadric, f, n, m); + + //glutSolidSphere(f, n, m); + +} + +static void draw_dodeca(t_drawcommand *x){glutSolidDodecahedron();} +static void draw_octa(t_drawcommand *x) {glutSolidOctahedron();} +static void draw_tetra(t_drawcommand *x) {glutSolidTetrahedron();} +static void draw_icosa(t_drawcommand *x) {glutSolidIcosahedron();} + +static void draw_wdodeca(t_drawcommand *x){glutWireDodecahedron();} +static void draw_wocta(t_drawcommand *x) {glutWireOctahedron();} +static void draw_wtetra(t_drawcommand *x) {glutWireTetrahedron();} +static void draw_wicosa(t_drawcommand *x) {glutWireIcosahedron();} + + + + + + +/* the actual (registered) draw method */ +/* when this is finished, the drawcommand object should commit suicide */ + +static void draw_process(t_drawcommand *x) +{ + int p = x->x_context_packet; + int pt = x->x_texture_packet; + float fx=1; + float fy=1; + x->x_have_texture = pdp_packet_texture_isvalid(pt); + + //post("pdp_3d_draw: context = %d, texture = %d", p, pt); + + /* check if it's a valid buffer we can draw in */ + if (pdp_packet_3Dcontext_isvalid(p)){ + + + /* setup rendering context */ + pdp_packet_3Dcontext_set_rendering_context(p); + + /* enable texture */ + if (x->x_have_texture){ + fx = pdp_packet_texture_fracx(pt); + fy = pdp_packet_texture_fracy(pt); + glEnable(GL_TEXTURE_2D); + pdp_packet_texture_make_current(pt); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + /* scale texture matrix to reflect subtexture's coords */ + glMatrixMode(GL_TEXTURE); + //glLoadIdentity(); + glPushMatrix(); + glScalef(fx, fy, 1); + glMatrixMode(GL_MODELVIEW); + + gluQuadricTexture(x->x_quadric, 1); + } + + /* call the generating method */ + if (x->x_method) (*x->x_method)(x); + + /* disable texture */ + if (x->x_have_texture){ + glMatrixMode(GL_TEXTURE); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glDisable(GL_TEXTURE_2D); + gluQuadricTexture(x->x_quadric, 0); + } + + } + + /* you know the drill: command done, sword in belly. */ + pdp_packet_mark_unused(x->x_texture_packet); + pdp_dpd_command_suicide(x); + +} + +static void pdp_3d_draw_p0(t_pdp_3d_draw *x, t_floatarg f){x->x_p0 = f;} +static void pdp_3d_draw_p1(t_pdp_3d_draw *x, t_floatarg f){x->x_p1 = f;} +static void pdp_3d_draw_p2(t_pdp_3d_draw *x, t_floatarg f){x->x_p2 = f;} +static void pdp_3d_draw_p3(t_pdp_3d_draw *x, t_floatarg f){x->x_p3 = f;} + + +t_class *pdp_3d_draw_class; + + + +void pdp_3d_draw_free(t_pdp_3d_draw *x) +{ + pdp_3dp_base_free(x); + gluDeleteQuadric(x->x_quadric); + pdp_dpd_commandfactory_free(&x->x_clist); +} + +void pdp_3d_draw_object(t_pdp_3d_draw *x, t_symbol *s) +{ + /* find out if it is a buffer operation */ + if (s == gensym("clear")) {x->x_method = (t_pdp_method)draw_clear; x->x_inlets = 0;} + + /* if not, find out which object we need to draw */ + else if (s == gensym("triangle")) {x->x_method = (t_pdp_method)draw_triangle; x->x_inlets = 1;} + else if (s == gensym("wtriangle")) {x->x_method = (t_pdp_method)draw_wtriangle; x->x_inlets = 1;} + else if (s == gensym("square")) {x->x_method = (t_pdp_method)draw_square; x->x_inlets = 1;} + else if (s == gensym("wsquare")) {x->x_method = (t_pdp_method)draw_wsquare; x->x_inlets = 1;} + else if (s == gensym("cube")) {x->x_method = (t_pdp_method)draw_cube; x->x_inlets = 1;} + else if (s == gensym("wcube")) {x->x_method = (t_pdp_method)draw_wcube; x->x_inlets = 1;} + else if (s == gensym("sphere")) {x->x_method = (t_pdp_method)draw_sphere; x->x_inlets = 3;} + else if (s == gensym("wsphere")) {x->x_method = (t_pdp_method)draw_wsphere; x->x_inlets = 3;} + else if (s == gensym("torus")) {x->x_method = (t_pdp_method)draw_torus; x->x_inlets = 4;} + else if (s == gensym("wtorus")) {x->x_method = (t_pdp_method)draw_wtorus; x->x_inlets = 4;} + else if (s == gensym("cone")) {x->x_method = (t_pdp_method)draw_cone; x->x_inlets = 4;} + else if (s == gensym("wcone")) {x->x_method = (t_pdp_method)draw_wcone; x->x_inlets = 4;} + else if (s == gensym("teapot")) {x->x_method = (t_pdp_method)draw_teapot; x->x_inlets = 1;} + else if (s == gensym("wteapot")) {x->x_method = (t_pdp_method)draw_wteapot; x->x_inlets = 1;} + + else if (s == gensym("dodeca")) {x->x_method = (t_pdp_method)draw_dodeca; x->x_inlets = 0;} + else if (s == gensym("icosa")) {x->x_method = (t_pdp_method)draw_icosa; x->x_inlets = 0;} + else if (s == gensym("octa")) {x->x_method = (t_pdp_method)draw_octa; x->x_inlets = 0;} + else if (s == gensym("tetra")) {x->x_method = (t_pdp_method)draw_tetra; x->x_inlets = 0;} + else if (s == gensym("wdodeca")) {x->x_method = (t_pdp_method)draw_wdodeca; x->x_inlets = 0;} + else if (s == gensym("wicosa")) {x->x_method = (t_pdp_method)draw_wicosa; x->x_inlets = 0;} + else if (s == gensym("wocta")) {x->x_method = (t_pdp_method)draw_wocta; x->x_inlets = 0;} + else if (s == gensym("wtetra")) {x->x_method = (t_pdp_method)draw_wtetra; x->x_inlets = 0;} + + else { + post("pdp_3d_draw: object %s not found", s->s_name); + x->x_method = 0; + x->x_inlets = 0; + } + + // the number of texture inlets + x->x_tex_in = 1; +} + + +void *pdp_3d_draw_new(t_symbol *s, t_floatarg p0, t_floatarg p1, t_floatarg p2, t_floatarg p3) +{ + t_pdp_3d_draw *x = (t_pdp_3d_draw *)pd_new(pdp_3d_draw_class); + char param[] = "p0"; + int i; + + /* super init */ + pdp_3dp_base_init(x); + + x->x_p0 = p0; + x->x_p1 = p1; + x->x_p2 = p2; + x->x_p3 = p3; + + /* set the object & number of inlets */ + pdp_3d_draw_object(x, s); + + /* create texture inlets */ + for(i=0; i<x->x_tex_in; i++){ + pdp_base_add_pdp_inlet(x); + } + + /* create additional inlets */ + for(i=0; i<x->x_inlets; i++){ + pdp_base_add_gen_inlet(x, gensym("float"), gensym(param)); + param[1]++; + } + + /* create dpd outlet */ + pdp_3dp_base_add_outlet(x, (t_pdp_method)draw_process, 0); + + /* setup quadric */ + x->x_quadric = gluNewQuadric(); + + /* init command list */ + pdp_dpd_commandfactory_init(&x->x_clist, sizeof(t_drawcommand)); + + /* register command factory method */ + pdp_dpd_base_register_command_factory_method(x, (t_pdp_newmethod)pdp_3d_draw_get_command_object); + + + + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_3d_draw_setup(void) +{ + + + pdp_3d_draw_class = class_new(gensym("3dp_draw"), (t_newmethod)pdp_3d_draw_new, + (t_method)pdp_3d_draw_free, sizeof(t_pdp_3d_draw), 0, A_SYMBOL, + A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_NULL); + pdp_3dp_base_setup(pdp_3d_draw_class); + + class_addmethod(pdp_3d_draw_class, (t_method)pdp_3d_draw_p0, gensym("p0"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_3d_draw_class, (t_method)pdp_3d_draw_p1, gensym("p1"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_3d_draw_class, (t_method)pdp_3d_draw_p2, gensym("p2"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_3d_draw_class, (t_method)pdp_3d_draw_p3, gensym("p3"), A_DEFFLOAT, A_NULL); + + class_addmethod(pdp_3d_draw_class, (t_method)pdp_3d_draw_delete_texture, gensym("delete_texture"), A_DEFFLOAT, A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/opengl/modules/pdp_3d_drawmesh.c b/opengl/modules/pdp_3d_drawmesh.c new file mode 100644 index 0000000..cd2c973 --- /dev/null +++ b/opengl/modules/pdp_3d_drawmesh.c @@ -0,0 +1,340 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +/* a very naive approach to triangular meshes */ + + +// $$TODO: some serious memory corruption in this file our the list implementation + + +#include "GL/gl.h" +#include <math.h> +//#include <GL/glut.h> + +#include "pdp_opengl.h" +#include "pdp_3dp_base.h" +#include "pdp_mesh.h" + + +/* PD OBJECT */ + +typedef struct _pdp_3d_drawmesh +{ + t_pdp_3dp_base x_base; + t_pdp_dpd_commandfactory x_clist; + + t_mesh *x_mesh; + int x_wireframe; + int x_flatshading; + +} t_pdp_3d_drawmesh; + + +/* MESHCOMMAND OBJECT */ + +typedef struct _meshcommand +{ + t_pdp_dpd_command x_head; + int x_context_packet; + int x_texture_packet; + t_pdp_3d_drawmesh *x_mother; + t_pdp_method x_method; + + int x_wireframe; + int x_flatshading; + float x_step; + float x_d0; + float x_r0; + int x_normal_type; + +} t_meshcommand; + + +/* MESHCOMMAND METHODS */ + +/* draw the mesh */ +static void meshcommand_draw(t_meshcommand *x) +{ + int i = 0; + t_pdp_atom *it; + t_pdp_list *tl = x->x_mother->x_mesh->triangles; + t_triangle *t; + GLenum mode = (x->x_wireframe) ? GL_LINE_LOOP : GL_TRIANGLES; + + //glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); + + glLineWidth(5); + + glBegin(mode); + + if (x->x_flatshading){ + PDP_POINTER_IN(tl, it, t){ + glNormal3fv(t->n); + for (i=0; i<3; i++){ + glVertex3fv(t->v[i]->c); + } + } + } + else{ + PDP_POINTER_IN(tl, it, t){ + for (i=0; i<3; i++){ + glNormal3fv(t->v[i]->n); + glVertex3fv(t->v[i]->c); + } + } + } + glEnd(); +} + +static void meshcommand_relax(t_meshcommand *x) +{ + mesh_relax(x->x_mother->x_mesh, x->x_step, x->x_d0, x->x_r0); +} + + +/* the main subcommand dispatcher */ +static void meshcommand_execute(t_meshcommand *x) +{ + int p = x->x_context_packet; + + /* check if it's a valid buffer we can draw in */ + if (pdp_packet_3Dcontext_isvalid(p)){ + + + /* setup rendering context */ + pdp_packet_3Dcontext_set_rendering_context(p); + + /* call the command method */ + if (x->x_method) (x->x_method)(x); + + } + + /* you know the drill: command done, sword in belly. */ + pdp_dpd_command_suicide(x); +} + +static void meshcommand_split_all_four(t_meshcommand *x) +{ + mesh_split_all_four(x->x_mother->x_mesh); +} +static void meshcommand_split_all_three(t_meshcommand *x){ + mesh_split_all_three(x->x_mother->x_mesh); +} +static void meshcommand_split_random_three(t_meshcommand *x){ + mesh_split_random_three(x->x_mother->x_mesh); +} + + +static void meshcommand_reset(t_meshcommand *x) +{ + mesh_free(x->x_mother->x_mesh); + x->x_mother->x_mesh = mesh_new_tetra(); +} + +static void meshcommand_debug(t_meshcommand *x) +{ + mesh_debug(x->x_mother->x_mesh); +} + +static void meshcommand_calculate_normals(t_meshcommand *x) +{ + x->x_mother->x_mesh->normal_type = x->x_normal_type; + mesh_calculate_normals(x->x_mother->x_mesh); +} + + + + +/* PD OBJECT METHODS */ + + +/* return a new command object */ +void *pdp_3d_drawmesh_get_command_object(t_pdp_3d_drawmesh *x) +{ + t_meshcommand *c = (t_meshcommand *)pdp_dpd_commandfactory_get_new_command(&x->x_clist); + c->x_context_packet = pdp_3dp_base_get_context_packet(x); + c->x_mother = x; + c->x_method = (t_pdp_method)meshcommand_draw; //default command is draw + c->x_wireframe = x->x_wireframe; + c->x_flatshading = x->x_flatshading; + + return c; +} + +/* schedule a command */ +static void pdp_3d_drawmesh_queue_command(t_pdp_3d_drawmesh *x, t_meshcommand *c) +{ + pdp_3dp_base_queue_command(x, c, (t_pdp_method)meshcommand_execute, 0, 0); +} + +static void pdp_3d_drawmesh_queue_simple_command(t_pdp_3d_drawmesh *x, t_pdp_method method) +{ + t_meshcommand *c = (t_meshcommand *)pdp_3d_drawmesh_get_command_object(x); + c->x_method = method; + pdp_3dp_base_queue_command(x, c, (t_pdp_method)meshcommand_execute, 0, 0); +} + +//NOTE: only the meshcommands are entitled to use the mesh (thread issues) +//therefore all mesh manipulations must be queued as a command + + +static void pdp_3d_drawmesh_debug(t_pdp_3d_drawmesh *x) +{ + pdp_3d_drawmesh_queue_simple_command(x, (t_pdp_method)meshcommand_debug); +} + +static void pdp_3d_drawmesh_relax(t_pdp_3d_drawmesh *x, t_floatarg step, + t_floatarg d0, t_floatarg r0) +{ + t_meshcommand *c = (t_meshcommand *)pdp_3d_drawmesh_get_command_object(x); + c->x_step = step; + c->x_d0 = d0; + c->x_r0 = r0; + c->x_method = (t_pdp_method)meshcommand_relax; + pdp_3d_drawmesh_queue_command(x, c); + +} + +void pdp_3d_drawmesh_normal(t_pdp_3d_drawmesh *x, t_symbol *s) +{ + t_meshcommand *c = (t_meshcommand *)pdp_3d_drawmesh_get_command_object(x); + if (gensym("sphere") == s) c->x_normal_type = MESH_NORMAL_SPHERE; + else if (gensym("prism") == s) c->x_normal_type = MESH_NORMAL_PRISM; + else if (gensym("random") == s) c->x_normal_type = MESH_NORMAL_RANDOM; + else if (gensym("average") == s) c->x_normal_type = MESH_NORMAL_AVERAGE; + c->x_method = (t_pdp_method)meshcommand_calculate_normals; + pdp_3d_drawmesh_queue_command(x, c); + +} + +/* this is used by the standard drawing routine, so doesn't need to be scheduled */ +void pdp_3d_drawmesh_wireframe(t_pdp_3d_drawmesh *x, t_float f) +{ + x->x_wireframe = (f != 0.0f); +} + +void pdp_3d_drawmesh_flatshading(t_pdp_3d_drawmesh *x, t_float f) +{ + x->x_flatshading = (f != 0.0f); +} + + +static void pdp_3d_drawmesh_split_all_four(t_pdp_3d_drawmesh *x) +{ + pdp_3d_drawmesh_queue_simple_command(x, (t_pdp_method)meshcommand_split_all_four); +} + +static void pdp_3d_drawmesh_split_all_three(t_pdp_3d_drawmesh *x) +{ + pdp_3d_drawmesh_queue_simple_command(x, (t_pdp_method)meshcommand_split_all_three); +} + +static void pdp_3d_drawmesh_split_random_three(t_pdp_3d_drawmesh *x) +{ + pdp_3d_drawmesh_queue_simple_command(x, (t_pdp_method)meshcommand_split_random_three); +} + + +static void pdp_3d_drawmesh_reset(t_pdp_3d_drawmesh *x) +{ + pdp_3d_drawmesh_queue_simple_command(x, (t_pdp_method)meshcommand_reset); + +} + + + + + + + + + + +t_class *pdp_3d_drawmesh_class; + + +void pdp_3d_drawmesh_free(t_pdp_3d_drawmesh *x) +{ + /* queue needs to finish before mesh is deleted */ + pdp_3dp_base_queue_wait(x); + mesh_free(x->x_mesh); + + pdp_3dp_base_free(x); + pdp_dpd_commandfactory_free(&x->x_clist); +} + +void *pdp_3d_drawmesh_new(t_symbol *s, t_floatarg p0, t_floatarg p1, t_floatarg p2, t_floatarg p3) +{ + t_pdp_3d_drawmesh *x = (t_pdp_3d_drawmesh *)pd_new(pdp_3d_drawmesh_class); + + /* super init */ + pdp_3dp_base_init(x); + + /* create dpd outlet */ + pdp_3dp_base_add_outlet(x, (t_pdp_method)meshcommand_execute, 0); + + /* init command list */ + pdp_dpd_commandfactory_init(&x->x_clist, sizeof(t_meshcommand)); + + /* register command factory method */ + pdp_dpd_base_register_command_factory_method(x, (t_pdp_newmethod)pdp_3d_drawmesh_get_command_object); + + + /* initialize triangular mesh with a simply connected manifold */ + x->x_mesh = mesh_new_tetra(); + + x->x_wireframe = 0; + x->x_flatshading = 0; + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_3d_drawmesh_setup(void) +{ + + pdp_3d_drawmesh_class = class_new(gensym("3dp_drawmesh"), (t_newmethod)pdp_3d_drawmesh_new, + (t_method)pdp_3d_drawmesh_free, sizeof(t_pdp_3d_drawmesh), 0, A_DEFSYMBOL, + A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_NULL); + pdp_3dp_base_setup(pdp_3d_drawmesh_class); + + + class_addmethod(pdp_3d_drawmesh_class, (t_method)pdp_3d_drawmesh_split_random_three, gensym("split3random"), A_NULL); + class_addmethod(pdp_3d_drawmesh_class, (t_method)pdp_3d_drawmesh_split_all_three, gensym("split3"), A_NULL); + class_addmethod(pdp_3d_drawmesh_class, (t_method)pdp_3d_drawmesh_split_all_four, gensym("split4"), A_NULL); + class_addmethod(pdp_3d_drawmesh_class, (t_method)pdp_3d_drawmesh_reset, gensym("reset"), A_NULL); + class_addmethod(pdp_3d_drawmesh_class, (t_method)pdp_3d_drawmesh_normal, gensym("normal"), A_SYMBOL, A_NULL); + class_addmethod(pdp_3d_drawmesh_class, (t_method)pdp_3d_drawmesh_relax, gensym("springrelax"), + A_FLOAT, A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_3d_drawmesh_class, (t_method)pdp_3d_drawmesh_debug, gensym("info"), A_NULL); + class_addmethod(pdp_3d_drawmesh_class, (t_method)pdp_3d_drawmesh_wireframe, gensym("wireframe"), A_FLOAT, A_NULL); + class_addmethod(pdp_3d_drawmesh_class, (t_method)pdp_3d_drawmesh_flatshading, gensym("flatshading"), A_FLOAT, A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/opengl/modules/pdp_3d_for.c b/opengl/modules/pdp_3d_for.c new file mode 100644 index 0000000..54b0a71 --- /dev/null +++ b/opengl/modules/pdp_3d_for.c @@ -0,0 +1,106 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +/* a for loop for 3dp packets + this can later be adapted to a for loop for dpd packets. */ + +#include "pdp_opengl.h" +#include "pdp_internals.h" + + +typedef struct pdp_3d_for_struct +{ + t_object x_obj; + + t_int x_count; + + t_outlet *x_outlet_dpd; + t_outlet *x_outlet_float; + +} t_pdp_3d_for; + + + +static void pdp_3d_for_input_0(t_pdp_3d_for *x, t_symbol *s, t_floatarg f) +{ + int i; + + /* trigger on "accumulate" */ + + if (s == gensym("accumulate")){ + for (i=0; i<x->x_count; i++){ + outlet_float(x->x_outlet_float, (float)i); + outlet_dpd(x->x_outlet_dpd, (int)f); + } + } +} + +static void pdp_3d_for_count(t_pdp_3d_for *x, t_floatarg f) +{ + int count = (int)f; + if (count >= 0) x->x_count = count; +} + + +static void pdp_3d_for_free(t_pdp_3d_for *x) +{ +} + +t_class *pdp_3d_for_class; + + + +void *pdp_3d_for_new(t_floatarg f) +{ + int count = (int)f; + + t_pdp_3d_for *x = (t_pdp_3d_for *)pd_new(pdp_3d_for_class); + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("count")); + + x->x_outlet_dpd = outlet_new(&x->x_obj, &s_anything); + x->x_outlet_float = outlet_new(&x->x_obj, &s_float); + x->x_count = (count > 0) ? count : 1; + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_3d_for_setup(void) +{ + + + pdp_3d_for_class = class_new(gensym("3dp_for"), (t_newmethod)pdp_3d_for_new, + (t_method)pdp_3d_for_free, sizeof(t_pdp_3d_for), 0, A_DEFFLOAT, A_NULL); + + class_addmethod(pdp_3d_for_class, (t_method)pdp_3d_for_input_0, gensym("dpd"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_3d_for_class, (t_method)pdp_3d_for_count, gensym("count"), A_FLOAT, A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/opengl/modules/pdp_3d_light.c b/opengl/modules/pdp_3d_light.c new file mode 100644 index 0000000..b0b4a92 --- /dev/null +++ b/opengl/modules/pdp_3d_light.c @@ -0,0 +1,155 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +#include <GL/gl.h> +#include "pdp_opengl.h" +#include "pdp_3dp_base.h" + +typedef struct pdp_3d_light_struct +{ + t_pdp_3dp_base x_base; + + //float x_centerx; + //float x_centery; + //float x_centerz; + int x_index; + +} t_pdp_3d_light; + + + +static void pdp_3d_light_process(t_pdp_3d_light *x) +{ + int p = pdp_3dp_base_get_context_packet(x); + int i; + GLfloat ambient[] = {.7,.7,.7,1}; + GLfloat diffuse[] = {.6,.6,.6,1}; + GLfloat specular[] = {1, 1, 1, 1}; + GLfloat shininess[] = {50}; + GLfloat position[] = {0,0,1,1}; + GLfloat intensity[] = {1,1,1,0}; + + int light = GL_LIGHT0 + x->x_index; + + /* check if it's a valid buffer we can draw in */ + if (pdp_packet_3Dcontext_isvalid(p)){ + + position[0] = 0; //x->x_centerx; + position[1] = 0; //x->x_centery; + position[2] = 0; //x->x_centerz; + + /* set rendering context */ + //pdp_packet_3Dcontext_set_rendering_context(p); + + /* setup lighting */ + + glEnable(GL_LIGHTING); + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); + glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); + glEnable(GL_COLOR_MATERIAL); + //glMaterialfv(GL_FRONT, GL_AMBIENT, ambient); + glMaterialfv(GL_FRONT, GL_SPECULAR, specular); + glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse); + glMaterialfv(GL_FRONT, GL_SHININESS, shininess); + glLightfv(light, GL_POSITION, position); + //glLightfv(light, GL_DIFFUSE, intensity); + glEnable(light); + + + /* ALPHA HACK */ + //glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); + //glEnable(GL_BLEND); + //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + //glBlendFunc(GL_SRC_ALPHA, GL_ONE); + //glEnable(GL_ALPHA_TEST); + //glAlphaFunc(GL_GREATER, 0.f); + + } + +} + + + +//static void pdp_3d_light_centerx(t_pdp_3d_light *x, t_floatarg f){x->x_centerx = f;} +//static void pdp_3d_light_centery(t_pdp_3d_light *x, t_floatarg f){x->x_centery = f;} +//static void pdp_3d_light_centerz(t_pdp_3d_light *x, t_floatarg f){x->x_centerz = f;} + + +t_class *pdp_3d_light_class; + + + +void pdp_3d_light_free(t_pdp_3d_light *x) +{ + pdp_3dp_base_free(x); +} + +void *pdp_3d_light_new(t_floatarg fi, t_floatarg cx, t_floatarg cy, t_floatarg cz) +{ + t_pdp_3d_light *x = (t_pdp_3d_light *)pd_new(pdp_3d_light_class); + + /* super init */ + pdp_3dp_base_init(x); + + if (fi < 0) fi = 0; + + x->x_index = (int)fi; + //x->x_centerx = cx; + //x->x_centery = cy; + //x->x_centerz = cz; + + /* io */ + //pdp_base_add_gen_inlet(x, gensym("float"), gensym("centerx")); + //pdp_base_add_gen_inlet(x, gensym("float"), gensym("centery")); + //pdp_base_add_gen_inlet(x, gensym("float"), gensym("centerz")); + + /* add dpd outlet */ + pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_light_process, 0); + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_3d_light_setup(void) +{ + + + pdp_3d_light_class = class_new(gensym("3dp_light"), (t_newmethod)pdp_3d_light_new, + (t_method)pdp_3d_light_free, sizeof(t_pdp_3d_light), 0, + A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_NULL); + + pdp_3dp_base_setup(pdp_3d_light_class); + + //class_addmethod(pdp_3d_light_class, (t_method)pdp_3d_light_centerx, gensym("centerx"), A_DEFFLOAT, A_NULL); + //class_addmethod(pdp_3d_light_class, (t_method)pdp_3d_light_centery, gensym("centery"), A_DEFFLOAT, A_NULL); + //class_addmethod(pdp_3d_light_class, (t_method)pdp_3d_light_centerz, gensym("centerz"), A_DEFFLOAT, A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/opengl/modules/pdp_3d_push.c b/opengl/modules/pdp_3d_push.c new file mode 100644 index 0000000..d5a45fb --- /dev/null +++ b/opengl/modules/pdp_3d_push.c @@ -0,0 +1,181 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include <GL/gl.h> +#include "pdp_opengl.h" +#include "pdp_3dp_base.h" + +typedef struct pdp_3d_push_struct +{ + t_pdp_3dp_base x_base; + GLenum x_matrix; + int x_change_mode; + +} t_pdp_3d_push; + + + +static void pdp_3d_push_process_right(t_pdp_3d_push *x) +{ + int p = pdp_3dp_base_get_context_packet(x); + if (-1 != p){ + + /* push one of the matrices */ + glMatrixMode(x->x_matrix); + glPushMatrix(); + + /* set default matrix to modelview */ + if (!x->x_change_mode) glMatrixMode(GL_MODELVIEW); + + } +} +static void pdp_3d_push_process_left(t_pdp_3d_push *x) +{ + int p = pdp_3dp_base_get_context_packet(x); + if (-1 != p){ + + /* restore the saved matrix */ + glMatrixMode(x->x_matrix); + glPopMatrix(); + + /* set default matrix back to modelview */ + glMatrixMode(GL_MODELVIEW); + + } + +} + + +static void pdp_3d_mode_process_right(t_pdp_3d_push *x) +{ + int p = pdp_3dp_base_get_context_packet(x); + if (-1 != p){ + + /* change matrix mode */ + glMatrixMode(x->x_matrix); + + } +} + +static void pdp_3d_mode_process_left(t_pdp_3d_push *x) +{ + int p = pdp_3dp_base_get_context_packet(x); + if (-1 != p){ + + /* restore default matrix to modelview */ + glMatrixMode(GL_MODELVIEW); + + } +} + + +static void pdp_3d_push_setmatrix(t_pdp_3d_push *x, t_symbol *s) +{ + GLenum m; + + /* find out which matrix to push */ + if (s == gensym("projection")) m = GL_PROJECTION; + else if (s == gensym("modelview")) m = GL_MODELVIEW; + else if (s == gensym("texture")) m = GL_TEXTURE; + else if (s == gensym("color")) m = GL_COLOR; + + /* default is modelview */ + else m = GL_MODELVIEW; + + x->x_matrix = m; +} + + +t_class *pdp_3d_push_class; + + + +void pdp_3d_push_free(t_pdp_3d_push *x) +{ + pdp_3dp_base_free(x); +} + +void *pdp_3d_push_mode_new(t_symbol *s) +{ + t_pdp_3d_push *x = (t_pdp_3d_push *)pd_new(pdp_3d_push_class); + + /* super init */ + pdp_3dp_base_init(x); + + /* setup which matrix we are talking about */ + pdp_3d_push_setmatrix(x, s); + + x->x_change_mode = 0; + + return (void *)x; +} + +void *pdp_3d_push_new(t_symbol *s, t_floatarg f) +{ + t_pdp_3d_push *x = (t_pdp_3d_push *)pdp_3d_push_mode_new(s); + + /* create dpd outlets */ + pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_push_process_left, 0); + pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_push_process_right, 0); + + x->x_change_mode = (f != 0.0f); + + return (void *)x; +} + + +void *pdp_3d_mode_new(t_symbol *s) +{ + t_pdp_3d_push *x = (t_pdp_3d_push *)pdp_3d_push_mode_new(s); + + /* create dpd outlets */ + pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_mode_process_left, 0); + pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_mode_process_right, 0); + + + return (void *)x; +} + + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_3d_push_setup(void) +{ + + + pdp_3d_push_class = class_new(gensym("3dp_push"), (t_newmethod)pdp_3d_push_new, + (t_method)pdp_3d_push_free, sizeof(t_pdp_3d_push), 0, A_DEFSYMBOL, A_NULL); + + class_addcreator((t_newmethod)pdp_3d_mode_new, gensym("3dp_mode"), A_DEFSYMBOL, A_NULL); + + pdp_3dp_base_setup(pdp_3d_push_class); + +} + +#ifdef __cplusplus +} +#endif diff --git a/opengl/modules/pdp_3d_snap.c b/opengl/modules/pdp_3d_snap.c new file mode 100644 index 0000000..2ee6d39 --- /dev/null +++ b/opengl/modules/pdp_3d_snap.c @@ -0,0 +1,216 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +#include <GL/gl.h> +#include "pdp.h" +#include "pdp_3dp_base.h" +#include "pdp_opengl.h" + +typedef struct _pdp_3d_snap +{ + t_pdp_3dp_base x_base; + t_pdp_dpd_commandfactory x_cfact; + t_outlet *x_result_outlet; + t_pdp_symbol *x_dest_template; + int x_is_texture; + u32 x_width; + u32 x_height; + int x_auto_snap; + int x_pending_snap; + +} t_pdp_3d_snap; + + +typedef struct _snap_command +{ + t_pdp_dpd_command x_base; + t_pdp_3d_snap *x_mother; + int x_context_packet; + int x_result_packet; + int x_active; +} t_snap_command; + + + + +/* COMAND METHODS */ + +static void snap_texture_process(t_snap_command *x) +{ + int pt = -1; + int p = x->x_context_packet; + int i; + u32 w,h; + + if (x->x_active && pdp_packet_3Dcontext_isvalid(p)){ + + /* get dest texture sub dims */ + w = (x->x_mother->x_width) ? x->x_mother->x_width : pdp_packet_3Dcontext_subwidth(p); + h = (x->x_mother->x_height) ? x->x_mother->x_height : pdp_packet_3Dcontext_subheight(p); + + /* texture is a special case */ + if (x->x_mother->x_is_texture){ + + /* create a new texture packet */ + pt = pdp_packet_new_texture(w,h,GL_RGB); + if (-1 != pt) { + + /* set rendering context */ + pdp_packet_3Dcontext_set_rendering_context(p); + + /* copy pbuf to new texture */ + pdp_packet_texture_make_current(pt); + //glReadBuffer(GL_FRONT); //this is for weird feedback stuff.. + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w, h); + + x->x_result_packet = pt; + } + } + + /* other type: snap to bitmap first, then convert */ + else{ + + //nvidia driver 4191 bug workaround (w -> multiple of 4) + w &= -4; + + pt = pdp_packet_3Dcontext_snap_to_bitmap(p, w, h); + //pt = pdp_packet_new_bitmap_rgb(w, h); + //pdp_packet_print_debug(pt); + x->x_result_packet = pdp_packet_convert_ro(pt, x->x_mother->x_dest_template); + pdp_packet_mark_unused(pt); + } + } +} + +static void snap_callback(t_snap_command *x) +{ + /* send packet to outlet */ + pdp_packet_pass_if_valid(x->x_mother->x_result_outlet, &x->x_result_packet); + pdp_dpd_command_suicide(x); +} + + +/* PD OBJECT METHODS */ + + +static void pdp_3d_snap_snap(t_pdp_3d_snap *x) +{ + x->x_pending_snap = 1; +} + +static void pdp_3d_snap_autosnap(t_pdp_3d_snap *x, t_floatarg f) +{ + if (f){ + x->x_auto_snap = 1; + x->x_pending_snap = 1; + } + else{ + x->x_auto_snap = 0; + x->x_pending_snap = 0; + } +} + +static void *pdp_3d_snap_get_new_command(t_pdp_3d_snap *x) +{ + t_snap_command *c = (t_snap_command *)pdp_dpd_commandfactory_get_new_command(&x->x_cfact); + c->x_mother = x; + c->x_context_packet = pdp_3dp_base_get_context_packet(x); + c->x_result_packet = -1; + c->x_active = x->x_pending_snap; + if (!x->x_auto_snap) x->x_pending_snap = 0; + return (void *)c; +} + + +t_class *pdp_3d_snap_class; + + + +void pdp_3d_snap_free(t_pdp_3d_snap *x) +{ + //pdp_dpd_base_queue_wait(x); + pdp_3dp_base_free(x); +} + +void *pdp_3d_snap_new(t_symbol *s, t_floatarg w, t_floatarg h) +{ + t_pdp_3d_snap *x = (t_pdp_3d_snap *)pd_new(pdp_3d_snap_class); + + /* super init */ + pdp_3dp_base_init(x); + + /* get destination template */ + x->x_dest_template = (s == gensym("")) ? pdp_gensym("texture/*/*") : pdp_gensym(s->s_name); + x->x_is_texture = pdp_type_description_match(x->x_dest_template, pdp_gensym("texture/*/*")); + w = (w < 0) ? 0 : w; + h = (h < 0) ? 0 : h; + x->x_width = w; + x->x_height = h; + + x->x_auto_snap = 1; + x->x_pending_snap = 1; + + /* issue warning */ + if (!x->x_is_texture && !(x->x_width && x->x_height)){ + //post("WARNING: 3dp_snap: target is not a texture and dimensions are not set."); + //post("WARNING: using default image size 320x240."); + //x->x_width = 320; + //x->x_height = 240; + } + + /* create outlets */ + pdp_3dp_base_add_outlet(x, (t_pdp_method)snap_texture_process, (t_pdp_method)snap_callback); + x->x_result_outlet = outlet_new((t_object *)x, &s_anything); + + /* init command list */ + pdp_dpd_commandfactory_init(&x->x_cfact, sizeof(t_snap_command)); + + /* register command factory method */ + pdp_dpd_base_register_command_factory_method(x, (t_pdp_newmethod)pdp_3d_snap_get_new_command); + + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_3d_snap_setup(void) +{ + + + pdp_3d_snap_class = class_new(gensym("3dp_snap"), (t_newmethod)pdp_3d_snap_new, + (t_method)pdp_3d_snap_free, sizeof(t_pdp_3d_snap), 0, A_DEFSYMBOL, A_DEFFLOAT, A_DEFFLOAT, A_NULL); + + pdp_3dp_base_setup(pdp_3d_snap_class); + + class_addmethod(pdp_3d_snap_class, (t_method)pdp_3d_snap_snap, gensym("bang"), A_NULL); + class_addmethod(pdp_3d_snap_class, (t_method)pdp_3d_snap_autosnap, gensym("autosnap"), A_FLOAT, A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/opengl/modules/pdp_3d_state.c b/opengl/modules/pdp_3d_state.c new file mode 100644 index 0000000..d34ff94 --- /dev/null +++ b/opengl/modules/pdp_3d_state.c @@ -0,0 +1,135 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +/* change binary opengl state variables. all defaults (flag = 0) should be set + in the render context init. + + right outlet has the thing enabled (or disabled, depending on toggle) + left outlet has the thing disabled (better: it should push it) + + simple version: does not permit reentry (yet) */ + + +#include <GL/gl.h> +#include "pdp_opengl.h" +#include "pdp_3dp_base.h" + +typedef struct pdp_3d_state_struct +{ + t_pdp_3dp_base x_base; + GLboolean x_flag; + GLboolean x_prev_flag; + GLenum x_thing; + void (*x_setup)(void); + +} t_pdp_3d_state; + + +static void _setflag(GLenum thing, GLboolean flag) +{ + if (flag) glEnable(thing); + else glDisable(thing); +} + +static void pdp_3d_state_process_right(t_pdp_3d_state *x) +{ + int p; + if (-1 != (p = pdp_3dp_base_get_context_packet(x))){ + /* store previous flag */ + pdp_packet_3Dcontext_set_rendering_context(p); + glGetBooleanv(x->x_thing, &x->x_prev_flag); + _setflag(x->x_thing, x->x_flag); + if (x->x_setup) x->x_setup(); + } +} + +static void pdp_3d_state_process_left(t_pdp_3d_state *x) +{ + int p; + /* allways run left method (reset) */ + if (-1 != (p = pdp_3dp_base_get_context_packet(x))){ + pdp_packet_3Dcontext_set_rendering_context(p); + _setflag(x->x_thing, x->x_prev_flag); + } +} + +static void pdp_3d_state_flag(t_pdp_3d_state *x, t_floatarg f) +{ + x->x_flag = (f == 0.0f) ? GL_FALSE : GL_TRUE; +} + +static void _blend(void) {glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);} +static void _blend_add(void) {glBlendFunc(GL_SRC_ALPHA, GL_ONE);} + +t_class *pdp_3d_state_class; +void pdp_3d_state_free(t_pdp_3d_state *x){pdp_3dp_base_free(x);} +void *pdp_3d_state_new(t_symbol *s, t_floatarg f) +{ + t_pdp_3d_state *x = (t_pdp_3d_state *)pd_new(pdp_3d_state_class); + + /* super init */ + pdp_3dp_base_init(x); + pdp_3d_state_flag(x,f); + + if (s == gensym("blend_mix")) {x->x_setup = _blend; x->x_thing = GL_BLEND;} + else if (s == gensym("blend_add")) {x->x_setup = _blend_add; x->x_thing = GL_BLEND;} + else if (s == gensym("depth_test")) {x->x_setup = 0; x->x_thing = GL_DEPTH_TEST;} + + /* unkown command: do nothing */ + else { + post ("3dp_state: unknown flag %s", s->s_name); + pd_free((void *)x); + return 0; + } + + /* create additional inlet */ + pdp_base_add_gen_inlet(x, gensym("float"), gensym("flag")); + + /* create dpd outlets */ + pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_state_process_left, 0); + pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_state_process_right, 0); + + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_3d_state_setup(void) +{ + + + pdp_3d_state_class = class_new(gensym("3dp_toggle"), (t_newmethod)pdp_3d_state_new, + (t_method)pdp_3d_state_free, sizeof(t_pdp_3d_state), 0, A_SYMBOL, A_DEFFLOAT, A_NULL); + + pdp_3dp_base_setup(pdp_3d_state_class); + class_addmethod(pdp_3d_state_class, (t_method)pdp_3d_state_flag, gensym("flag"), A_FLOAT, A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/opengl/modules/pdp_3d_subcontext.c b/opengl/modules/pdp_3d_subcontext.c new file mode 100644 index 0000000..11017e2 --- /dev/null +++ b/opengl/modules/pdp_3d_subcontext.c @@ -0,0 +1,116 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include <GL/gl.h> +#include "pdp_opengl.h" +#include "pdp_3dp_base.h" + +typedef struct pdp_3d_subcontext_struct +{ + t_pdp_3dp_base x_base; + int x_width; + int x_height; + +} t_pdp_3d_subcontext; + + + +static void pdp_3d_subcontext_process_right(t_pdp_3d_subcontext *x) +{ + int p = pdp_3dp_base_get_context_packet(x); + if (-1 != p){ + + /* set subdims */ + pdp_packet_3Dcontext_set_subwidth(p, x->x_width); + pdp_packet_3Dcontext_set_subheight(p, x->x_height); + + /* reinit everything */ + pdp_packet_3Dcontext_set_rendering_context(p); + pdp_packet_3Dcontext_setup_3d_context(p); + + } +} +static void pdp_3d_subcontext_process_left(t_pdp_3d_subcontext *x) +{ + int p = pdp_3dp_base_get_context_packet(x); + if (-1 != p){ + + /* restore subdims */ + pdp_packet_3Dcontext_set_subwidth(p, pdp_packet_3Dcontext_width(p)); + pdp_packet_3Dcontext_set_subheight(p, pdp_packet_3Dcontext_height(p)); + + /* re-init everything */ + pdp_packet_3Dcontext_set_rendering_context(p); + pdp_packet_3Dcontext_setup_3d_context(p); + + } + +} + +t_class *pdp_3d_subcontext_class; + + + +void pdp_3d_subcontext_free(t_pdp_3d_subcontext *x) +{ + pdp_3dp_base_free(x); +} + +void *pdp_3d_subcontext_new(t_floatarg w, t_floatarg h) +{ + t_pdp_3d_subcontext *x = (t_pdp_3d_subcontext *)pd_new(pdp_3d_subcontext_class); + + /* super init */ + pdp_3dp_base_init(x); + + + /* create dpd outlets */ + pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_subcontext_process_left, 0); + pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_subcontext_process_right, 0); + + x->x_width = (w < 0) ? 64 : w; + x->x_height = (h < 0) ? 64 : h; + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_3d_subcontext_setup(void) +{ + + + pdp_3d_subcontext_class = class_new(gensym("3dp_subcontext"), (t_newmethod)pdp_3d_subcontext_new, + (t_method)pdp_3d_subcontext_free, sizeof(t_pdp_3d_subcontext), 0, A_FLOAT, A_FLOAT, A_NULL); + + pdp_3dp_base_setup(pdp_3d_subcontext_class); + +} + +#ifdef __cplusplus +} +#endif diff --git a/opengl/modules/pdp_3d_view.c b/opengl/modules/pdp_3d_view.c new file mode 100644 index 0000000..2317703 --- /dev/null +++ b/opengl/modules/pdp_3d_view.c @@ -0,0 +1,231 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include <GL/gl.h> +#include "pdp_opengl.h" +#include "pdp_3dp_base.h" + + + +/* PD OBJECT */ +typedef struct _pdp_3d_view +{ + t_pdp_3dp_base x_base; + t_pdp_dpd_commandfactory x_clist; + + float x_p0; + float x_p1; + float x_p2; + float x_p3; + t_pdp_method x_method; + + + int x_inlets; +} t_pdp_3d_view; + + +/* COMMAND OBJECT */ +typedef struct _viewcommand +{ + t_pdp_dpd_command x_head; // viewcommand base + t_pdp_3d_view *x_x; // command owner + int x_context_packet; + float x_p0; + float x_p1; + float x_p2; + float x_p3; + +} t_viewcommand; + + + + +/* COMMAND OBJECT METHODS */ + +/* rotate about the negative z axis */ +static void view_rot2d(t_viewcommand *x) {glRotatef(x->x_p0, 0, 0, -1);} + +/* rotate about the positive x,y,z axis */ +static void view_rotx(t_viewcommand *x) {glRotatef(x->x_p0, 1, 0, 0);} +static void view_roty(t_viewcommand *x) {glRotatef(x->x_p0, 0, 1, 0);} +static void view_rotz(t_viewcommand *x) {glRotatef(x->x_p0, 0, 0, 1);} +static void view_rota(t_viewcommand *x) {glRotatef(x->x_p3, x->x_p0, x->x_p1, x->x_p2);} + +/* translate along an axis */ +static void view_transx(t_viewcommand *x) {glTranslatef(x->x_p0, 0, 0);} +static void view_transy(t_viewcommand *x) {glTranslatef(0, x->x_p0, 0);} +static void view_transz(t_viewcommand *x) {glTranslatef(0, 0, x->x_p0);} +static void view_transxyz(t_viewcommand *x) {glTranslatef(x->x_p0, x->x_p1, x->x_p2);} + +/* rotate about the positive x,y,z axis */ +static void view_scalex(t_viewcommand *x) {glScalef(x->x_p0, 1, 1);} +static void view_scaley(t_viewcommand *x) {glScalef(1, x->x_p0, 1);} +static void view_scalez(t_viewcommand *x) {glScalef(1, 1, x->x_p0);} +static void view_scale(t_viewcommand *x) {glScalef(x->x_p0, x->x_p0, x->x_p0);} + +/* specials */ +static void view_reset_3d(t_viewcommand *x) {pdp_packet_3Dcontext_setup_3d_context(x->x_context_packet);} +static void view_scale_aspect(t_viewcommand *x) {glScalef(pdp_packet_3Dcontext_subaspect(x->x_context_packet),1,1);} + + +/* process command */ +static void view_process(t_viewcommand *x) +{ + int p = x->x_context_packet; + + /* check if it's a valid context buffer we can draw in */ + if (pdp_packet_3Dcontext_isvalid(p)){ + + /* setup rendering context */ + pdp_packet_3Dcontext_set_rendering_context(p); + + /* call the generating method */ + if (x->x_x->x_method) (*x->x_x->x_method)(x); + } + + /* suicide */ + pdp_dpd_command_suicide(x); +} + + + +/* command object factory method */ +void *pdp_3d_view_get_command_object(t_pdp_3d_view *x) +{ + t_viewcommand *c = (t_viewcommand *)pdp_dpd_commandfactory_get_new_command(&x->x_clist); + c->x_p0 = x->x_p0; + c->x_p1 = x->x_p1; + c->x_p2 = x->x_p2; + c->x_p3 = x->x_p3; + c->x_context_packet = pdp_3dp_base_get_context_packet(x); + c->x_x = x; + + return c; +} + + + +/* PD OBJECT METHODS */ + +static void pdp_3d_view_p0(t_pdp_3d_view *x, t_floatarg f){x->x_p0 = f;} +static void pdp_3d_view_p1(t_pdp_3d_view *x, t_floatarg f){x->x_p1 = f;} +static void pdp_3d_view_p2(t_pdp_3d_view *x, t_floatarg f){x->x_p2 = f;} +static void pdp_3d_view_p3(t_pdp_3d_view *x, t_floatarg f){x->x_p3 = f;} + + +t_class *pdp_3d_view_class; + + + +void pdp_3d_view_free(t_pdp_3d_view *x) +{ + pdp_dpd_commandfactory_free(&x->x_clist); + pdp_3dp_base_free(x); +} + +void *pdp_3d_view_new(t_symbol *s, t_floatarg p0, t_floatarg p1, t_floatarg p2, t_floatarg p3) +{ + t_pdp_3d_view *x = (t_pdp_3d_view *)pd_new(pdp_3d_view_class); + char param[] = "p0"; + int i; + + /* super init */ + pdp_3dp_base_init(x); + + x->x_p0 = p0; + x->x_p1 = p1; + x->x_p2 = p2; + x->x_p3 = p3; + + /* find out which transform we need to apply */ + if (s == gensym("rot2d")) {x->x_method = (t_pdp_method)view_rot2d; x->x_inlets = 1;} + + else if (s == gensym("rotx")) {x->x_method = (t_pdp_method)view_rotx; x->x_inlets = 1;} + else if (s == gensym("roty")) {x->x_method = (t_pdp_method)view_roty; x->x_inlets = 1;} + else if (s == gensym("rotz")) {x->x_method = (t_pdp_method)view_rotz; x->x_inlets = 1;} + else if (s == gensym("rota")) {x->x_method = (t_pdp_method)view_rota; x->x_inlets = 4;} + + else if (s == gensym("transx")) {x->x_method = (t_pdp_method)view_transx; x->x_inlets = 1;} + else if (s == gensym("transy")) {x->x_method = (t_pdp_method)view_transy; x->x_inlets = 1;} + else if (s == gensym("transz")) {x->x_method = (t_pdp_method)view_transz; x->x_inlets = 1;} + else if (s == gensym("transxyz")) {x->x_method = (t_pdp_method)view_transxyz; x->x_inlets = 3;} + + else if (s == gensym("scalex")) {x->x_method = (t_pdp_method)view_scalex; x->x_inlets = 1;} + else if (s == gensym("scaley")) {x->x_method = (t_pdp_method)view_scaley; x->x_inlets = 1;} + else if (s == gensym("scalez")) {x->x_method = (t_pdp_method)view_scalez; x->x_inlets = 1;} + else if (s == gensym("scale")) {x->x_method = (t_pdp_method)view_scale; x->x_inlets = 1;} + + else if (s == gensym("scale_aspect")) {x->x_method = (t_pdp_method)view_scale_aspect; x->x_inlets = 0;} + else if (s == gensym("reset")) {x->x_method = (t_pdp_method)view_reset_3d; x->x_inlets = 0;} + + else { + post("pdp_view: view transformation %s not found", s->s_name); + x->x_method = 0; + x->x_inlets = 0; + } + + /* create additional inlets */ + for(i=0; i<x->x_inlets; i++){ + pdp_base_add_gen_inlet(x, gensym("float"), gensym(param)); + param[1]++; + } + + /* create dpd outlet */ + pdp_3dp_base_add_outlet(x, (t_pdp_method)view_process, 0); + + /* init command factory */ + pdp_dpd_commandfactory_init(&x->x_clist, sizeof(t_viewcommand)); + + /* register command factory method */ + pdp_dpd_base_register_command_factory_method(x, (t_pdp_newmethod)pdp_3d_view_get_command_object); + + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_3d_view_setup(void) +{ + + + pdp_3d_view_class = class_new(gensym("3dp_view"), (t_newmethod)pdp_3d_view_new, + (t_method)pdp_3d_view_free, sizeof(t_pdp_3d_view), 0, A_SYMBOL, + A_DEFFLOAT,A_DEFFLOAT,A_DEFFLOAT,A_DEFFLOAT, A_NULL); + + pdp_3dp_base_setup(pdp_3d_view_class); + + class_addmethod(pdp_3d_view_class, (t_method)pdp_3d_view_p0, gensym("p0"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_3d_view_class, (t_method)pdp_3d_view_p1, gensym("p1"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_3d_view_class, (t_method)pdp_3d_view_p2, gensym("p2"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_3d_view_class, (t_method)pdp_3d_view_p3, gensym("p3"), A_DEFFLOAT, A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/opengl/modules/pdp_3d_windowcontext.c b/opengl/modules/pdp_3d_windowcontext.c new file mode 100644 index 0000000..4e7aa93 --- /dev/null +++ b/opengl/modules/pdp_3d_windowcontext.c @@ -0,0 +1,232 @@ +/* + * Pure Data Packet module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +#include <GL/gl.h> +#include "pdp_opengl.h" +#include "pdp_3dp_base.h" + +typedef struct pdp_3d_windowcontext_struct +{ + t_pdp_3dp_base x_base; + int x_width; + int x_height; + t_outlet *x_eventout; + int x_finish_queue_id[2]; + int x_finish_queue_id_current; + +} t_pdp_3d_windowcontext; + + +static void pdp_3d_windowcontext_sendfinish(t_pdp_3d_windowcontext *x) +{ + PDP_ASSERT(x); + PDP_ASSERT(x->x_eventout); + outlet_symbol(x->x_eventout, gensym("done")); +} + +/* outlet methods */ + +/* called before the context is propagated */ +static void pdp_3d_windowcontext_clearbuffer(t_pdp_3d_windowcontext *x) +{ + int p = pdp_3dp_base_get_context_packet(x); + //post("setting up render buffer"); + + // for multipass rendering + //pdp_packet_3Dcontext_set_subwidth(p, 320); + //pdp_packet_3Dcontext_set_subheight(p, 240); + + pdp_packet_3Dcontext_set_rendering_context(p); + pdp_packet_3Dcontext_setup_3d_context(p); + + /* clear buffer */ + //glScissor(0,0, + // pdp_packet_3Dcontext_subwidth(p), + // pdp_packet_3Dcontext_subheight(p)); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + + +} + +/* called after context is propagated */ +static void pdp_3d_windowcontext_swapbuffer(t_pdp_3d_windowcontext *x) +{ + int p = pdp_3dp_base_get_context_packet(x); + //post("displaying render buffer"); + //pdp_packet_3Dcontext_set_rendering_context(p); + pdp_packet_3Dcontext_win_swapbuffers(p); + //pdp_packet_3Dcontext_unset_rendering_context(p); +} + +void pdp_3d_windowcontext_resize(t_pdp_3d_windowcontext *x, t_floatarg width, t_floatarg height) +{ + int w = (int)width; + int h = (int)height; + int p = pdp_3dp_base_get_context_packet(x); + if ((w>0) && (h>0)){ + pdp_packet_3Dcontext_win_resize(p, w, h); + x->x_width = w; + x->x_height = h; + } +} + +void pdp_3d_windowcontext_open(t_pdp_3d_windowcontext *x) +{ + int p = pdp_3dp_base_get_context_packet(x); + if (-1 == p){ + p = pdp_packet_new_3Dcontext_win(); + pdp_3d_windowcontext_resize(x, x->x_width, x->x_height); + pdp_3dp_base_set_context_packet(x, p); + } + +} +void pdp_3d_windowcontext_close(t_pdp_3d_windowcontext *x) +{ + t_pdp_procqueue *q = pdp_3dp_base_get_queue(x); + + /* flush all pending tasks in the queue */ + //post("preflush"); + pdp_procqueue_flush(q); + //post("postflush"); + + /* now it is safe to delete the context packet */ + pdp_packet_delete(pdp_3dp_base_move_context_packet(x)); + + //post("deleted"); +} + +void pdp_3d_windowcontext_cursor(t_pdp_3d_windowcontext *x, t_floatarg f) +{ + int p = pdp_3dp_base_get_context_packet(x); + bool toggle = (f != 0.0f); + pdp_packet_3Dcontext_win_cursor(p, toggle); +} + + + +static void pdp_3d_windowcontext_bang(t_pdp_3d_windowcontext *x) +{ + int p; + int cur = x->x_finish_queue_id_current; + t_pdp_list *eventlist; + + /* check if at least recent processing chain is done (two chains busy = max pipeline depth) */ + if (-1 != x->x_finish_queue_id[cur]){ + //post("pdp_3d_windowcontext_bang: bang ignored (previous rendering not finished)"); + return; + } + + /* create a window context if needed */ + pdp_3d_windowcontext_open(x); + + /* get events and send to outlet */ + p = pdp_3dp_base_get_context_packet(x); + eventlist = pdp_packet_3Dcontext_win_get_eventlist(p); + if (eventlist){ + t_pdp_atom *a; + for (a=eventlist->first; a; a=a->next){ + outlet_pdp_list(x->x_eventout, a->w.w_list); + } + pdp_tree_free(eventlist); + } + + /* bang base */ + pdp_3dp_base_bang(x); + + /* add a dummy process to the queue for synchro */ + pdp_procqueue_add(pdp_3dp_base_get_queue(x), x, 0, 0, &x->x_finish_queue_id[cur]); + x->x_finish_queue_id_current = !cur; + + + +} + + +static void pdp_3d_windowcontext_free(t_pdp_3d_windowcontext *x) +{ + pdp_3d_windowcontext_close(x); + pdp_3dp_base_free(x); + +} + +t_class *pdp_3d_windowcontext_class; + + +void *pdp_3d_windowcontext_new(void) +{ + /* allocate */ + t_pdp_3d_windowcontext *x = (t_pdp_3d_windowcontext *)pd_new(pdp_3d_windowcontext_class); + + x->x_width = 320; + x->x_height = 240; + x->x_finish_queue_id[0] = -1; + x->x_finish_queue_id[1] = -1; + x->x_finish_queue_id_current =0; + + /* init super: this is mandatory */ + pdp_3dp_base_init(x); + pdp_3dp_base_disable_active_inlet(x); + + /* set the dpd processing methods & outlets */ + pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_windowcontext_clearbuffer, 0); + pdp_3dp_base_add_cleanup(x, (t_pdp_method)pdp_3d_windowcontext_swapbuffer, (t_pdp_method)pdp_3d_windowcontext_sendfinish); + + /* add event outlet */ + x->x_eventout = outlet_new((t_object *)x, &s_anything); + + + return (void *)x; +} + + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_3d_windowcontext_setup(void) +{ + /* create a standard pd class */ + pdp_3d_windowcontext_class = class_new(gensym("3dp_windowcontext"), (t_newmethod)pdp_3d_windowcontext_new, + (t_method)pdp_3d_windowcontext_free, sizeof(t_pdp_3d_windowcontext), 0, A_NULL); + + /* inherit pdp base class methods */ + pdp_3dp_base_setup(pdp_3d_windowcontext_class); + + /* register methods */ + class_addbang(pdp_3d_windowcontext_class, pdp_3d_windowcontext_bang); + + class_addmethod(pdp_3d_windowcontext_class, (t_method)pdp_3d_windowcontext_open, gensym("open"), A_NULL); + class_addmethod(pdp_3d_windowcontext_class, (t_method)pdp_3d_windowcontext_close, gensym("close"), A_NULL); + class_addmethod(pdp_3d_windowcontext_class, (t_method)pdp_3d_windowcontext_resize, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_3d_windowcontext_class, (t_method)pdp_3d_windowcontext_resize, gensym("size"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_3d_windowcontext_class, (t_method)pdp_3d_windowcontext_cursor, gensym("cursor"), A_FLOAT, A_NULL); + +} + + + +#ifdef __cplusplus +} +#endif diff --git a/opengl/system/Makefile b/opengl/system/Makefile new file mode 100644 index 0000000..0a31482 --- /dev/null +++ b/opengl/system/Makefile @@ -0,0 +1,8 @@ +include ../Makefile.config + +all: pdp_texture.o pdp_3Dcontext_glx.o pdp_3Dcontext_common.o \ + pdp_opengl.o pdp_3dp_base.o pdp_mesh.o setup.o + +clean: + rm -rf *~ *.o + diff --git a/opengl/system/pdp_3Dcontext_common.c b/opengl/system/pdp_3Dcontext_common.c new file mode 100644 index 0000000..185e2be --- /dev/null +++ b/opengl/system/pdp_3Dcontext_common.c @@ -0,0 +1,267 @@ + +/* + * OpenGL Extension Module for pdp - pbuffer packet implementation + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 code uses glx. i don't know if it is worth to take into + account portabiliy. since it will take a while until pdp runs + on anything else than linux. but in any case, providing a windows/osx + implementation here should not be too difficult.. +*/ + +#include "pdp_3Dcontext.h" +#include <GL/gl.h> +//#include <GL/glx.h> +#include <GL/glu.h> +//#include <GL/glut.h> + +#define D if (0) + +/* constructor */ + +/* pbuf operators */ + +u32 pdp_packet_3Dcontext_width(int packet) +{ + t_3Dcontext *c = pdp_packet_3Dcontext_info(packet); + if (c) return c->width; + else return 0; +} + +u32 pdp_packet_3Dcontext_height(int packet) +{ + t_3Dcontext *c = pdp_packet_3Dcontext_info(packet); + if (c) return c->height; + else return 0; +} + +u32 pdp_packet_3Dcontext_subwidth(int packet) +{ + t_3Dcontext *c = pdp_packet_3Dcontext_info(packet); + if (c) return c->sub_width; + else return 0; +} + + +u32 pdp_packet_3Dcontext_subheight(int packet) +{ + t_3Dcontext *c = pdp_packet_3Dcontext_info(packet); + if (c) return c->sub_height; + else return 0; +} + + +void pdp_packet_3Dcontext_set_subwidth(int packet, u32 w) +{ + t_3Dcontext *c = pdp_packet_3Dcontext_info(packet); + if (c) c->sub_width = w; +} + + +void pdp_packet_3Dcontext_set_subheight(int packet, u32 h) +{ + t_3Dcontext *c = pdp_packet_3Dcontext_info(packet); + if (c) c->sub_height = h; +} + + +float pdp_packet_3Dcontext_subaspect(int packet) +{ + t_3Dcontext *c = pdp_packet_3Dcontext_info(packet); + if (c) return (float)c->sub_width/c->sub_height; + else return 0; +} + +int pdp_packet_3Dcontext_isvalid(int packet) +{ + t_pdp *header = pdp_packet_header(packet); + t_3Dcontext *c = pdp_packet_3Dcontext_info(packet); + + if (!header) return 0; + if (!c) return 0; + if (PDP_3DCONTEXT != header->type) return 0; + return 1; +} + +t_3Dcontext *pdp_packet_3Dcontext_info(int packet) +{ + t_pdp *header = pdp_packet_header(packet); + if (!header) return 0; + if (PDP_3DCONTEXT != header->type) return 0; + return (t_3Dcontext *)&header->info.raw; +} + + + +void pdp_llconv_flip_top_bottom(char *data, int width, int height, int pixelsize); + +int pdp_packet_3Dcontext_snap_to_bitmap(int packet, int w, int h) +{ + int x, y, new_p, i; + char *data = 0; + // char r; + // int extra = 5; + + if (!pdp_packet_3Dcontext_isvalid(packet)) goto error; + + x = pdp_packet_3Dcontext_subwidth(packet); + y = pdp_packet_3Dcontext_subheight(packet); + + x = (x - w) >> 1; + y = (y - h) >> 1; + x = (x < 0 ) ? 0 : x; + y = (y < 0 ) ? 0 : y; + + new_p = pdp_packet_new_bitmap_rgb(w, h); + data = (char *)pdp_packet_data(new_p); + if (-1 == new_p || !data) goto error; + pdp_packet_3Dcontext_set_rendering_context(packet); + + // D post("BEGIN READPIXELS %d %d %d %d %x", w, h, x, y, data); + + //for (i=0; i<w*h; i++){ + // data[3*i] = 255; + // data[3*i+1] = 255; + // data[3*i+2] = 0; + //} + // r = random(); + // data[w*h*3] = r; + + /* seems nvidia drivers 4191 have a bug + when w % 4 is not zero */ + glReadPixels(x,y, w ,h,GL_RGB,GL_UNSIGNED_BYTE, data); + + /* inplace swap top to bottom (textures and buffers have + another coordinate system than standard images) + instead of fixing this by using a different texture coordinate + system, a memory swap is performed. this is more expensive + but eliminates hassle when converting between buffers, textures + and bitmaps */ + + pdp_llconv_flip_top_bottom(data, w, h, 3); + + // if (r != data[w*h*3]) post("PANIC"); + + // post("END READPIXELS %d %d", w, h); + + + return new_p; + + error: + return -1; + +} + + + + +/* move these to the pdp_3d_context object: they're too specific */ + +/* setup for 2d operation from pbuf dimensions */ +void pdp_packet_3Dcontext_setup_2d_context(int p) +{ + u32 w; + u32 h; + float asp; + if (!pdp_packet_3Dcontext_isvalid(p)) return; + w = pdp_packet_3Dcontext_subwidth(p); + h = pdp_packet_3Dcontext_subheight(p); + asp = pdp_packet_3Dcontext_subaspect(p); + + + /* set the viewport to the size of the sub frame */ + glViewport(0, 0, w, h); + + /* set orthogonal projection, with a relative frame size of (2asp x 2) */ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluOrtho2D(0, 2*asp, 0, 2); + + /* set the center of view */ + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(asp, 1, 0); + glScalef(1,-1,1); + + +} + +/* setup for 3d operation from pbuf dimensions */ +void pdp_packet_3Dcontext_setup_3d_context(int p) +{ + u32 w; + u32 h; + int i; + float asp; + float m_perspect[] = {-1.f, /* left */ + 1.f, /* right */ + -1.f, /* bottom */ + 1.f, /* top */ + 1.f, /* front */ + 20.f};/* back */ + + if (!pdp_packet_3Dcontext_isvalid(p)) return; + w = pdp_packet_3Dcontext_subwidth(p); + h = pdp_packet_3Dcontext_subheight(p); + asp = pdp_packet_3Dcontext_subaspect(p); + + + /* set the viewport to the size of the sub frame */ + glViewport(0, 0, w, h); + + /* set orthogonal projection, with a relative frame size of (2asp x 2) */ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(m_perspect[0] * asp, m_perspect[1] * asp, // left, right + m_perspect[2], m_perspect[3], // bottom, top + m_perspect[4], m_perspect[5]); // front, back + + /* reset texture matrix */ + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + + + /* set the center of view */ + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt(0, 0, 4, 0, 0, 0, 0, 1, 0); + //glTranslatef(asp, 1, 0); + + + glEnable(GL_DEPTH_TEST); + glEnable(GL_AUTO_NORMAL); + glEnable(GL_NORMALIZE); + glShadeModel(GL_SMOOTH); + //glShadeModel(GL_FLAT); + + + /* disable everything that is enabled in other modules + this resets the ogl state to its initial conditions */ + glDisable(GL_LIGHTING); + for (i=0; i<8; i++) glDisable(GL_LIGHT0 + i); + glDisable(GL_COLOR_MATERIAL); + + +} + + +void pdp_3Dcontext_common_setup(void) +{ +} diff --git a/opengl/system/pdp_3Dcontext_glx.c b/opengl/system/pdp_3Dcontext_glx.c new file mode 100644 index 0000000..ac25a13 --- /dev/null +++ b/opengl/system/pdp_3Dcontext_glx.c @@ -0,0 +1,393 @@ + +/* + * OpenGL Extension Module for pdp - opengl system stuff + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 file contains the platform dependent opengl setup routines (glx) + and pdp_packet_3Dcontext methods */ + +#include "pdp_opengl.h" +#include "pdp_xwindow.h" +#include "pdp_internals.h" +#include <GL/gl.h> +#include <GL/glx.h> +#include <GL/glu.h> +//#include <GL/glut.h> + +/* all symbols are C-style */ +#ifdef __cplusplus +//extern "C" +//{ +#endif + +// this is buggy: disabled +#define PRIVATE_CONTEXT 0 + + +/* structure to hold the (platform dependent) gl environment setup */ +typedef struct _gl_env +{ + bool initialized; /* data structure is consistent */ + + XVisualInfo *visual; /* the visual info structure for the context */ + GLXContext context; /* the rendering context used to render to windows or pbufs */ + GLXFBConfig *config; /* the framebuffer config object */ + + t_pdp_xdisplay *xdpy; /* pdp's x display object */ + + //Display *dpy; /* x display connection */ + //int screen; /* x screen */ + int last_context_packet; /* the packet that is currently rendered too (for caching) */ +} t_gl_env; + +static t_gl_env pdp_glx_env; +static t_pdp_class *context_class; + +/* PDP_3DCONTEXT packet methods */ + +/* set/unset ogl rendering context to pbuf */ +void pdp_packet_3Dcontext_set_rendering_context(int packet) +{ + t_3Dcontext *c = pdp_packet_3Dcontext_info(packet); + + + if (!c) return; + + + /* don't do a glx call if the context is still the same */ + if (pdp_glx_env.last_context_packet == packet) return; + + //post("new current context is %d", packet); + + + /* pbuffer */ + switch(c->encoding){ + case PDP_3DCONTEXT_WINDOW: + //glFinish(); + //glXMakeCurrent(pdp_glx_env.dpy, ((t_pdp_xwindow *)c->drawable)->win, pdp_glx_env.context); + glXMakeCurrent(pdp_glx_env.xdpy->dpy, ((t_pdp_xwindow *)c->drawable)->win, (GLXContext)c->context); + pdp_glx_env.last_context_packet = packet; + break; + case PDP_3DCONTEXT_PBUFFER: + //glXMakeCurrent(pdp_glx_env.dpy, (GLXPbuffer)c->drawable, pdp_glx_env.context); + //glXMakeContextCurrent(c->dpy, c->drawable.pbuf, c->drawable.pbuf, c->context); + pdp_glx_env.last_context_packet = -1; + break; + default: + pdp_glx_env.last_context_packet = -1; + break; + } + +} + +void pdp_packet_3Dcontext_unset_rendering_context(int packet) +{ + t_3Dcontext *c = pdp_packet_3Dcontext_info(packet); + if (!c) return; + + /* pbuffer */ + switch(c->encoding){ + case PDP_3DCONTEXT_WINDOW: + glXMakeCurrent(pdp_glx_env.xdpy->dpy, None, NULL); + pdp_glx_env.last_context_packet = -1; + break; + case PDP_3DCONTEXT_PBUFFER: + //glXMakeCurrent(pdp_glx_env.dpy, None, NULL); + //glXMakeContextCurrent(c->dpy, c->drawable.pbuf, c->drawable.pbuf, c->context); + break; + default: + break; + } +} + + +/* cons/des */ +static void _3Dcontext_clone(t_pdp *dst, t_pdp *src) +{ + post("ERROR: clone not supported for 3Dcontext packets"); +} + +static void _3Dcontext_copy(t_pdp *dst, t_pdp *src) +{ + post("ERROR: copy not supported for 3Dcontext packets"); +} + +static void _3Dcontext_reinit(t_pdp *dst) +{ + /* leave the packet as is */ +} +static void _3Dcontext_cleanup(t_pdp *dst) +{ + t_3Dcontext *c = (t_3Dcontext *)(&dst->info.raw); + + /* reset context packet cache, in case this packet was the current context. */ + pdp_glx_env.last_context_packet = -1; + + switch(c->encoding){ + case PDP_3DCONTEXT_WINDOW: +#if PRIVATE_CONTEXT + glXDestroyContext (pdp_glx_env.dpy, (GLXContext)c->context); +#endif + pdp_xwindow_cleanup((t_pdp_xwindow *)c->drawable); + free(c->drawable); + break; + + case PDP_3DCONTEXT_PBUFFER: + break; + //glXDestroyContext(c->dpy, c->context); + //glXDestroyPbuffer(c->dpy, c->drawable.pbuf); + default: + break; + } +} + + +/* setup packet methods */ +static void _3Dcontext_init_methods(t_pdp *header) +{ + header->theclass = context_class; + header->flags = PDP_FLAG_DONOTCOPY; +} + + + +/* window specific methods */ + + +void _pdp_3Dcontext_set_window_size(t_3Dcontext *c, t_pdp_xwindow *xwin) +{ + c->width = xwin->winwidth; + c->sub_width = xwin->winwidth; + c->height = xwin->winheight; + c->sub_height= xwin->winheight; +} + +/* resize the window */ +void pdp_packet_3Dcontext_win_resize(int packet, int width, int height) +{ + t_pdp_xwindow *xwin; + t_3Dcontext *c = pdp_packet_3Dcontext_info(packet); + if (!c) return; + if (PDP_3DCONTEXT_WINDOW != c->encoding) return; + xwin = (t_pdp_xwindow *)c->drawable; + pdp_xwindow_resize(xwin, width, height); + _pdp_3Dcontext_set_window_size(c, xwin); +} + + +t_pdp_list *pdp_packet_3Dcontext_win_get_eventlist(int packet) +{ + t_pdp_list *eventlist; + t_pdp_xwindow *xwin; + t_3Dcontext *c = pdp_packet_3Dcontext_info(packet); + if (!c) return 0; + if (PDP_3DCONTEXT_WINDOW != c->encoding) return 0; + xwin = (t_pdp_xwindow *)c->drawable; + eventlist = pdp_xwindow_get_eventlist(xwin); + _pdp_3Dcontext_set_window_size(c, xwin); + return eventlist; +} + +void pdp_packet_3Dcontext_win_cursor(int packet, bool toggle) +{ + t_pdp_xwindow *xwin; + t_3Dcontext *c = pdp_packet_3Dcontext_info(packet); + if (!c) return; + if (PDP_3DCONTEXT_WINDOW != c->encoding) return; + xwin = (t_pdp_xwindow *)c->drawable; + pdp_xwindow_cursor(xwin, toggle); + +} + +void pdp_packet_3Dcontext_win_swapbuffers(int packet) +{ + t_pdp_xwindow *xwin; + t_3Dcontext *c = pdp_packet_3Dcontext_info(packet); + if (!c) return; + if (PDP_3DCONTEXT_WINDOW != c->encoding) return; + xwin = (t_pdp_xwindow *)c->drawable; + glXSwapBuffers(xwin->xdisplay->dpy,xwin->win); + //glFinish(); + +} + + +/* constructors */ + +/* construct (or reuse) a window packet */ +int pdp_packet_new_3Dcontext_win(void) +{ + /* $$$FIXME: this assumes packet can't be reused */ + int p = pdp_packet_new(PDP_3DCONTEXT, 0); + t_pdp_xwindow *xwin; + t_3Dcontext *c; + t_pdp *header = pdp_packet_header(p); + if (!header) return -1; /* pool full ? */ + c = (t_3Dcontext *)&header->info.raw; + + if (c->drawable){ + xwin = (t_pdp_xwindow *)c->drawable; + } + else{ + xwin = (t_pdp_xwindow *)malloc(sizeof(*xwin)); + } + + pdp_xwindow_init(xwin); + pdp_xwindow_create_on_display(xwin, pdp_glx_env.xdpy); + + /* init subheader */ +#if PRIVATE_CONTEXT + if (NULL == (c->context = (void *)glXCreateContext(pdp_glx_env.dpy, pdp_glx_env.visual, pdp_glx_env.context, True))){ + post("pdp_packet_new_3Dcontext_wind: ERROR: can't create rendering context"); + } +#else + c->context = (void *)pdp_glx_env.context; +#endif + c->drawable = xwin; + c->encoding = PDP_3DCONTEXT_WINDOW; + _pdp_3Dcontext_set_window_size(c, xwin); + + /* init packet methods */ + _3Dcontext_init_methods(header); + + /* init header */ + header->desc = pdp_gensym("3Dcontext/window"); + header->flags = PDP_FLAG_DONOTCOPY; + + return p; + + +} + +/* pbuf constructor */ +int pdp_packet_new_3Dcontext_pbuf(u32 width, u32 height, u32 depth) +{ + post("ERROR: 3Dcontext/pbuffer packets not implemented"); + return -1; +} + + +/* this is a notifier sent when the processing thread which + executes gl commands is changed. we need to release the current context + before another thread can take it. */ +void pdp_3Dcontext_prepare_for_thread_switch(void) +{ + pdp_packet_3Dcontext_unset_rendering_context(pdp_glx_env.last_context_packet); +} + + + + + +/* setup routine */ +static void pdp_3Dcontext_glx_setup_inthread(void) +{ + /* this opens the connection to the x server and creates a render context + for windows (glx < 1.3) or windows/pbufs (glx >= 1.3) */ + + static int dblBuf24[] = {GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_ALPHA_SIZE, 0, + GLX_DEPTH_SIZE, 1, + GLX_DOUBLEBUFFER, + None}; + + pdp_glx_env.initialized = 0; + + + /* init xlib for thread usage */ + if (!XInitThreads()){ + post("pdp_opengl_system_setup: can't init Xlib for thread usage."); + goto init_failed; + } + + + /* open display: + the first display on the local machine is opened, not DISPLAY. + since pdp_opengl is all about direct rendering, and there + is no way to specify another display, or even close it and + open it again, this seems to be the "least surprise" solution. + it enables the pd interface to be displayed on another display, + using the DISPLAY environment variable. */ + + + + + + if (NULL == (pdp_glx_env.xdpy = pdp_xdisplay_new(":0"))){ + post("pdp_opengl_system_setup: can't open display"); + goto init_failed; + } + + + /* get visual */ + if (NULL == (pdp_glx_env.visual = glXChooseVisual(pdp_glx_env.xdpy->dpy, pdp_glx_env.xdpy->screen, dblBuf24))){ + post("pdp_opengl_system_setup: can't find appropriate visual"); + goto init_failed_close_dpy; + } + + + /* create a (direct) rendering context */ + if (NULL == (pdp_glx_env.context = glXCreateContext(pdp_glx_env.xdpy->dpy, pdp_glx_env.visual, 0, True))){ + post("pdp_opengl_system_setup: can't create rendering context"); + goto init_failed_close_dpy; + } + + + //post("pdp_opengl_system_setup: pdp_opengl init OK."); + pdp_glx_env.last_context_packet = -1; + pdp_glx_env.initialized = 1; + + /* setup class object */ + context_class = pdp_class_new(pdp_gensym("3Dcontext/*"), 0); + context_class->cleanup = _3Dcontext_cleanup; + context_class->wakeup = _3Dcontext_reinit; + //context_class->clone = _3Dcontext_clone; + context_class->copy = _3Dcontext_copy; + + + /* setup conversion programs: NOT IMPLEMENTED */ + return; + + + init_failed_close_dpy: + pdp_xdisplay_free(pdp_glx_env.xdpy); + pdp_glx_env.xdpy = 0; + init_failed: + post("pdp_opengl_system_setup: FATAL ERROR: pdp_opengl init failed."); + exit(1); + +} + +/* run the setup routine in the procqueue thread, and wait for it to finish */ +/* NOTE: this seems to make an Xlib deadlock problem go away when running + pd with realtime scheduling. frankly, i'm very puzzled by this problem + and even more by the way this workaround solves it. anyhow... */ +void pdp_3Dcontext_glx_setup(void) +{ + t_pdp_procqueue *q = pdp_opengl_get_queue(); + pdp_procqueue_add(q, 0, pdp_3Dcontext_glx_setup_inthread, 0, 0); + pdp_procqueue_flush(q); +} + +#ifdef __cplusplus +//} +#endif diff --git a/opengl/system/pdp_3dp_base.c b/opengl/system/pdp_3dp_base.c new file mode 100644 index 0000000..5190c11 --- /dev/null +++ b/opengl/system/pdp_3dp_base.c @@ -0,0 +1,30 @@ +#include "pdp_opengl.h" +#include "pdp_3dp_base.h" + +#define THIS(b) t_pdp_3pd_base *b = (t_pdp_3pd_base *)x + +/* destructor */ +void pdp_3dp_base_free(void *x) +{ + // free super + pdp_dpd_base_free(x); +} + +/* init method */ +void pdp_3dp_base_init(void *x) +{ + // init super + pdp_dpd_base_init(x); + + // set processing queue to pdp_opengl system queue + pdp_dpd_base_set_queue(x, pdp_opengl_get_queue()); + +} + +/* class setup method */ +void pdp_3dp_base_setup(t_class *class) +{ + // setup super + pdp_dpd_base_setup(class); +} + diff --git a/opengl/system/pdp_mesh.c b/opengl/system/pdp_mesh.c new file mode 100644 index 0000000..b319d1e --- /dev/null +++ b/opengl/system/pdp_mesh.c @@ -0,0 +1,560 @@ +/* + * Pure Data Packet module. mesh implementation + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +/* a very naive approach to triangular meshes */ + + +// $$TODO: some serious memory corruption in this file our the list implementation + + +#include <math.h> + +#include "pdp.h" +#include "pdp_mesh.h" + + +/* VERTEX methods */ +void vertex_add_triangle(t_vertex *v, t_triangle *t) +{ + pdp_list_add_pointer(v->trilist, t); +} +void vertex_remove_triangle(t_vertex *v, t_triangle *t) +{ + pdp_list_remove_pointer(v->trilist, t); +} +void vertex_add_neighbour(t_vertex *v, t_vertex *neighbour) +{ + pdp_list_add_pointer_to_set(v->vertlist, neighbour); +}; + + +/* constructor/destructors are "private" + they may only be called by the mesh object to ensure + the vector list stays sound (i.e. without duplicates) */ +void _vertex_free(t_vertex *v) +{ + if (!v->trilist) post("WARNING: vertex %x has empty trilist", v); + else{ + pdp_list_free(v->trilist); + v->trilist = 0; + } + if (!v->vertlist) post("WARNING: vertex %x has empty vertlist", v); + { + pdp_list_free(v->vertlist); + v->vertlist = 0; + } + pdp_dealloc(v); +} + +t_vertex *_vertex_new(float *c, float *n) +{ + int k; + t_vertex *v = (t_vertex *) pdp_alloc(sizeof(t_vertex)); + I3(k) v->c[k] = c[k]; + I3(k) v->n[k] = n[k]; + v->trilist = pdp_list_new(0); + v->vertlist = pdp_list_new(0); + return v; +} + + +void vertex_compute_normal_random(t_vertex *v){int k; I3(k) v->n[k] = _rand();} +void vertex_compute_normal_sphere(t_vertex *v){int k; I3(k) v->n[k] = v->c[k];} +void vertex_compute_normal_prism(t_vertex *v) +{ + float scale = 0.0f; + float sum[] = {0.0f, 0.0f, 0.0f}; + int k; + t_pdp_atom* i; + t_pdp_list *vl = v->vertlist; + t_vertex *vtx; + + PDP_POINTER_IN(vl, i, vtx) { + I3(k) sum[k] += vtx->c[k]; + scale = scale + 1.0f; + } + scale = 1.0f / scale; + I3(k) sum[k] *= scale; + I3(k) v->n[k] = v->c[k] - sum[k]; + + //post("computed normal (%f, %f, %f) of vertex (%f, %f, %f)", v->n[0], v->n[1], v->n[2], v->c[0], v->c[1], v->c[2]); +}; +void vertex_compute_normal_average(t_vertex *v) +{ + int triangles = pdp_list_size(v->trilist); + float scale = 1.0f / ((float)triangles); + t_pdp_atom* i; + int k; + t_triangle *t; + + I3(k) v->n[k] = 0; //reset normal + PDP_POINTER_IN(v->trilist, i, t){ + I3(k) v->n[k] += t->n[k]; + } + _vector3_scale(v->n, scale); + + +} + + +float vertex_normalize(t_vertex *v) +{ + return _vector3_normalize(v->c); +} + + +/* TRIANGLE methods */ + +/* create triangle (a connection between 3 vertices): + counterclockwize with facing front + this method is "private" + you can only create triangles as part of a mesh */ +t_triangle *_triangle_new(t_vertex *v0, t_vertex *v1, t_vertex *v2) +{ + int k; + + t_triangle *t = (t_triangle *)pdp_alloc(sizeof(t_triangle)); + + /* store vertex references */ + t->v[0] = v0; + t->v[1] = v1; + t->v[2] = v2; + + /* reset median vertices */ + I3(k) t->m[k] = 0; + + /* connect triangle to vertices */ + vertex_add_triangle(v0, t); + vertex_add_triangle(v1, t); + vertex_add_triangle(v2, t); + + /* connect vertices to vertices */ + vertex_add_neighbour(v0, v1); + vertex_add_neighbour(v0, v2); + vertex_add_neighbour(v1, v0); + vertex_add_neighbour(v1, v2); + vertex_add_neighbour(v2, v0); + vertex_add_neighbour(v2, v1); + + return t; +} + +/* delete a triangle, disconnecting the vertices */ +void _triangle_free(t_triangle *t) +{ + int k; + + /* remove the triangle reference of the vertices */ + I3(k) vertex_remove_triangle(t->v[k], t); + + /* set references to zero (bug catcher) */ + I3(k) t->v[k] = 0; + I3(k) t->m[k] = 0; + + /* free struct */ + pdp_dealloc(t); + +} + +/* get triangle that shares the link between v0 and v1 */ +t_triangle *triangle_neighbour(t_triangle *t, t_vertex *v0, t_vertex *v1) +{ + t_pdp_atom* it; + t_triangle *tri; + PDP_POINTER_IN(v1->trilist, it, tri){ + if (tri != t && pdp_list_contains_pointer(v0->trilist, tri)) return tri; + } + return 0; +} + +/* add a median vector to a link in a triangle + note: vertices must be in triangle, or behaviour is undefined */ +void triangle_add_median(t_triangle *t, t_vertex *v0, t_vertex *v1, t_vertex *median) +{ + + /* link 0 1 */ + if (!((v0 == t->v[2]) || (v1 == t->v[2]))) t->m[0] = median; + + /* link 1 2 */ + else if (!((v0 == t->v[0]) || (v1 == t->v[0]))) t->m[1] = median; + + /* link 2 0 */ + else t->m[2] = median; +} + +void triangle_compute_normal(t_triangle *t) +{ + int k; + float v0[3]; + float v1[3]; + I3(k) v0[k] = t->v[1]->c[k] - t->v[0]->c[k]; + I3(k) v1[k] = t->v[2]->c[k] - t->v[0]->c[k]; + _vector3_cross(v0,v1,t->n); +} + +void triangle_compute_unit_normal(t_triangle *t) +{ + triangle_compute_normal(t); + _vector3_normalize(t->n); +} + +/* MESH methods */ + +/* add and remove methods for vertices and triangles */ +t_vertex *mesh_vertex_add(t_mesh *m, float *c, float *n) +{ + t_vertex *v = _vertex_new(c, n); + pdp_list_add_pointer(m->vertices, v); + return v; +} + +void mesh_vertex_remove(t_mesh *m, t_vertex *v) +{ + pdp_list_remove_pointer(m->vertices, v); + _vertex_free(v); +} + +t_triangle *mesh_triangle_add(t_mesh *m, t_vertex *v0, t_vertex *v1, t_vertex *v2) +{ + t_triangle *t = _triangle_new(v0,v1,v2); + pdp_list_add_pointer(m->triangles, t); + return t; +} + +void mesh_triangle_remove(t_mesh *m, t_triangle *t) +{ + pdp_list_remove_pointer(m->triangles, t); + _triangle_free(t); +} + +/* calculate normals */ +void mesh_calculate_normals(t_mesh *m) +{ + t_pdp_atom* it; + t_pdp_atom* it_tri; + t_pdp_list *l = m->vertices; + t_pdp_list *l_tri = m->triangles; + t_vertex *v; + t_triangle *t; + //while (v = pdp_list_getnext_pointer(l, &it)) vertex_compute_normal_sphere(v); + switch(m->normal_type){ + default: + case MESH_NORMAL_SPHERE: PDP_POINTER_IN(l, it, v) vertex_compute_normal_sphere(v); break; + case MESH_NORMAL_PRISM: PDP_POINTER_IN(l, it, v) vertex_compute_normal_prism(v); break; + case MESH_NORMAL_RANDOM: PDP_POINTER_IN(l, it, v) vertex_compute_normal_random(v); break; + case MESH_NORMAL_AVERAGE: + PDP_POINTER_IN(l_tri, it_tri, t) triangle_compute_unit_normal(t); + PDP_POINTER_IN(l, it, v) vertex_compute_normal_average(v); + break; + } +} + +/* split a triangle in 4, using the intermedia median vertex storage */ +void mesh_split_four(t_mesh *m, t_triangle *old_t) +{ + int k; + t_vertex *v[6]; + + /* some intermediates */ + t_triangle *neighbour; + t_float newv[] = {0,0,0}; + t_float nullvect[] = {0,0,0}; + + + /* get main vertices */ + I3(k) v[k] = old_t->v[k]; + + /* get median vertices inserted by neighbouring triangles */ + I3(k) v[k+3] = old_t->m[k]; + +#define GET_MEDIAN(v, v0, v1) \ + if (!v){ \ + I3(k) newv[k] = 0.5f * (v0->c[k] + v1->c[k]); \ + v = mesh_vertex_add(m, newv, nullvect); \ + /*vertex_normalize(v);*/ \ + if (neighbour = triangle_neighbour(old_t, v0, v1)){ \ + triangle_add_median(neighbour, v0, v1, v); \ + } \ + } + + GET_MEDIAN(v[3], v[0], v[1]) + GET_MEDIAN(v[4], v[1], v[2]) + GET_MEDIAN(v[5], v[2], v[0]) + +#undef GET_MEDIAN + + /* remove the old triangle */ + mesh_triangle_remove(m, old_t); + + /* create 4 new triangles */ + mesh_triangle_add(m, v[0], v[3], v[5]); + mesh_triangle_add(m, v[1], v[4], v[3]); + mesh_triangle_add(m, v[2], v[5], v[4]); + mesh_triangle_add(m, v[3], v[4], v[5]); + +} + +/* split a triangle in 3 */ +void mesh_split_three(t_mesh *m, t_triangle *old_t) +{ + int k, l; + t_vertex *v[4]; + t_float newv[] = {0,0,0}; + t_float nullvect[] = {0,0,0}; + + /* get vertices */ + I3(k) v[k] = old_t->v[k]; + + /* remove a triangle */ + mesh_triangle_remove(m, old_t); + + /* compute new vertex coordinates */ + I3(k) I3(l) newv[k] += 0.33333f * v[l]->c[k]; + + /* create new vertex */ + v[3] = mesh_vertex_add(m, newv, nullvect); + //vertex_normalize(v[3]); + + /* create 3 new triangles */ + mesh_triangle_add(m, v[0], v[1], v[3]); + mesh_triangle_add(m, v[1], v[2], v[3]); + mesh_triangle_add(m, v[2], v[0], v[3]); + +} + + + +void mesh_split_all_four(t_mesh *m) +{ + t_triangle *t; + t_pdp_list *l = pdp_list_copy(m->triangles); + + //post("split_all_four: nb triangles %d", pdp_list_size(m->triangles)); + + while (l->elements){ + t = pdp_list_pop(l).w_pointer; + mesh_split_four(m, t); + } + mesh_calculate_normals(m); + pdp_list_free(l); +} + + +void mesh_split_all_three(t_mesh *m) +{ + t_triangle *t; + t_pdp_list *l = pdp_list_copy(m->triangles); + + //post("split_all_three: nb triangles %d", pdp_list_size(m->triangles)); + + while (l->elements){ + t = pdp_list_pop(l).w_pointer; + mesh_split_three(m, t); + } + mesh_calculate_normals(m); + pdp_list_free(l); +} + +void mesh_split_random_three(t_mesh *m) +{ + int size = pdp_list_size(m->triangles); + t_triangle *t = pdp_list_index(m->triangles, (random() % size)).w_pointer; + mesh_split_three(m, t); + mesh_calculate_normals(m); +} + + + +void mesh_free(t_mesh *m) +{ + t_pdp_list *l; + t_triangle *t; + t_vertex *v; + + /* delete all triangles */ + while (m->triangles->elements){ + t = pdp_list_pop(m->triangles).w_pointer; + //post("freeing triangle %x", t); + _triangle_free(t); + } + pdp_list_free(m->triangles); + m->triangles = 0; + + /* delete all vertices */ + while (m->vertices->elements){ + v = pdp_list_pop(m->vertices).w_pointer; + //post("freeing vertex %x", v); + _vertex_free(v); + } + pdp_list_free(m->vertices); + m->vertices = 0; + + pdp_dealloc(m); + +} + + +t_mesh *_mesh_new(void) +{ + t_mesh *m = (t_mesh *)pdp_alloc(sizeof(t_mesh)); + + /* create main vertex and triangle lists */ + m->triangles = pdp_list_new(0); + m->vertices = pdp_list_new(0); + + /* set normal type */ + m->normal_type = MESH_NORMAL_PRISM; + + return m; +} + +/* init tetra */ +t_mesh *mesh_new_tetra(void) +{ + int k; + t_triangle *t[4]; + t_vertex *v[4]; + t_pdp_atom* it; + t_triangle *tri; + t_mesh *m = _mesh_new(); + + float n[] = {0,0,0}; + float fv[4][3] = {{2,0,0},{0,2,0},{0,0,2}, {-1,-1,-1}}; + + /* add vertices */ + I4(k) v[k] = mesh_vertex_add(m, &fv[k][0], n); + I4(k) vertex_normalize(v[k]); + + /* add triangles */ + mesh_triangle_add(m, v[0], v[1], v[2]); + mesh_triangle_add(m, v[1], v[0], v[3]); + mesh_triangle_add(m, v[0], v[2], v[3]); + mesh_triangle_add(m, v[1], v[3], v[2]); + + + /* compute normals */ + mesh_calculate_normals(m); + + return m; +} + + +void _mesh_relax_compute_resultant_spring(t_mesh *m, float *center, float d0, float r0) +{ + int k; + t_pdp_atom *i, *j; + t_vertex *v, *w; + + PDP_POINTER_IN(m->vertices, i, v){ + float scale = 0.0f; + float r; + + /* compute contribution of origin link */ + I3(k) v->n[k] = v->c[k] - center[k]; + r = _vector3_normalize(v->n); + I3(k) v->n[k] *= (r0 - r); + + PDP_POINTER_IN(v->vertlist, j, w){ + int k; + float f[3]; + float d, l; + + /* compute force contribution of one link (model: spring with rest length == d0) */ + I3(k) f[k] = w->c[k] - v->c[k]; // PC: f == distance vector + d = _vector3_normalize(f); // PC: d == distance, vector == unit norm + I3(k) v->n[k] += (d - d0) * f[k]; // PC: n == n_prev + fource resultant + } + } +} + +void _mesh_relax_apply_force(t_mesh *m, float k) +{ + t_pdp_atom* it; + t_vertex *v; + + PDP_POINTER_IN(m->vertices, it, v){ + int i; + /* apply fource vector with step */ + I3(i) v->c[i] += k * v->n[i]; + } + +} + +void mesh_compute_center(t_mesh *m, float *c) +{ + t_pdp_atom*(it); + t_vertex *v; + float scale; + int k; + + I3(k) c[k] = 0; + PDP_POINTER_IN(m->vertices, it, v){ + I3(k) c[k] += v->c[k]; + } + scale = 1.0f / ((float)pdp_list_size(m->vertices)); + I3(k) c[k] *= scale; + +} + +void mesh_translate(t_mesh *m, float *c) +{ + t_pdp_atom *it; + t_vertex *v; + int k; + + PDP_POINTER_IN(m->vertices, it, v){ + I3(k) v->c[k] += c[k]; + } +} + +/* relax a mesh (move toward equal link length) */ +void mesh_relax(t_mesh *m, float step, float d0, float r0) +{ + int k; + float c[3]; + mesh_compute_center(m, c); + I3(k) c[k] = -c[k]; + mesh_translate(m, c); + I3(k) c[k] = 0; + _mesh_relax_compute_resultant_spring(m, c, d0, r0); /* compute force resultant */ + _mesh_relax_apply_force(m, step); /* apply "time step towards desired distance" */ + mesh_calculate_normals(m); /* restore normals */ +} + + + +/* print some debug information */ +void mesh_debug(t_mesh *m) +{ + int k; + int boundary_edges = 0; + t_pdp_atom* it; + t_triangle *t; + post("mesh info"); + post("\tnumber of vertices = %d", pdp_list_size(m->vertices)); + post("\tnumber of triangles = %d", pdp_list_size(m->triangles)); + + PDP_POINTER_IN(m->triangles, it, t){ + I3(k) if (!triangle_neighbour(t, t->v[k], t->v[(k+1)%3])) boundary_edges++; + } + post("\tnumber of boundaray edges = %d", boundary_edges); + + +} diff --git a/opengl/system/pdp_opengl.c b/opengl/system/pdp_opengl.c new file mode 100644 index 0000000..541af75 --- /dev/null +++ b/opengl/system/pdp_opengl.c @@ -0,0 +1,76 @@ + +/* + * OpenGL Extension Module for pdp - opengl system stuff + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +#include "pdp.h" +#include "pdp_control.h" + +#define PDP_3DP_QUEUE_LOGSIZE 16 +#define PDP_3DP_QUEUE_DELTIME 1.0f + + + +void pdp_3Dcontext_prepare_for_thread_switch(void *); +static t_pdp_procqueue _3dp_queue; + + +static void pdp_control_thread(void *x, t_symbol *s, int argc, t_atom *argv) +{ + int t = 0; + float f; + if (argc != 1) return; + if (argv[0].a_type != A_FLOAT) return; + f = argv[0].a_w.w_float; + t = (f != 0.0f); + post("3dp thread switched %s", t ? "on":"off"); + + + /* when we switch threads, the glx system needs to be notified + because it has to release the render context. this is done + in a process method, so it is run in the correct thread. */ + + + pdp_procqueue_add(&_3dp_queue, 0, pdp_3Dcontext_prepare_for_thread_switch, 0, 0); + pdp_procqueue_wait(&_3dp_queue); + + + /* fresh start: enable/disable the thread dispatching */ + pdp_procqueue_use_thread(&_3dp_queue, t); + +} + +/* kernel setup */ +void pdp_opengl_system_setup(void) +{ + /* init the 3dp queue */ + pdp_procqueue_init(&_3dp_queue, PDP_3DP_QUEUE_DELTIME, PDP_3DP_QUEUE_LOGSIZE); + + /* scheduler uses the thread */ + pdp_procqueue_use_thread(&_3dp_queue, 1); + //pdp_procqueue_use_thread(&_3dp_queue, 0); //DEBUG: disable 3dp thread + + /* add pdp_control method for thread */ + pdp_control_addmethod((t_method)pdp_control_thread, gensym("3dthread")); +} + +t_pdp_procqueue* pdp_opengl_get_queue(void){return (&_3dp_queue);} + + + diff --git a/opengl/system/pdp_texture.c b/opengl/system/pdp_texture.c new file mode 100644 index 0000000..8bc7b21 --- /dev/null +++ b/opengl/system/pdp_texture.c @@ -0,0 +1,541 @@ +/* + * OpenGL Extension Module for pdp - texture packet implementation + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 modules implemtents the opengl texture packet + it contains only portable opengl code */ + +#include <stdio.h> +#include <GL/gl.h> +#include <GL/glu.h> +#include "pdp_opengl.h" +#include "pdp_texture.h" +#include "pdp_dpd_command.h" + + +static t_pdp_class *texture_class; + +static t_pdp_dpd_commandfactory _tex_cf; + +typedef struct _texture_command +{ + t_pdp_dpd_command base; + int p_src; + int p_dst; +} t_texture_command; + + +/* all symbols are C-style */ +#ifdef __cplusplus +extern "C" +{ +#endif + + + +/* returns a pointer to the packet subheader given the pdp header */ +static t_texture *_pdp_tex_info(t_pdp *x) +{ + return (t_texture *)&(x->info.raw); +} + + +/* create a pow of 2 texture dimension, ge than 8 */ +static int _round_to_pow_2(int n){ + int r = 8; + while (n > r) r <<= 1; + return r; +} + +t_pdp_symbol *_pdp_get_tex_description_from_params(GLsizei width, GLsizei height, GLint format) +{ + char description[1024]; + char *c = description; + + c += sprintf(c, "texture"); + switch(format){ + case GL_LUMINANCE: c += sprintf(c, "/grey"); break; + case GL_RGB: c += sprintf(c, "/rgb"); break; + case GL_RGBA: c += sprintf(c, "/rgba"); break; + default: + c += sprintf(c, "/unknown"); goto exit; + } + c += sprintf(c, "/%dx%d", width, height); + + exit: + return pdp_gensym(description); +} + +t_pdp_symbol *_pdp_tex_get_description(t_pdp *header) +{ + t_texture *texture = _pdp_tex_info(header); + int encoding; + + if (!header) return pdp_gensym("invalid"); + else if (!header->desc){ + if (header->type == PDP_TEXTURE){ + /* if description is not defined, try to construct it */ + return _pdp_get_tex_description_from_params(texture->width, texture->height, texture->format); + } + else return pdp_gensym("unknown"); + } + else return header->desc; +} + + +static int _pdp_packet_texture_old_or_dummy(u32 width, u32 height, s32 format); +static void _pdp_packet_gentexture(int packet); + +static void texture_command_convert_bitmap_to_texture(t_texture_command *c) +{ + t_texture *t = (t_texture *)pdp_packet_subheader(c->p_dst); + + /* make sure packet contains a texture, since it is created with _pdp_packet_reuse_texture */ + _pdp_packet_gentexture(c->p_dst); + + /* flip source image before uploading */ + pdp_packet_bitmap_flip_top_bottom(c->p_src); + + /* fill texture */ + pdp_packet_texture_make_current(c->p_dst); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, t->sub_width, t->sub_height, + t->format, GL_UNSIGNED_BYTE, (char *)pdp_packet_data(c->p_src)); + + /* decrease refcount */ + pdp_packet_mark_unused(c->p_src); + pdp_packet_mark_unused(c->p_dst); + + //post("conversion done"); + pdp_dpd_command_suicide(c); +} + + +/* converters to standard pdp types */ +int _pdp_packet_texture_convert_image_to_texture(int packet, t_pdp_symbol *dest_template) +{ + int p_temp, p; + + //post ("converting to bitmap"); + p_temp = pdp_packet_convert_rw(packet, pdp_gensym("bitmap/*/*")); + if (p_temp == -1) return -1; + + //post ("converting to texture"); + p = pdp_packet_convert_rw(p_temp, pdp_gensym("texture/*/*")); + pdp_packet_mark_unused(p_temp); + return p; +} + + + +/* converters to standard pdp types */ +int _pdp_packet_texture_convert_bitmap_to_texture(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + void *data = pdp_packet_data (packet); + int new_p; + u32 w; + u32 h; + t_texture_command *c; + + if (!pdp_packet_bitmap_isvalid(packet)) return -1; + + w = header->info.image.width; + h = header->info.image.height; + + switch (header->info.image.encoding){ + case PDP_BITMAP_GREY: + /* create greyscale texture */ + new_p = _pdp_packet_texture_old_or_dummy(w,h, GL_LUMINANCE); + break; + case PDP_BITMAP_RGB: + /* create rgb texture */ + new_p = _pdp_packet_texture_old_or_dummy(w,h, GL_RGB); + break; + case PDP_BITMAP_RGBA: + /* create greyscale texture */ + new_p = _pdp_packet_texture_old_or_dummy(w,h, GL_RGBA); + break; + default: + new_p = -1; + break; + } + + if (new_p != -1){ + + /* remark: this is a hack. a texture has to be created + when a rendering context is active. this means it has + to be created in the correct thread. therefore a dpd + command is added to the 3dp queue. this seems to work, + but without a dropping mechanism, this can overload the + queue. the real solution would be to add a converter + object to a 3dp chain, or to accept image or bitmap + packets in 3dp objects */ + + + /* dispatch command */ + c = (t_texture_command *)pdp_dpd_commandfactory_get_new_command(&_tex_cf); + c->p_src = pdp_packet_copy_rw(packet); + c->p_dst = pdp_packet_copy_ro(new_p); + pdp_procqueue_add(pdp_opengl_get_queue(), c, texture_command_convert_bitmap_to_texture, 0, 0); + } + return new_p; + +} + + + +int _pdp_packet_texture_convert_texture_to_bitmap(int packet, t_pdp_symbol *dest_template0) +{ + post("_pdp_packet_texture_convert_texture_to_bitmap not implemented."); + return -1; +} + + +t_texture *pdp_packet_texture_info(int packet) +{ + t_pdp *header = pdp_packet_header(packet); + if (pdp_packet_texture_isvalid(packet)) return _pdp_tex_info(header); + else return 0; +} + +/* check if valid texture packet. all other methods assume packet is valid */ +int pdp_packet_texture_isvalid(int packet) +{ + t_pdp *header; + if (!(header = pdp_packet_header(packet))) return 0; + if (PDP_TEXTURE != header->type) return 0; + return glIsTexture(_pdp_tex_info(header)->tex_obj); +} + + + +static void _tex_init_obj(t_texture *t) +{ + //u8 *dummydata; + //int i; + + glBindTexture(GL_TEXTURE_2D, t->tex_obj); + glTexImage2D(GL_TEXTURE_2D, 0, t->format, t->width, t->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + + /* debug + dummydata = (u8 *)malloc(t->width*t->height*4); + for (i=0; i<t->width*t->height*4; i++){dummydata[i] = random(); } + glTexImage2D(GL_TEXTURE_2D, 0, t->format, t->width, t->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, dummydata); + free(dummydata); + */ + +} + + +static void _pdp_tex_copy(t_pdp *dst, t_pdp *src); +static void _pdp_tex_clone(t_pdp *dst, t_pdp *src); +static void _pdp_tex_reinit(t_pdp *dst); +static void _pdp_tex_cleanup(t_pdp *dst); + +static void _pdp_tex_init_methods(t_pdp *h) +{ + h->theclass = texture_class; +} + +static void _pdp_tex_reinit(t_pdp *dst) +{ + /* this does nothing. texture is assumed to be in a valid state */ +} +static void _pdp_tex_clone(t_pdp *dst, t_pdp *src) +{ + t_texture *dst_t = _pdp_tex_info(dst); + t_texture *src_t = _pdp_tex_info(src); + + //post("WARNING: _pdp_tex_clone: should not be called from outside 3d thread"); + + /* determine if destination texture is valid */ + if (glIsTexture(dst_t->tex_obj)){ + /* check format */ + if ((dst_t->width >= src_t->width) + && (dst_t->height >= src_t->height) + && (dst_t->format == src_t->format)){ + dst_t->sub_width = src_t->sub_width; + dst_t->sub_height = src_t->sub_height; + return; + } + } + /* not initialized, so we need to create a new one */ + else { + glGenTextures(1, (GLuint*)&dst_t->tex_obj); + } + + /* setup header */ + dst_t->width = src_t->width; + dst_t->height = src_t->height; + dst_t->format = src_t->format; + dst_t->sub_width = src_t->sub_width; + dst_t->sub_height = src_t->sub_height; + + /* setup packet methods */ + _pdp_tex_init_methods(dst); + + /* init description */ + dst->desc = _pdp_tex_get_description(dst); + +} +static void _pdp_tex_copy(t_pdp *dst, t_pdp *src) +{ + /* texture copying is inefficient. for the tex extensions there is no analogy + for "efficient in-place processing" + this means the pdp_packet_register_rw() call should be avoided + this inconsistency should be tucked away in a texture base class */ + + /* todo: use texture combining extensions for this */ + + post("WARNING: fanout is not yet implemented correctly for texture packets"); + + /* not implemented yet, just a call to the clone method */ + _pdp_tex_clone(dst, src); +} + +static void _pdp_tex_cleanup(t_pdp *dst) +{ + t_texture *t = _pdp_tex_info(dst); + glDeleteTextures(1, (GLuint*)&t->tex_obj); + t->tex_obj = -1; /* is this value guaranteed to be invalid? */ +} + + +/* texture constructors */ + +/* reuse a texture, or create a "dummy" == packet with everything except a valid texture object */ +static int _pdp_packet_texture_old_or_dummy(u32 width, u32 height, s32 format) +{ + int p = -1; + t_pdp *h; + t_texture *t; + + int p2_w = _round_to_pow_2(width); + int p2_h = _round_to_pow_2(height); + + + /* try to reuse a texture packet or get a new one */ + p = pdp_packet_reuse(_pdp_get_tex_description_from_params(p2_w, p2_h, format)); + if (-1 == p) p = pdp_packet_create(PDP_TEXTURE, 0); + if (-1 == p) return -1; + + h = pdp_packet_header(p); + t = _pdp_tex_info(h); + + /* check if alloc succeded */ + if (!h) return -1; + + /* check if tex is already initialized */ + if (pdp_packet_texture_isvalid(p)){ + /* check format */ + if ((t->width >= width) && (t->height >= height) && (t->format == format)){ + //post("pdp_packet_new_tex: reused"); + t->sub_width = width; + t->sub_height = height; + return p; + } + post("ERROR: pdp_packet_new_texture: pdp_packet_reuse returned wrong type"); + } + + /* determine the texture dims * setup rest of data struct */ + t->width = 64; + t->height = 64; + while (t->width < width) t->width <<= 1; + while (t->height < height) t->height <<= 1; + + t->format = format; + t->sub_width = width; + t->sub_height = height; + + _pdp_tex_init_methods(h); + + + /* init the texture */ + //_tex_init_obj(t); + + /* init description */ + h->desc = _pdp_tex_get_description(h); + + + return p; +} + +/* don't call this method on a non-texture object! */ +static void _pdp_packet_gentexture(int p) +{ + t_texture *t; + if (!pdp_packet_texture_isvalid(p)){ + /* not initialized, so we need to create a new one */ + // post("generating texture"); + t = (t_texture *)pdp_packet_subheader(p); + + /* create the texture object */ + glGenTextures(1, (GLuint *)&t->tex_obj); + + /* init the texture */ + _tex_init_obj(t); + + } +} + +int pdp_packet_new_texture(u32 width, u32 height, s32 format) +{ + t_texture *t; + int p = _pdp_packet_texture_old_or_dummy(width, height, format); + + //post("WARNING: pdp_packet_new_texture: this method should not be called outside the 3dp thread"); + + if (p == -1) return -1; + _pdp_packet_gentexture(p); + return p; +} + + +/* high level texture packet operators */ + +/* make a texture the current texture context */ +void pdp_packet_texture_make_current(int packet) +{ + t_texture *t = pdp_packet_texture_info(packet); + if (!t) return; + glBindTexture(GL_TEXTURE_2D, t->tex_obj); +} + +void pdp_packet_texture_make_current_enable(int packet) +{ + glEnable(GL_TEXTURE_2D); + pdp_packet_texture_make_current(packet); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); +} + +float pdp_packet_texture_fracx(int packet) +{ + t_texture *t = pdp_packet_texture_info(packet); + if (!t) return 0.0; + return (float)t->sub_width/t->width; +} + +float pdp_packet_texture_fracy(int packet) +{ + t_texture *t = pdp_packet_texture_info(packet); + if (!t) return 0.0; + return (float)t->sub_height/t->height; +} + +u32 pdp_packet_texture_total_width(int packet) +{ + t_texture *t = pdp_packet_texture_info(packet); + if (!t) return 0; + return t->width; + +} +u32 pdp_packet_texture_total_height(int packet) +{ + t_texture *t = pdp_packet_texture_info(packet); + if (!t) return 0; + return t->height; + +} + +u32 pdp_packet_texture_sub_width(int packet) +{ + t_texture *t = pdp_packet_texture_info(packet); + if (!t) return 0; + return t->sub_width; + +} +u32 pdp_packet_texture_sub_height(int packet) +{ + t_texture *t = pdp_packet_texture_info(packet); + if (!t) return 0; + return t->sub_height; +} + +float pdp_packet_texture_sub_aspect(int packet) +{ + t_texture *t = pdp_packet_texture_info(packet); + if (!t) return 0; + return (float)t->sub_width/t->sub_height; +} + +/* setup for 2d operation from texture dimensions */ +void pdp_packet_texture_setup_2d_context(int p) +{ + u32 w; + u32 h; + float asp; + if (!pdp_packet_texture_isvalid(p)) return; + w = pdp_packet_texture_sub_width(p); + h = pdp_packet_texture_sub_height(p); + asp = pdp_packet_texture_sub_aspect(p); + + /* set the viewport to the size of the sub texture */ + glViewport(0, 0, w, h); + + /* set orthogonal projection, with a relative frame size of (2asp x 2) */ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluOrtho2D(0.0, 2*asp, 0, 2); + + /* set the center of view */ + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(asp, 1, 0); + glScalef(1,-1,1); +} + +void pdp_texture_setup(void) +{ + t_pdp_conversion_program *program; + + /* setup packet class */ + texture_class = pdp_class_new(pdp_gensym("texture/*/*"), 0); + texture_class->cleanup = _pdp_tex_cleanup; + texture_class->wakeup = _pdp_tex_reinit; + //texture_class->clone = _pdp_tex_clone; + texture_class->copy = _pdp_tex_copy; + + /* init command list */ + pdp_dpd_commandfactory_init(&_tex_cf, sizeof(t_texture_command)); + + + + /* setup programs */ + program = pdp_conversion_program_new(_pdp_packet_texture_convert_bitmap_to_texture, 0); + pdp_type_register_conversion(pdp_gensym("bitmap/*/*"), pdp_gensym("texture/*/*"), program); + + /* this is a hack to use until the type conversion system has a proper search algo */ + program = pdp_conversion_program_new(_pdp_packet_texture_convert_image_to_texture, 0); + pdp_type_register_conversion(pdp_gensym("image/*/*"), pdp_gensym("texture/*/*"), program); + + + program = pdp_conversion_program_new(_pdp_packet_texture_convert_texture_to_bitmap, 0); + pdp_type_register_conversion(pdp_gensym("texture/*/*"), pdp_gensym("bitmap/*/*"), program); + +} + +/* all symbols are C-style */ +#ifdef __cplusplus +} +#endif diff --git a/opengl/system/setup.c b/opengl/system/setup.c new file mode 100644 index 0000000..18d267a --- /dev/null +++ b/opengl/system/setup.c @@ -0,0 +1,83 @@ +#include "pdp_opengl.h" + +/* 3dp overview: + + - texture packets (gl) + - drawable packets (glX windows and pbufs) + + the 3dp system connects to a display server and creates a common context + this can be a pbuf context (if supported, glx >= 1.3) or a normal glX context + textures are standard opengl + drawable packets are wrappers around glx drawables (windows or pbufs) + they share the central display connection and rendering context + +*/ + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* opengl lib kernel setup */ +void pdp_opengl_system_setup(void); + +/* packet type setup */ +void pdp_3Dcontext_glx_setup(void); /* glx specific part of the 3D context packet */ +void pdp_3Dcontext_common_setup(void); /* common part of the 3D context packet */ +void pdp_texture_setup(void); /* texture packet */ + + +/* module setup */ +void pdp_3d_windowcontext_setup(void); +void pdp_3d_draw_setup(void); +void pdp_3d_view_setup(void); +void pdp_3d_light_setup(void); +void pdp_3d_color_setup(void); +void pdp_3d_push_setup(void); +void pdp_3d_snap_setup(void); +void pdp_3d_dlist_setup(void); +void pdp_3d_drawmesh_setup(void); +void pdp_3d_for_setup(void); +void pdp_3d_state_setup(void); +void pdp_3d_subcontext_setup(void); + + + //#define D(x) { pdp_post_n( #x ".." ); x; pdp_post("done"); } +#define D(x) x + +void pdp_opengl_setup(void) +{ + int i; + post("PDP: pdp_opengl extension library"); + + /* setup system */ + D(pdp_opengl_system_setup()); + + /* setup packet types */ + D(pdp_3Dcontext_glx_setup()); + D(pdp_3Dcontext_common_setup()); + D(pdp_texture_setup()); + + + /* setup modules */ + D(pdp_3d_windowcontext_setup()); + D(pdp_3d_draw_setup()); + D(pdp_3d_view_setup()); + D(pdp_3d_push_setup()); + D(pdp_3d_light_setup()); + D(pdp_3d_dlist_setup()); + D(pdp_3d_color_setup()); + D(pdp_3d_snap_setup()); + D(pdp_3d_drawmesh_setup()); + D(pdp_3d_for_setup()); + D(pdp_3d_state_setup()); + D(pdp_3d_subcontext_setup()); + + +} + + +#ifdef __cplusplus +} +#endif diff --git a/opengl/test/arm.pd b/opengl/test/arm.pd new file mode 100644 index 0000000..4da4ce1 --- /dev/null +++ b/opengl/test/arm.pd @@ -0,0 +1,39 @@ +#N canvas 475 534 450 300 10; +#X obj 51 14 inlet; +#X obj 52 252 outlet; +#X obj 76 133 3dp_push; +#X obj 176 117 3dp_view transx 0.5; +#X obj 71 81 3dp_view rotz; +#X obj 211 52 inlet; +#X obj 177 91 3dp_view scalex \$1; +#X obj 51 194 3dp_view transx \$1; +#X obj 360 105 r texture; +#X obj 40 62 3dp_view roty; +#X obj 159 22 r roty; +#X obj 301 50 r scale; +#X obj 43 37 3dp_draw cube 1; +#X obj 123 5 r cubesize; +#X obj 257 219 3dp_draw torus 0.25 0.5 6; +#X obj 231 176 spigot; +#X obj 264 148 r drawtorus; +#X obj 322 191 r torusr1; +#X obj 355 160 r torusr2; +#X connect 0 0 12 0; +#X connect 2 0 7 0; +#X connect 2 1 6 0; +#X connect 3 0 15 0; +#X connect 4 0 2 0; +#X connect 5 0 4 1; +#X connect 6 0 3 0; +#X connect 7 0 1 0; +#X connect 8 0 14 1; +#X connect 9 0 4 0; +#X connect 10 0 9 1; +#X connect 11 0 6 1; +#X connect 11 0 7 1; +#X connect 12 0 9 0; +#X connect 13 0 12 2; +#X connect 15 0 14 0; +#X connect 16 0 15 1; +#X connect 17 0 14 2; +#X connect 18 0 14 3; diff --git a/opengl/test/meshtest.pd b/opengl/test/meshtest.pd new file mode 100644 index 0000000..4b8d342 --- /dev/null +++ b/opengl/test/meshtest.pd @@ -0,0 +1,200 @@ +#N canvas 561 0 657 860 10; +#X obj 101 61 3dp_windowcontext; +#X obj 101 27 metro 20; +#X obj 101 122 3dp_push; +#X obj 102 11 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 56 40 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 253 32 cursor \$1; +#X obj 253 12 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X obj 90 222 3dp_mouserotate; +#X text 14 250 use the mouse to rotate the model (but not the light +source since it is rendered before the rotation is applied.); +#X obj 67 516 3dp_drawmesh; +#X obj 261 163 3dp_view transxyz 0 0 4; +#X floatatom 412 128 5 0 0 0 - - -; +#X floatatom 193 392 5 0 0 0 - - -; +#X obj 312 293 spigot; +#X obj 362 263 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X obj 119 341 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 179 494 3dp_dlist; +#X msg 188 467 compile; +#X obj 110 466 pdp_route; +#X obj 202 442 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 266 363 reset; +#X obj 180 292 t b b b b b; +#X msg 310 504 normal sphere; +#X msg 309 458 normal prism; +#X msg 310 481 normal random; +#X obj 276 307 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 276 328 t b b b; +#X obj 334 369 f; +#X floatatom 382 317 5 0 0 0 - - -; +#X floatatom 433 318 5 0 0 0 - - -; +#X obj 81 297 pdp_t p b; +#X obj 308 607 t b b; +#X obj 390 612 t b b; +#X obj 251 581 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 428 575 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X floatatom 483 316 5 0 0 0 - - -; +#X msg 451 288 5; +#X msg 478 287 0; +#X msg 507 290 5; +#X obj 317 399 pack 0 0 0; +#X msg 383 293 0.01; +#X obj 68 420 3dp_view scale 0.5; +#X obj 426 348 abs; +#X obj 470 337 abs; +#X msg 67 569 wireframe \$1; +#X obj 84 545 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X obj 10 322 spigot; +#X obj 60 292 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X msg 518 152 collectgarbage; +#X obj 516 179 pdp_control; +#X msg 317 537 info; +#X msg 226 332 split4; +#X msg 177 334 split3; +#X msg 10 364 split3random; +#X msg 317 421 springrelax \$1 \$2 \$3; +#X obj 471 243 t b b b b; +#X obj 486 219 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 273 199 3dp_light; +#X floatatom 58 147 5 0 0 0 - - -; +#X floatatom 103 146 5 0 0 0 - - -; +#X floatatom 147 145 5 0 0 0 - - -; +#X floatatom 191 143 5 0 0 0 - - -; +#X msg 431 485 normal average; +#X obj 85 590 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X msg 68 614 flatshading \$1; +#X obj 89 196 3dp_view roty; +#X obj 387 54 f; +#X obj 388 82 +; +#X obj 98 78 pdp_t p b; +#X floatatom 431 57 5 0 0 0 - - -; +#X floatatom 181 9 5 0 0 0 - - -; +#X obj 45 785 3dp_snap; +#X floatatom 152 692 5 0 0 0 - - -; +#X obj 221 736 print; +#X obj 21 176 3dp_color 0.74 0.73 0.62 1; +#X obj 32 726 3dp_draw sphere 9; +#X obj 533 88 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X msg 524 111 3dthread \$1; +#X obj 256 672 pdp_v4l; +#X obj 258 644 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 369 682 pdp_convert texture/*/*; +#X obj 365 712 pdp_description; +#X symbolatom 376 746 10 0 0 0 - - -; +#X obj 191 654 metro 40; +#X obj 191 631 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 314 760 pdp_xv; +#X connect 0 0 68 0; +#X connect 0 1 7 1; +#X connect 1 0 0 0; +#X connect 1 0 66 0; +#X connect 2 0 74 0; +#X connect 2 1 10 0; +#X connect 3 0 1 0; +#X connect 4 0 0 0; +#X connect 5 0 0 0; +#X connect 6 0 5 0; +#X connect 7 0 30 0; +#X connect 9 0 75 0; +#X connect 10 0 57 0; +#X connect 11 0 10 3; +#X connect 12 0 41 1; +#X connect 13 0 27 0; +#X connect 14 0 13 1; +#X connect 15 0 9 0; +#X connect 16 0 9 0; +#X connect 17 0 16 0; +#X connect 18 0 9 0; +#X connect 18 1 16 0; +#X connect 19 0 18 1; +#X connect 20 0 9 0; +#X connect 21 0 52 0; +#X connect 21 1 52 0; +#X connect 21 2 51 0; +#X connect 21 4 51 0; +#X connect 22 0 9 0; +#X connect 23 0 9 0; +#X connect 24 0 9 0; +#X connect 25 0 26 0; +#X connect 26 0 62 0; +#X connect 26 1 21 0; +#X connect 26 2 20 0; +#X connect 27 0 39 0; +#X connect 28 0 27 1; +#X connect 29 0 39 1; +#X connect 30 0 41 0; +#X connect 30 1 13 0; +#X connect 30 1 46 0; +#X connect 31 0 52 0; +#X connect 31 1 50 0; +#X connect 32 0 51 0; +#X connect 32 1 50 0; +#X connect 33 0 31 0; +#X connect 34 0 32 0; +#X connect 35 0 43 0; +#X connect 36 0 29 0; +#X connect 37 0 29 0; +#X connect 38 0 35 0; +#X connect 39 0 54 0; +#X connect 40 0 28 0; +#X connect 41 0 18 0; +#X connect 42 0 39 1; +#X connect 43 0 39 2; +#X connect 44 0 9 0; +#X connect 45 0 44 0; +#X connect 46 0 53 0; +#X connect 47 0 46 1; +#X connect 48 0 49 0; +#X connect 50 0 9 0; +#X connect 51 0 9 0; +#X connect 52 0 9 0; +#X connect 53 0 9 0; +#X connect 54 0 9 0; +#X connect 55 0 14 0; +#X connect 55 1 40 0; +#X connect 55 2 37 0; +#X connect 55 3 38 0; +#X connect 56 0 55 0; +#X connect 58 0 74 1; +#X connect 59 0 74 2; +#X connect 60 0 74 3; +#X connect 61 0 74 4; +#X connect 62 0 9 0; +#X connect 63 0 64 0; +#X connect 64 0 9 0; +#X connect 65 0 7 0; +#X connect 66 0 67 0; +#X connect 67 0 66 1; +#X connect 67 0 65 1; +#X connect 68 0 2 0; +#X connect 69 0 67 1; +#X connect 70 0 1 1; +#X connect 72 0 75 2; +#X connect 74 1 65 0; +#X connect 76 0 77 0; +#X connect 77 0 49 0; +#X connect 78 0 80 0; +#X connect 79 0 78 0; +#X connect 80 0 81 0; +#X connect 80 0 75 1; +#X connect 81 0 82 0; +#X connect 83 0 78 0; +#X connect 84 0 83 0; diff --git a/opengl/test/pdp_ogl_draw_limb.pd b/opengl/test/pdp_ogl_draw_limb.pd new file mode 100644 index 0000000..7b76c74 --- /dev/null +++ b/opengl/test/pdp_ogl_draw_limb.pd @@ -0,0 +1,361 @@ +#N canvas 408 287 799 654 10; +#X floatatom 170 39 5 0 0; +#X obj 82 46 metro 40; +#X obj 82 19 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 125 17 10; +#X msg 99 4 stop; +#X floatatom 284 336 5 0 0; +#X obj 83 128 3dp_push; +#X floatatom 502 132 5 0 0; +#X obj 413 193 3dp_view transx 3; +#X obj 404 251 3dp_light; +#X obj 317 23 f; +#X floatatom 356 24 5 0 0; +#X floatatom 155 114 5 0 0; +#X floatatom 575 415 5 0 0; +#X floatatom 405 344 5 0 0; +#X obj 130 456 arm 3; +#X obj 128 482 arm 3; +#X obj 128 516 arm 3; +#X obj 137 430 arm 3; +#X floatatom 288 376 5 0 0; +#X floatatom 286 414 5 0 0; +#X floatatom 290 454 5 0 0; +#X floatatom 285 509 5 0 0; +#X obj 139 608 arm 3; +#X obj 138 641 arm 3; +#X obj 132 671 arm 3; +#X obj 139 583 arm 3; +#X floatatom 289 549 5 0 0; +#X floatatom 287 587 5 0 0; +#X floatatom 291 627 5 0 0; +#X obj 78 226 3dp_view roty; +#X obj 248 358 * 1; +#X obj 251 610 * -1; +#X obj 507 567 s texture; +#X obj 790 506 pdp_v4l; +#X obj 790 478 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 785 434 metro 10; +#X obj 782 408 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 812 403 stop; +#X obj 139 707 arm 3; +#X floatatom 307 661 5 0 0; +#X obj 256 684 * -1.5; +#X obj 474 719 s roty; +#X floatatom 436 644 5 0 0; +#X floatatom 570 687 5 0 0; +#X obj 572 718 s scale; +#X floatatom 180 212 5 0 0; +#X floatatom 285 108 5 0 0; +#X floatatom 347 299 5 0 0; +#X obj 252 398 * -1.01; +#X obj 250 436 * 0.99; +#X obj 254 476 * -1.01; +#X obj 249 531 * 2.1; +#X obj 253 571 * -1.7; +#X obj 133 399 3dp_draw cube 1.4; +#X obj 129 886 3dp_draw cube 1.4; +#X obj 445 68 t b b; +#X msg 615 633 4; +#X msg 503 640 14; +#X obj 323 57 + 3; +#X obj 70 174 3dp_view transz -3; +#X obj 411 164 3dp_view roty 54; +#X obj 398 378 s cubesize; +#X msg 351 255 3.15; +#X obj 68 248 3dp_view scale 0.4; +#X msg 173 15 20; +#X obj 255 649 * 0.11; +#X floatatom 544 163 5 0 0; +#X msg 421 3 0; +#X obj 269 283 * 1; +#X obj 85 203 3dp_view rotx; +#X floatatom 163 172 5 0 0; +#X floatatom 309 690 5 0 0; +#X obj 128 769 arm 3; +#X obj 127 802 arm 3; +#X obj 121 832 arm 3; +#X obj 128 733 arm 3; +#X floatatom 313 730 5 0 0; +#X floatatom 311 768 5 0 0; +#X floatatom 315 808 5 0 0; +#X obj 275 791 * -1; +#X obj 128 868 arm 3; +#X floatatom 331 842 5 0 0; +#X obj 280 865 * -1.5; +#X obj 273 712 * 2.1; +#X obj 277 752 * -1.7; +#X obj 279 830 * 0.11; +#X obj 8 344 3dp_push; +#X obj 148 311 3dp_view transz; +#X floatatom 212 262 5 0 0; +#X obj 44 365 3dp_view transz; +#X obj 88 326 * -1; +#X msg 267 165 2; +#X obj 222 118 * 0.05; +#X obj 518 805 s drawtorus; +#X obj 518 778 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X obj 515 853 s torusr1; +#X floatatom 513 830 5 0 0; +#X floatatom 611 831 5 0 0; +#X obj 613 854 s torusr2; +#X msg 569 761 1; +#X obj 418 678 *; +#X obj 422 292 metro 100; +#X obj 418 266 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 167 366 3dp_dlist; +#X msg 174 335 compile; +#X floatatom 27 142 5 0 0; +#X obj 82 150 3dp_push; +#X obj 449 801 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 400 772 metro 40; +#X obj 375 780 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj -20 368 3dp_push; +#X obj -23 453 3dp_view rotx; +#X floatatom 64 432 5 0 0; +#X msg -4 56 dim 640 480; +#X obj -15 533 3dp_draw sphere 30 40; +#X msg 635 291 dim 512 512; +#X obj 445 424 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 637 360 pdp_t p p; +#X msg 434 617; +#X msg 478 613 0.001; +#X obj -11 573 3dp_snap; +#X obj 701 192 pdp_control; +#X msg 731 157 thread 1; +#X msg 731 126 thread 0; +#X obj 438 580 / 1000; +#X floatatom 432 545 5 0 0; +#X obj 156 89 3dp_view roty; +#X floatatom 264 67 5 0 0; +#X obj 591 104 print een; +#X obj 595 129 print twee; +#X obj 380 866 pdp_tex; +#X obj 389 836 pdp_noise; +#X msg 376 806 dim 64 64; +#X obj 376 748 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 476 880 dim 32 32; +#X obj 341 894 print tex; +#X obj 452 858 print noise; +#X obj 505 16 loadbang; +#X obj 460 13 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 440 821 pdp_v4l; +#X obj 38 25 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 597 243 osc~ 400; +#X obj 582 275 dac~; +#X msg 601 50 \; pd dsp 1; +#X obj 137 68 3dp_windowcontext; +#X msg 575 188 stop; +#X obj 569 211 metro 1000; +#X floatatom 620 181 5 0 0; +#X obj 551 188 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj -13 98 3dp_windowcontext; +#X obj 82 66 t b b; +#X floatatom 361 84 5 0 0; +#X obj 14 281 3dp_push; +#X obj 96 273 pdp_t p b; +#X obj 9 307 pdp_t p b; +#X obj 428 43 t b b; +#X msg 510 42 open; +#X msg 304 213 400; +#X msg 241 209 -400; +#X obj 274 254 +; +#X obj 748 595 pdp_xv; +#X obj 750 544 pdp_abs; +#X obj 504 465 print; +#X obj 504 441 route done; +#X obj -17 170 3dp_color; +#X obj 8 696 pdp_description; +#X symbolatom -14 773 40 0 0; +#X msg 695 82 collectgarbage; +#X obj -9 738 symbol; +#X obj -11 717 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 14 628 pdp_del 50; +#X connect 0 0 1 1; +#X connect 1 0 10 0; +#X connect 1 0 151 0; +#X connect 2 0 1 0; +#X connect 3 0 1 1; +#X connect 4 0 1 0; +#X connect 5 0 31 1; +#X connect 6 0 107 0; +#X connect 6 1 61 0; +#X connect 7 0 61 1; +#X connect 8 0 9 0; +#X connect 10 0 59 0; +#X connect 11 0 59 1; +#X connect 12 0 60 1; +#X connect 14 0 62 0; +#X connect 15 0 16 0; +#X connect 16 0 17 0; +#X connect 17 0 26 0; +#X connect 18 0 15 0; +#X connect 19 0 49 1; +#X connect 20 0 50 1; +#X connect 21 0 51 1; +#X connect 22 0 52 1; +#X connect 23 0 24 0; +#X connect 24 0 25 0; +#X connect 25 0 39 0; +#X connect 26 0 23 0; +#X connect 27 0 53 1; +#X connect 28 0 32 1; +#X connect 29 0 66 1; +#X connect 30 0 64 0; +#X connect 31 0 49 0; +#X connect 31 0 18 1; +#X connect 32 0 66 0; +#X connect 32 0 24 1; +#X connect 34 0 162 0; +#X connect 35 0 34 0; +#X connect 36 0 35 0; +#X connect 37 0 36 0; +#X connect 38 0 36 0; +#X connect 39 0 76 0; +#X connect 40 0 41 1; +#X connect 41 0 39 1; +#X connect 41 0 84 0; +#X connect 43 0 101 1; +#X connect 44 0 45 0; +#X connect 46 0 64 1; +#X connect 47 0 93 1; +#X connect 48 0 54 2; +#X connect 48 0 55 2; +#X connect 49 0 50 0; +#X connect 49 0 15 1; +#X connect 50 0 51 0; +#X connect 50 0 16 1; +#X connect 51 0 52 0; +#X connect 51 0 17 1; +#X connect 52 0 53 0; +#X connect 52 0 26 1; +#X connect 53 0 32 0; +#X connect 53 0 23 1; +#X connect 54 0 18 0; +#X connect 56 0 2 0; +#X connect 56 0 63 0; +#X connect 56 0 65 0; +#X connect 56 0 92 0; +#X connect 56 1 57 0; +#X connect 56 1 144 0; +#X connect 56 1 147 0; +#X connect 57 0 44 0; +#X connect 57 0 58 0; +#X connect 57 0 100 0; +#X connect 58 0 42 0; +#X connect 59 0 10 1; +#X connect 59 0 93 0; +#X connect 59 0 101 0; +#X connect 59 0 160 1; +#X connect 60 0 70 0; +#X connect 61 0 8 0; +#X connect 63 0 48 0; +#X connect 64 0 153 0; +#X connect 65 0 0 0; +#X connect 66 0 41 0; +#X connect 66 0 25 1; +#X connect 67 0 8 1; +#X connect 68 0 10 0; +#X connect 69 0 31 0; +#X connect 70 0 30 0; +#X connect 71 0 70 1; +#X connect 72 0 84 1; +#X connect 73 0 74 0; +#X connect 74 0 75 0; +#X connect 75 0 81 0; +#X connect 76 0 73 0; +#X connect 77 0 85 1; +#X connect 78 0 80 1; +#X connect 79 0 86 1; +#X connect 80 0 86 0; +#X connect 80 0 74 1; +#X connect 81 0 55 0; +#X connect 82 0 83 1; +#X connect 83 0 81 1; +#X connect 84 0 85 0; +#X connect 85 0 80 0; +#X connect 85 0 73 1; +#X connect 86 0 83 0; +#X connect 86 0 75 1; +#X connect 87 0 111 0; +#X connect 87 1 90 0; +#X connect 88 0 54 0; +#X connect 89 0 88 1; +#X connect 89 0 91 0; +#X connect 90 0 54 0; +#X connect 91 0 90 1; +#X connect 92 0 89 0; +#X connect 93 0 30 1; +#X connect 95 0 94 0; +#X connect 97 0 96 0; +#X connect 98 0 99 0; +#X connect 100 0 95 0; +#X connect 101 0 42 0; +#X connect 103 0 102 0; +#X connect 104 0 54 0; +#X connect 105 0 104 0; +#X connect 106 0 165 3; +#X connect 107 0 60 0; +#X connect 108 0 140 0; +#X connect 110 0 132 0; +#X connect 111 0 112 0; +#X connect 112 0 115 0; +#X connect 113 0 112 1; +#X connect 114 0 150 0; +#X connect 115 0 121 0; +#X connect 117 0 134 0; +#X connect 120 0 43 0; +#X connect 121 1 171 0; +#X connect 123 0 122 0; +#X connect 124 0 122 0; +#X connect 125 0 43 0; +#X connect 126 0 125 0; +#X connect 127 0 6 0; +#X connect 128 0 127 1; +#X connect 133 0 132 0; +#X connect 134 0 108 0; +#X connect 135 0 132 0; +#X connect 138 0 139 0; +#X connect 139 0 156 0; +#X connect 141 0 151 0; +#X connect 142 0 143 0; +#X connect 142 0 143 1; +#X connect 145 0 127 0; +#X connect 145 1 130 0; +#X connect 146 0 147 0; +#X connect 148 0 147 1; +#X connect 149 0 147 0; +#X connect 150 0 165 0; +#X connect 151 0 150 0; +#X connect 153 0 155 0; +#X connect 153 1 154 0; +#X connect 154 0 88 0; +#X connect 154 1 159 0; +#X connect 155 0 87 0; +#X connect 155 1 158 0; +#X connect 156 1 56 0; +#X connect 157 0 145 0; +#X connect 158 0 160 0; +#X connect 159 0 160 0; +#X connect 160 0 69 0; +#X connect 162 0 161 0; +#X connect 164 0 163 0; +#X connect 165 0 6 0; +#X connect 166 0 169 1; +#X connect 168 0 122 0; +#X connect 169 0 167 0; +#X connect 170 0 169 0; +#X connect 171 0 115 1; diff --git a/opengl/test/textest.pd b/opengl/test/textest.pd new file mode 100644 index 0000000..3640d94 --- /dev/null +++ b/opengl/test/textest.pd @@ -0,0 +1,54 @@ +#N canvas 561 0 657 860 10; +#X obj 106 106 3dp_windowcontext; +#X obj 101 27 metro 20; +#X obj 102 11 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X obj 56 40 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X floatatom 181 9 5 0 0 0 - - -; +#X floatatom 106 663 5 0 0 0 - - -; +#X obj 221 736 print; +#X obj 229 541 pdp_v4l; +#X obj 231 513 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 369 682 pdp_convert texture/*/*; +#X obj 314 760 pdp_xv; +#X obj 365 712 pdp_description; +#X symbolatom 376 746 10 0 0 0 - - -; +#X obj 369 657 pdp_convert bitmap/*/*; +#X obj 164 523 metro 40; +#X obj 164 500 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X floatatom 214 466 5 0 0 0 - - -; +#X obj 363 235 pdp_control; +#X msg 366 199 3dthread \$1; +#X obj 374 167 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X obj 109 135 3dp_mouserotate; +#X obj 32 726 3dp_draw sphere 9; +#X msg 167 417 open /dev/video1; +#X obj 379 558 pdp_chrot; +#X floatatom 429 519 5 0 0 0 - - -; +#X connect 0 0 20 0; +#X connect 0 1 20 1; +#X connect 1 0 0 0; +#X connect 2 0 1 0; +#X connect 3 0 0 0; +#X connect 4 0 1 1; +#X connect 5 0 21 2; +#X connect 7 0 23 0; +#X connect 8 0 7 0; +#X connect 9 0 11 0; +#X connect 9 0 21 1; +#X connect 11 0 12 0; +#X connect 13 0 9 0; +#X connect 14 0 7 0; +#X connect 15 0 14 0; +#X connect 16 0 14 1; +#X connect 18 0 17 0; +#X connect 19 0 18 0; +#X connect 20 0 21 0; +#X connect 22 0 7 0; +#X connect 23 0 13 0; +#X connect 23 0 10 0; +#X connect 24 0 23 1; diff --git a/puredata/CONTENTS b/puredata/CONTENTS new file mode 100644 index 0000000..19eeaaa --- /dev/null +++ b/puredata/CONTENTS @@ -0,0 +1,10 @@ +base pdp base pd object +image_base image processing base pd object +dpd_base bucket base pd object +comm pdp communication protocol in pd +compat legacy pdp stuff +control control pdp from within pd +fp object interface to the forth system +forthconsole console interface to the forth system +queue processing queue and synchro stuff +ut some utility pd objects diff --git a/puredata/Makefile b/puredata/Makefile new file mode 100644 index 0000000..11c78ec --- /dev/null +++ b/puredata/Makefile @@ -0,0 +1,12 @@ + +OBJECTS = pdp_base.o pdp_imagebase.o pdp_dpd_base.o pdp_ut.o pdp_queue.o pdp_comm.o \ + pdp_control.o pdp_compat.o $(PDP_PDMOD) + + +include ../Makefile.config + +all: $(OBJECTS) + +clean: + rm -f *~ + rm -f *.o diff --git a/puredata/pdp_base.c b/puredata/pdp_base.c new file mode 100644 index 0000000..194134e --- /dev/null +++ b/puredata/pdp_base.c @@ -0,0 +1,415 @@ +/* + * Pure Data Packet base class implementation. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 file contains the pdp base class object. + This is really nothing more than an attempt to stay away from c++ + as far as possible, while having some kind of base class functionality + for pdp (tucking away the communication & thread protocol). + +*/ + +#include "pdp_base.h" +#include <stdarg.h> + + +static void pdp_base_debug(t_pdp_base *b, t_floatarg f) +{ + int i; + post("debug"); + post("inlets: %d", b->b_inlets); + post("\tpacket\tnext_packet"); + for (i=0; i<b->b_inlets; i++) + post("\t%d\t%d", b->b_packet[i], b->b_packet_next[i]); + //post("outlets: %d", b->b_inlets); +} + +static void pdp_base_thread(t_pdp_base *b, t_floatarg f) +{ + int i = (int)f; + if ((i == 0) || (i == 1)) b->b_thread_enabled = i; +} + +static void pdp_base_process(t_pdp_base *b) +{ + + if (b->b_process_method) + (*b->b_process_method)(b); +} + +/* this method is called after the thread has finished processing */ +static void pdp_base_postprocess(t_pdp_base *b) +{ + /* call the derived class postproc callback if there is any */ + if (b->b_postproc_method) + (*b->b_postproc_method)(b); + + /* unregister (mark unused) packet and propagate if packet is valid */ + if (b->b_outlet[0]) + pdp_pass_if_valid(b->b_outlet[0], &b->b_packet[0]); +} + + +/* move the passive packets in place */ +void pdp_base_movepassive(void *x) +{ + t_pdp_base *b = (t_pdp_base *)x; + int i; + + /* if a cold packet was received in the meantime + swap it in, else keep the old one */ + for (i=1; i<b->b_inlets; i++){ + pdp_replace_if_valid(&b->b_packet[i], &b->b_packet_next[i]); + } + + +} + +/* the standard bang method */ +void pdp_base_bang(void *x) +{ + t_pdp_base *b = (t_pdp_base *)x; + int i; + + /* if pdp thread is still processing, do nothing */ + if (-1 != b->b_queue_id) return; + + /* move packets in place */ + pdp_base_movepassive(x); + + + /* if there is a preproc method defined, call it inside + the pd thread. (mainly for allocations) */ + if (b->b_preproc_method) + (*b->b_preproc_method)(b); + + /* check if we need to use pdp queue */ + if (b->b_thread_enabled){ + + /* add the process method and callback to the process queue */ + pdp_procqueue_add(b->b_q, b, pdp_base_process, pdp_base_postprocess, &b->b_queue_id); + } + else{ + /* call both methods directly */ + pdp_base_process(b); + pdp_base_postprocess(b); + } +} + +/* hot packet input handler */ +void pdp_base_input_hot(t_pdp_base *b, t_symbol *s, t_floatarg f) +{ + + int p = (int)f; + + /* dont register if active inlet is disabled */ + if (!b->b_active_inlet_enabled) return; + + /* register the packet (readonly or read/write) + or drop it if we have an active packet + if type template is not null, packet will be converted */ + + + if (b->b_active_inlet_readonly){ + if (s == S_REGISTER_RO){ + if (b->b_type_template[0]){ + pdp_packet_convert_ro_or_drop(&b->b_packet[0], p, b->b_type_template[0]); + } + else{ + pdp_packet_copy_ro_or_drop(&b->b_packet[0], p); + } + } + } + else{ + if (s == S_REGISTER_RW) { + if (b->b_type_template[0]){ + pdp_packet_convert_rw_or_drop(&b->b_packet[0], p, b->b_type_template[0]); + } + else{ + pdp_packet_copy_rw_or_drop(&b->b_packet[0], p); + } + } + } + + /* start processing if there is an active packet to process + and the processing method is not active */ + + if ((s == S_PROCESS) && (-1 != b->b_packet[0]) && (-1 == b->b_queue_id)){ + pdp_base_bang(b); + } + //if ((pdp_sym_prc() == s) && (-1 != b->b_packet[0]) && (!b->b_dropped)) pdp_base_bang(b); + +} + +/* cold packet input handlers */ +void pdp_base_input_cold(t_pdp_base *b, t_symbol *s, int ac, t_atom *av) +{ + + int p; + int i; + char msg[] = "pdp1"; + char *c; + + int inlet; + + //post("pdp_base_input_cold: got packet"); + + /* do cheap tests first */ + if (ac != 2) return; + if (av[0].a_type != A_SYMBOL) return; + if (av[0].a_w.w_symbol != S_REGISTER_RO) return; + if (av[1].a_type != A_FLOAT) return; + p = (int)av[1].a_w.w_float; + + + /* check if it's a pdp message + and determine inlet */ + for (i=1; i<MAX_NB_PDP_BASE_INLETS; i++){ + if (s == gensym(msg)){ + inlet = i; + goto found; + } + else{ + msg[3]++; + } + } + return; + + + found: + + /* store the packet and trow away + the old one, if there is any */ + + pdp_packet_copy_ro_or_drop(&b->b_packet_next[inlet], p); +} + + +void pdp_base_set_process_method(void *x, t_pdp_method m) +{ + t_pdp_base *b = (t_pdp_base *)x; + b->b_process_method = m; +} + +void pdp_base_set_preproc_method(void *x, t_pdp_method m) +{ + t_pdp_base *b = (t_pdp_base *)x; + b->b_preproc_method = m; +} + + +void pdp_base_set_postproc_method(void *x, t_pdp_method m) +{ + t_pdp_base *b = (t_pdp_base *)x; + b->b_postproc_method = m; +} + + +void pdp_base_queue_wait(void *x) +{ + t_pdp_base *b = (t_pdp_base *)x; + pdp_procqueue_wait(b->b_q); +} + +void pdp_base_set_queue(void *x, t_pdp_procqueue *q) +{ + t_pdp_base *b = (t_pdp_base *)x; + pdp_base_queue_wait(x); + b->b_q = q; +} + +t_pdp_procqueue *pdp_base_get_queue(void *x) +{ + t_pdp_base *b = (t_pdp_base *)x; + return b->b_q; +} + +void pdp_base_setup(t_class *c) +{ + + /* add pdp base class methods */ + class_addmethod(c, (t_method)pdp_base_thread, gensym("thread"), A_FLOAT, A_NULL); + class_addmethod(c, (t_method)pdp_base_debug, gensym("debug"), A_NULL); + + /* hot packet handler */ + class_addmethod(c, (t_method)pdp_base_input_hot, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + + /* cold packet handler */ + class_addanything(c, (t_method)pdp_base_input_cold); +} + +/* pdp base instance constructor */ +void pdp_base_init(void *x) +{ + int i; + t_pdp_base *b = (t_pdp_base *)x; + + b->b_channel_mask = -1; + + for(i=0; i<MAX_NB_PDP_BASE_INLETS; i++){ + b->b_packet[i] = -1; + b->b_packet_next[i] = -1; + b->b_type_template[i] = 0; + } + + b->b_queue_id = -1; + //b->b_dropped = 0; + b->b_process_method = 0; + b->b_preproc_method = 0; + b->b_inlets = 1; + b->b_outlets = 0; + b->b_active_inlet_enabled = 1; + b->b_active_inlet_readonly = 0; + b->b_thread_enabled = 1; + + // default queue is pdp queue + b->b_q = pdp_queue_get_queue(); + +} + +/* base instance destructor */ +void pdp_base_free(void *x) +{ + int i; + t_pdp_base *b = (t_pdp_base *)x; + /* remove process method from queue before deleting data */ + pdp_procqueue_finish(b->b_q, b->b_queue_id); + + /* delete stuff */ + for(i=0; i<MAX_NB_PDP_BASE_INLETS; i++){ + pdp_packet_mark_unused(b->b_packet[i]); + pdp_packet_mark_unused(b->b_packet_next[i]); + } + +} + +void pdp_base_readonly_active_inlet(void *x) +{ + t_pdp_base *b = (t_pdp_base *)x; + b->b_active_inlet_readonly = 1; +} + +void pdp_base_disable_active_inlet(void *x) +{ + t_pdp_base *b = (t_pdp_base *)x; + b->b_active_inlet_enabled = 0; +} + + +/* add an inlet */ +void pdp_base_add_pdp_inlet(void *x) +{ + t_pdp_base *b = (t_pdp_base *)x; + char s[] = "pdp0"; + s[3] += b->b_inlets; + + if (b->b_inlets < MAX_NB_PDP_BASE_INLETS){ + inlet_new(&b->x_obj, &b->x_obj.ob_pd, gensym("pdp"), gensym(s)); + b->b_inlets++; + } + else { + post("pdp_base_add_pdp_inlet: only %d pdp inlets allowed. ignoring.", MAX_NB_PDP_BASE_INLETS); + } +} + + +/* add an outlet: only one allowed */ +t_outlet *pdp_base_add_pdp_outlet(void *x) +{ + t_pdp_base *b = (t_pdp_base *)x; + t_outlet *outlet = outlet_new(&b->x_obj, &s_anything); + + + if (b->b_outlets < MAX_NB_PDP_BASE_OUTLETS){ + b->b_outlet[b->b_outlets] = outlet; + b->b_outlets++; + } + + return outlet; + +} + +void pdp_base_set_packet(void *x, int inlet, int packet) +{ + t_pdp_base *b = (t_pdp_base *)x; + + if (inlet < b->b_inlets){ + //post("%d %d", b->b_packet[inlet], b->b_packet_next[inlet]); + pdp_packet_mark_unused(b->b_packet[inlet]); + b->b_packet[inlet] = packet; + } +} + + +int pdp_base_get_packet(void *x, int inlet) +{ + t_pdp_base *b = (t_pdp_base *)x; + + if (inlet < b->b_inlets){ + //post("%d %d", b->b_packet[inlet], b->b_packet_next[inlet]); + return (b->b_packet[inlet]); + } + + return -1; +} + +int pdp_base_move_packet(void *x, int inlet) +{ + t_pdp_base *b = (t_pdp_base *)x; + int p; + + if (inlet < b->b_inlets){ + p = b->b_packet[inlet]; + b->b_packet[inlet] = -1; + return (p); + } + + return -1; +} + + + +t_object *pdp_base_get_object(void *x) +{ + return (t_object *)x; +} + +void pdp_base_add_gen_inlet(void *x, t_symbol *from, t_symbol *to) +{ + t_object *o = (t_object *)x; + inlet_new(o, &o->ob_pd, from, to); +} + +void pdp_base_disable_thread(void *x) +{ + + t_pdp_base *b = (t_pdp_base *)x; + b->b_thread_enabled = 0; +} + +void pdp_base_set_type_template(void *x, int inlet, t_pdp_symbol *type_template) +{ + t_pdp_base *b = (t_pdp_base *)x; + if (inlet < b->b_inlets){ + b->b_type_template[inlet] = type_template; + } +} diff --git a/puredata/pdp_comm.c b/puredata/pdp_comm.c new file mode 100644 index 0000000..4c67659 --- /dev/null +++ b/puredata/pdp_comm.c @@ -0,0 +1,367 @@ +/* + * Pure Data Packet system implementation. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 file contains misc communication (packet) methods for pd */ + + +#include <stdio.h> +#include "pdp_pd.h" +#include "pdp_internals.h" +#include "pdp_packet.h" +#include "pdp_comm.h" +#include "pdp_type.h" +#include "pdp_control.h" +#include "pdp_mem.h" +#include "pdp_queue.h" // for notify drop: fix this (should be from pdp_control.h) +#include "pdp_debug.h" + +/* all symbols are C style */ +#ifdef __cplusplus +extern "C" +{ +#endif + + +/* interface to pd system: + pdp/dpd communication protocol in pd + pd <-> pdp atom and list conversion */ + + /* NOTE: when using the outlet_pdp methods, the packet + is no longer read/write, but can be readonly */ + + + /* NOTE: since 0.13 the passing packet is no more. + in order to limit copying. processors should always register ro, + and replace with writable when packet needs to be written in the process method */ + + +/* send a packet to an outlet */ +void outlet_pdp_register(t_outlet *out, int packetid) +{ + t_atom atom[2]; + + SETFLOAT(atom+1, (float)packetid); + + /* during the following phase, + objects can register a ro copy */ + + SETSYMBOL(atom+0, S_REGISTER_RO); + outlet_anything(out, S_PDP, 2, atom); + + /* DEPRECIATED: objects can register a rw copy + but this will always copy the packet. it is better + to perform a pdp_packet_replace_with_writable operation during the process step */ + + SETSYMBOL(atom+0, S_REGISTER_RW); + outlet_anything(out, S_PDP, 2, atom); + +} +/* send a packet to an outlet */ +void outlet_pdp_process(t_outlet *out) +{ + t_atom atom[2]; + + /* set a dummy invalid packet. + this is for uniform pdp messages in pd, for ease of routing. */ + SETFLOAT(atom+1, (float)-1); + + /* during the process phase, objects can perform pdp_packet_replace_with_writable + and process the packet data */ + SETSYMBOL(atom+0, S_PROCESS); + outlet_anything(out, S_PDP, 2, atom); + +} + +/* for compat */ +void outlet_pdp(t_outlet *out, int packetid) +{ + outlet_pdp_register(out, packetid); + outlet_pdp_process(out); +} + +/* send an accumulation packet to an outlet */ +void outlet_dpd(t_outlet *out, int packetid) +{ + t_atom atom[2]; + + SETFLOAT(atom+1, (float)packetid); + + SETSYMBOL(atom+0, S_INSPECT); + outlet_anything(out, S_DPD, 2, atom); + + SETSYMBOL(atom+0, S_ACCUMULATE); + outlet_anything(out, S_DPD, 2, atom); + +} + +/* unregister a packet and send it to an outlet */ +void + +pdp_packet_pass_if_valid(t_outlet *outlet, int *packet_ptr) +{ + t_pdp *header = pdp_packet_header(*packet_ptr); + if (header){ + + /* send register phase */ + outlet_pdp_register(outlet, *packet_ptr); + + /* unregister */ + pdp_packet_mark_unused(*packet_ptr); + *packet_ptr = -1; + + /* send process phase */ + outlet_pdp_process(outlet); + + } +} + +void +pdp_packet_replace_if_valid(int *dpacket, int *spacket) +{ + if (-1 != *spacket){ + pdp_packet_mark_unused(*dpacket); + *dpacket = *spacket; + *spacket = -1; + } + +} + + +int +pdp_packet_copy_ro_or_drop(int *dpacket, int spacket) +{ + int drop = 0; + if (*dpacket == -1) *dpacket = pdp_packet_copy_ro(spacket); + else { + /* send a notification there is a dropped packet */ + pdp_control_notify_drop(spacket); + drop = 1; + } + return drop; +} + + +int +pdp_packet_copy_rw_or_drop(int *dpacket, int spacket) +{ + int drop = 0; + if (*dpacket == -1) *dpacket = pdp_packet_copy_rw(spacket); + else { + /* send a notification there is a dropped packet */ + pdp_control_notify_drop(spacket); + drop = 1; + } + return drop; +} + +int +pdp_packet_convert_ro_or_drop(int *dpacket, int spacket, t_pdp_symbol *template) +{ + int drop = 0; + + if (!template) return pdp_packet_copy_ro_or_drop(dpacket, spacket); + + if (*dpacket == -1) *dpacket = pdp_packet_convert_ro(spacket, template); + else { + /* send a notification there is a dropped packet */ + pdp_control_notify_drop(spacket); + drop = 1; + } + return drop; +} + + +int +pdp_packet_convert_rw_or_drop(int *dpacket, int spacket, t_pdp_symbol *template) +{ + int drop = 0; + + if (!template) return pdp_packet_copy_rw_or_drop(dpacket, spacket); + + if (*dpacket == -1) *dpacket = pdp_packet_convert_rw(spacket, template); + else { + /* send a notification there is a dropped packet */ + pdp_control_notify_drop(spacket); + drop = 1; + } + return drop; +} + + +/* send a pdp list to a pd outlet. packets are not copied but passed! */ +void outlet_pdp_atom(t_outlet *out, t_pdp_atom *a) +{ + int packet = -1; + if (!a) return; + switch(a->t){ + case a_float: + outlet_float(out, a->w.w_float); + return; + case a_int: + outlet_float(out, (float)a->w.w_int); + return; + case a_symbol: + outlet_symbol(out, gensym(a->w.w_symbol->s_name)); + return; + case a_list: + outlet_pdp_list(out, a->w.w_list); + return; + case a_packet: + pdp_packet_pass_if_valid(out, &a->w.w_packet); + return; + default: + return; + } +} + +void outlet_pdp_list(t_outlet *out, struct _pdp_list *l) +{ + int elements; + t_atom *atomlist; + t_pdp_atom *pdp_a; + t_atom *pd_a; + t_symbol *pd_selector; + + if (!l) return; + switch(l->elements){ + case 0: /* bang */ + outlet_bang(out); + return; + case 1: /* atom */ + outlet_pdp_atom(out, l->first); + return; + default: /* proper list*/ + elements = l->elements; + + /* allocate list */ + atomlist = pdp_alloc(sizeof (t_atom) * l->elements); + pd_a = atomlist; + pdp_a = l->first; + + /* setup selector */ + if (pdp_a->t != a_symbol){ + pd_selector = gensym("list"); + } + else { + pd_selector = gensym(pdp_a->w.w_symbol->s_name); + elements--; + pdp_a = pdp_a->next; + } + + /* setup atoms */ + while (pdp_a){ + switch(pdp_a->t){ + case a_float: + SETFLOAT(pd_a, pdp_a->w.w_float); + break; + case a_int: + SETFLOAT(pd_a, (float)pdp_a->w.w_int); + break; + case a_symbol: + SETSYMBOL(pd_a, gensym(pdp_a->w.w_symbol->s_name)); + break; + default: + SETSYMBOL(pd_a, gensym("invalid")); + break; + } + + pdp_a = pdp_a->next; + pd_a++; + } + + /* send out */ + outlet_anything(out, pd_selector, elements, atomlist); + + + + /* clean up */ + pdp_dealloc(atomlist); + + } + + +} + + +void pd_atom_to_pdp_atom(t_atom *pdatom, t_pdp_atom *pdpatom) +{ + switch (pdatom->a_type){ + case A_FLOAT: + pdpatom->t = a_float; + pdpatom->w.w_float = pdatom->a_w.w_float; + break; + case A_SYMBOL: + pdpatom->t = a_symbol; + pdpatom->w.w_symbol = pdp_gensym(pdatom->a_w.w_symbol->s_name); + break; + default: + pdpatom->t = a_undef; + break; + } +} + + + +/* some "accelerated" pd symbols */ +t_symbol s_pdp = {"pdp", 0, 0}; +t_symbol s_register_ro = {"register_ro", 0, 0}; +t_symbol s_register_rw = {"register_rw", 0, 0}; +t_symbol s_process = {"process", 0, 0}; +t_symbol s_dpd = {"dpd", 0, 0}; +t_symbol s_inspect = {"inspect", 0, 0}; +t_symbol s_accumulate = {"accumulate", 0, 0}; +t_symbol s_chanmask = {"chanmask", 0, 0}; + +// internal pd method +t_symbol *dogensym(char *s, t_symbol *oldsym); +static void _addsym(t_symbol *s) +{ + + /* don't kill me for this one.. + if the symbol is already defined and used, .. well, that's a problem + but right now it seems a reasonable hack */ + + t_symbol *sret = dogensym(s->s_name, s); + if (s != sret){ + post("PDP INIT ERROR: pd symbol clash adding symbol %s: new=%08x old=%08x", s->s_name, s, sret); + post("try loading pdp before other libraries"); + } +} + +void +pdp_pdsym_setup(void) +{ + + _addsym(&s_pdp); + _addsym(&s_register_ro); + _addsym(&s_register_rw); + _addsym(&s_process); + _addsym(&s_dpd); + _addsym(&s_inspect); + _addsym(&s_accumulate); + _addsym(&s_chanmask); + +} + + + +#ifdef __cplusplus +} +#endif diff --git a/puredata/pdp_compat.c b/puredata/pdp_compat.c new file mode 100644 index 0000000..e7bc0c2 --- /dev/null +++ b/puredata/pdp_compat.c @@ -0,0 +1,57 @@ +/* + * Pure Data Packet system implementation. Compatibility routines. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 file contains misc communication methods */ + +#include <stdio.h> + +#include "pdp_pd.h" +#include "pdp_comm.h" +#include "pdp_internals.h" + +/* all symbols are C style */ +#ifdef __cplusplus +extern "C" +{ +#endif + + + +void +pdp_pass_if_valid(t_outlet *outlet, int *packet) +{ + pdp_packet_pass_if_valid(outlet, packet); +} + +void +pdp_replace_if_valid(int *dpacket, int *spacket) +{ + pdp_packet_replace_if_valid(dpacket, spacket); + +} + + + + + + +#ifdef __cplusplus +} +#endif diff --git a/puredata/pdp_control.c b/puredata/pdp_control.c new file mode 100644 index 0000000..0b49fd9 --- /dev/null +++ b/puredata/pdp_control.c @@ -0,0 +1,186 @@ +/* + * Pure Data Packet system implementation: control object + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 is an actual pd class that is used for communication with the + pdp framework */ + +#include "pdp_internals.h" +#include "pdp_control.h" +#include "pdp_packet.h" +#include <stdio.h> + +/* all symbols are C style */ +#ifdef __cplusplus +extern "C" +{ +#endif + + + +static long dropped_packets; + +static t_class* pdp_control_class; + + +/* pdp control instance data */ + +struct _pdp_control; +typedef struct _pdp_control +{ + t_object x_obj; + t_outlet *x_outlet0; + struct _pdp_control *x_next; + +} t_pdp_control; + + + +static t_pdp_control *pdp_control_list; + +static void pdp_control_info(t_pdp_control *x) +{ +} + +static void pdp_control_collectgarbage(t_pdp_control *x) +{ + int nb_packets_freed = pdp_pool_collect_garbage(); + post("pdp_control: freed %d packets", nb_packets_freed); + +} + +static void pdp_control_set_mem_limit(t_pdp_control *x, t_floatarg f) +{ + int limit = (int)f; + if (limit < 0) limit = 0; + pdp_pool_set_max_mem_usage(limit); + if (limit) post("pdp_control: set memory limit to %d bytes", limit); + else post("pdp_control: disabled memory limit"); + +} + +static void pdp_control_thread(t_pdp_control *x, t_floatarg f) +{ + int t = (int)f; + + if (t){ + post("pdp_control: pdp is now using its own processing thread"); + pdp_queue_use_thread(1); + } + else { + post("pdp_control: pdp is now using the main pd thread"); + pdp_queue_use_thread(0); + } +} + + +static void pdp_control_send_drop_message(t_pdp_control *x) +{ + t_atom atom[1]; + t_symbol *s = gensym("pdp_drop"); + + SETFLOAT(atom+0, (float)dropped_packets); + outlet_anything(x->x_outlet0, s, 1, atom); +} + + +static void pdp_control_free(t_pdp_control *x) +{ + /* remove from linked list */ + t_pdp_control *curr = pdp_control_list; + if (pdp_control_list == x) pdp_control_list = x->x_next; + else while (curr){ + if (curr->x_next == x) { + curr->x_next = x->x_next; + break; + } + else { + curr = curr->x_next; + } + + } +} + + +static void *pdp_control_new(void) +{ + t_pdp_control *x = (t_pdp_control *)pd_new(pdp_control_class); + x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + + /* add to list */ + x->x_next = pdp_control_list; + pdp_control_list = x; + return x; +} + +/************************* class methods ***************************************/ + + +void pdp_control_addmethod(t_method m, t_symbol *s) +{ + class_addmethod(pdp_control_class, m, s, A_GIMME, A_NULL); +} + +void pdp_control_setup(void) +{ + + pdp_control_list = 0; + dropped_packets = 0; + + /* setup pd class data */ + pdp_control_class = class_new(gensym("pdp_control"), (t_newmethod)pdp_control_new, + (t_method)pdp_control_free, sizeof(t_pdp_control), 0, A_NULL); + + + class_addmethod(pdp_control_class, (t_method)pdp_control_info, gensym("info"), A_NULL); + class_addmethod(pdp_control_class, (t_method)pdp_control_thread, gensym("thread"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_control_class, (t_method)pdp_control_collectgarbage, gensym("collectgarbage"), A_NULL); + class_addmethod(pdp_control_class, (t_method)pdp_control_set_mem_limit, gensym("memlimit"), A_FLOAT, A_NULL); +} + + + +void pdp_control_notify_broadcast(t_pdp_control_method_notify *notify) +{ + t_pdp_control *curr = pdp_control_list; + while (curr){ + (*notify)(curr); + curr = curr->x_next; + } +} + + + +/************************* notify class methods *************************/ + +void pdp_control_notify_drop(int packet) +{ + dropped_packets++; + + /* send drop notify to controller class instances */ + pdp_control_notify_broadcast(pdp_control_send_drop_message); + //post("dropped packet"); +} + + + +#ifdef __cplusplus +} +#endif diff --git a/puredata/pdp_dpd_base.c b/puredata/pdp_dpd_base.c new file mode 100644 index 0000000..371b99e --- /dev/null +++ b/puredata/pdp_dpd_base.c @@ -0,0 +1,270 @@ +/* + * Pure Data Packet module. DPD base class implementation. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +#include "pdp_dpd_base.h" +#include "pdp_internals.h" + + +#define THIS(b) t_pdp_dpd_base *b = (t_pdp_dpd_base *)x + + +#ifdef __cplusplus +extern "C" +{ +#endif + + + +/* PRIVATE METHODS */ + + + + +/* dpd packet context input handler */ +static void _pdp_dpd_base_context_input(t_pdp_dpd_base *b, t_symbol *s, t_floatarg f) +{ + + int p = (int)f; + int i; + + //post ("pdp_dpd_base_context_input: got %s %d", s->s_name, p); + + /* sources/sinks have active inlet disabled */ + if (b->b_dpd_active_inlet_disabled) return; + + /* handle inspect message */ + if (s == S_INSPECT){ + + /* store packet for inspector */ + b->b_context_packet = p; + + /* add inspector to pdp queue + this is special: it doesn't use a command object */ + pdp_dpd_base_queue_command(b, b, b->b_inspector_method, b->b_inspector_callback, 0); + } + + /* handle accumulate message */ + if (s == S_ACCUMULATE){ + + /* store context for accumulator methods */ + b->b_context_packet = p; + + /* call bang */ + pdp_dpd_base_bang(b); + + + } + +} + +/* default command object (returns self) */ +void *_pdp_dpd_base_get_command_object(void *x){return x;} + +/* PUBLIC METHODS */ + + +void pdp_dpd_base_queue_command(void *x, void *c, t_pdp_method process, + t_pdp_method callback, int *id) +{ + THIS(b); + t_pdp_procqueue *q = pdp_base_get_queue(x); + pdp_procqueue_add(q, c, process, callback, id); + +} + +/* bang method (propagate context to outlet) : it is not registered as a pd message by default ! */ +void pdp_dpd_base_bang(void *x) +{ + THIS(b); + int i, id; + void *cobj; + + /* move passive pdp packets in place */ + pdp_base_movepassive(x); + + /* get command object (or use self) */ + cobj = b->b_command_factory_method ? (b->b_command_factory_method)(b) : b; + //post(" command object is %x. object is %x", cobj, b); + + + /* queue acc method & propagate for all outlets */ + for (i=b->b_nb_context_outlets; i--;){ + + + /* propagate the context packet to the outlet */ + if (b->b_outlet_enable[i]){ + pdp_dpd_base_queue_command(x, cobj, b->b_accum_method[i], b->b_accum_callback[i], 0); + outlet_dpd(b->b_context_outlet[i], b->b_context_packet); + } + else{ + //post("outlet %d disabled", i); + } + } + + /* queue cleanup method */ + if (b->b_cleanup_method) + //pdp_procqueue_add(b->b_q, b, b->b_cleanup_method, 0, &b->b_cleanup_queue_id); + pdp_dpd_base_queue_command(x, cobj, b->b_cleanup_method, b->b_cleanup_callback, 0); + + /* send communication complete notify */ + if (b->b_complete_notify) + (b->b_complete_notify)(x); + +} + +/* get/set context packet */ +int pdp_dpd_base_get_context_packet(void *x){ + THIS(b); + return b->b_context_packet; +} +int pdp_dpd_base_move_context_packet(void *x){ + THIS(b); + int p = b->b_context_packet; + b->b_context_packet = -1; + return p; +} + +void pdp_dpd_base_set_context_packet(void *x, int p){ + THIS(b); + pdp_packet_mark_unused(b->b_context_packet); + b->b_context_packet = p; +} + +/* add a cleanup callback (called after all propagation is finished) for sources/sinks */ +void pdp_dpd_base_add_cleanup(void *x, t_pdp_method cleanup_method, t_pdp_method cleanup_callback) +{ + THIS(b); + b->b_cleanup_method = cleanup_method; + b->b_cleanup_callback = cleanup_callback; + //b->b_cleanup_queue_id = -1; +} + +/* add a inspector callback */ +void pdp_dpd_base_add_inspector(void *x, t_pdp_method inspector_method) +{ + THIS(b); + b->b_inspector_method = inspector_method; + //b->b_inspector_queue_id = -1; +} + +/* add a context outlet */ +t_outlet *pdp_dpd_base_add_outlet(void *x, t_pdp_method accum_method, t_pdp_method accum_callback) +{ + THIS(b); + int i = b->b_nb_context_outlets; + if (i < PDP_DPD_MAX_CONTEXT_OUTLETS){ + b->b_context_outlet[i] = outlet_new((t_object *)b, &s_anything); + b->b_outlet_enable[i] = 1; + b->b_accum_method[i] = accum_method; + b->b_accum_callback[i] = accum_callback; + //b->b_accum_queue_id[i] = -1; + b->b_nb_context_outlets++; + return b->b_context_outlet[i]; + } + else{ + post("pdp_dpd_base_add_outlet: no more free outlet slots"); + return 0; + } + +} + + +/* destructor */ +void pdp_dpd_base_free(void *x) +{ + THIS(b); + + /* free base */ + pdp_base_free(b); +} + + +void pdp_dpd_base_disable_active_inlet(void *x) +{ + THIS(b); + b->b_dpd_active_inlet_disabled = 1; +} + + + +void pdp_dpd_base_enable_outlet(void *x, int outlet, int toggle) +{ + THIS(b); + if (outlet >=0 && outlet < PDP_DPD_MAX_CONTEXT_OUTLETS){ + b->b_outlet_enable[outlet] = toggle; + } + +} + + +void pdp_dpd_base_register_complete_notify(void *x, t_pdp_method method) +{ + THIS(b); + b->b_complete_notify = method; +} + +void pdp_dpd_base_register_command_factory_method(void *x, t_pdp_newmethod command_factory_method) +{ + THIS(b); + b->b_command_factory_method = command_factory_method; +} + + +/* init method */ +void pdp_dpd_base_init(void *x) +{ + THIS(b); + + /* super init */ + pdp_base_init(b); + + /* disable pdp messages on active inlet (dpd messages are used as sync) */ + pdp_base_disable_active_inlet(b); + + /* init data */ + b->b_nb_context_outlets = 0; + b->b_context_packet = -1; + b->b_cleanup_method = 0; + //b->b_cleanup_queue_id = -1; + b->b_inspector_method = 0; + //b->b_inspector_queue_id = -1; + b->b_dpd_active_inlet_disabled = 0; + + // default notify == none + b->b_complete_notify = 0; + + // default command object getter + b->b_command_factory_method = 0; + +} + + +void pdp_dpd_base_setup(t_class *class) +{ + + pdp_base_setup(class); + class_addmethod(class, (t_method)_pdp_dpd_base_context_input, gensym("dpd"), A_SYMBOL, A_FLOAT, A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/puredata/pdp_imagebase.c b/puredata/pdp_imagebase.c new file mode 100644 index 0000000..f9634e1 --- /dev/null +++ b/puredata/pdp_imagebase.c @@ -0,0 +1,79 @@ +/* + * Pure Data Packet image processor base class implementation. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 file contains the pdp image base class object. +*/ + +#include "pdp_imagebase.h" +#include <stdarg.h> + + +static void pdp_imagebase_chanmask(t_pdp_base *b, t_floatarg f) +{ + int i = (int)f; + if (i < 0) i = -1; + b->b_channel_mask = i; +} + +void pdp_imagebase_setup(t_class *c) +{ + /* parent class setup */ + pdp_base_setup(c); + + /* add pdp base class methods */ + class_addmethod(c, (t_method)pdp_imagebase_chanmask, gensym("chanmask"), A_FLOAT, A_NULL); + +} + +/* pdp base instance constructor */ +void pdp_imagebase_init(void *x) +{ + int i; + t_pdp_imagebase *b = (t_pdp_imagebase *)x; + + /* init super */ + pdp_base_init(x); + + /* convert all active incoming packet types to image */ + pdp_base_set_type_template(x, 0, pdp_gensym("image/*/*")); + + /* default chanmask == all */ + b->b_channel_mask = -1; + +} + +/* base instance destructor */ +void pdp_imagebase_free(void *x) +{ + /* free super */ + pdp_base_free(x); + +} + +/* chanmask getter */ +u32 pdp_imagebase_get_chanmask(void *x) +{ + t_pdp_base *b = (t_pdp_base *)x; + return b->b_channel_mask; +} + diff --git a/puredata/pdp_queue.c b/puredata/pdp_queue.c new file mode 100644 index 0000000..b66289a --- /dev/null +++ b/puredata/pdp_queue.c @@ -0,0 +1,386 @@ +/* + * Pure Data Packet - processor queue module. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 is a the processor queue pdp system module + it receives tasks from objects that are schedules to + be computed in another thread. the object is signalled back + when the task is completed, using a polling mechanism + based on a pd clock. + + the queue object can be reused. the pdp system however only + has one instance (one pdp queue. pdp remains a serial program, though + it can run in a separate thread) + + */ + + +#include <string.h> + +#include "pdp_queue.h" +#include "pdp_mem.h" + + +#define D if (0) + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define PDP_QUEUE_LOGSIZE 10 +#define PDP_QUEUE_DELTIME 10.0f + + +/* there are 3 synchro methods, which can be used i.e. to ensure + all processing is done before shared resources are freed. + + all 3 wait for the processing thread to finish, and + + _wait: leaves callback queue untouched + _finish: clears the queue_id item in the callback queue + _flush: waits for thread and calls callbacks + and loops until callback list is empty + +*/ + + + +/********************* general purpose pd process queue class *********************/ + +void pdp_procqueue_wait(t_pdp_procqueue *q) +{ + D post("pdp_procqueue_wait(%x): waiting for pdp_queue_thread to finish processing", q); + pthread_mutex_lock(&q->mut); + while(((q->curr - q->head) & q->mask) != 0){ + + pthread_cond_wait(&q->cond_processingdone, &q->mut); + } + pthread_mutex_unlock(&q->mut); + D post("pdp_procqueue_wait(%x): pdp_procqueue_thread has finished processing", q); + +} +void pdp_procqueue_finish(t_pdp_procqueue *q, int index) +{ + + if (-1 == index) { + //post("pdp_pq_remove: index == -1"); + return; + } + /* wait for processing thread to finish*/ + pdp_procqueue_wait(q); + + /* invalidate callback at index */ + q->q[index & q->mask].x_callback = 0; + q->q[index & q->mask].x_queue_id = 0; + +} + +static void pdp_procqueue_callback (t_pdp_procqueue *q); + +void pdp_procqueue_flush(t_pdp_procqueue *q) +{ + /* wait once */ + pdp_procqueue_wait(q); + + do { + + /* process callbacks and wait again + in case the callbacks introduced new tasks */ + pdp_procqueue_callback(q); + pdp_procqueue_wait(q); + + } + /* repeat if callback list is not empty */ + while ((q->curr - q->head) & q->mask); + + D post("pdp_procqueue_flush: done"); +} + +static void pdp_procqueue_signal_processor(t_pdp_procqueue *q) +{ + + //NOTE: uncommenting these post statements causes a libc crash + //in mutex lock in putc + //D post("pdp_procqueue_signal_processor(%x): signalling process thread", q); + pthread_mutex_lock(&q->mut); + pthread_cond_signal(&q->cond_dataready); + pthread_mutex_unlock(&q->mut); + //D post("pdp_procqueue_signal_processor(%x): signalling done", q); + + +} + +static void pdp_procqueue_wait_for_feeder(t_pdp_procqueue *q) +{ + + + /* only use locking when there is no data */ + if(((q->curr - q->head) & q->mask) == 0){ + + /* signal processing done */ + D post("pdp_procqueue_wait_for_feeder(%x): signalling processing is done", q); + pthread_mutex_lock(&q->mut); + pthread_cond_signal(&q->cond_processingdone); + + /* wait until there is an item in the queue */ + while(((q->curr - q->head) & q->mask) == 0){ + pthread_cond_wait(&q->cond_dataready, &q->mut); + } + + pthread_mutex_unlock(&q->mut); + D post("pdp_procqueue_wait_for_feeder(%x): waiting done", q); + + } +} + + +int pdp_procqueue_full(t_pdp_procqueue *q) +{ + return (1 == ((q->tail - q->head) & q->mask)); +} + + +void pdp_procqueue_add(t_pdp_procqueue *q, void *owner, void *process, void *callback, int *queue_id) +{ + int i; + + /* if processing is in not in thread, just call the funcs */ + if (!q->use_thread){ + D post("pdp_procqueue_add(%q): calling processing routine directly", q); + if (queue_id) *queue_id = -1; + if (process) ((t_pdpmethod) process)(owner); + if (callback) ((t_pdpmethod) callback)(owner); + return; + } + + + /* if queue is full, print an error message and return */ + if (pdp_procqueue_full(q)) { + post("pdp_procqueue_add: WARNING: processing queue (%x) is full.\n", q); + post("pdp_procqueue_add: WARNING: tail %08x, head %08x (%08x), mask %08x.\n", q->tail, q->head, q->head & q->mask, q->mask); + post("pdp_procqueue_add: WARNING: skipping process method, calling callback directly.\n"); + if (queue_id) *queue_id = -1; + if (callback) ((t_pdpmethod) callback)(owner); + return; + //exit(1); + } + + /* schedule method in thread queue */ + i = q->head & q->mask; + q->q[i].x_owner = owner; + q->q[i].x_process = process; + q->q[i].x_callback = callback; + q->q[i].x_queue_id = queue_id; + if (queue_id) *queue_id = i; + //post("pdp_queue_add: added method to queue, index %d", i); + + + // increase the packet count + q->packets++; + + // move head forward + q->head++; + + pdp_procqueue_signal_processor(q); + +} + + +/* processing thread */ +static void *pdp_procqueue_thread(void *vq) +{ + t_pdp_procqueue *q = (t_pdp_procqueue *)vq; + + D post("pdp_procqueue_thread(%x): thread started", q); + + while(1){ + t_process_queue_item *p; + + + D post("pdp_procqueue_thread(%x): waiting for feeder", q); + + /* wait until there is data available */ + pdp_procqueue_wait_for_feeder(q); + + + D post("pdp_procqueue_thread(%x): processing %d", q, q->curr & q->mask); + + + /* call the process routine */ + p = &q->q[q->curr & q->mask]; + if (p->x_process) + (p->x_process)(p->x_owner); + + /* advance */ + q->curr++; + + + } + return 0; +} + + +/* call back all the callbacks */ +static void pdp_procqueue_callback (t_pdp_procqueue *q) +{ + + /* call callbacks for finished packets */ + while(0 != ((q->curr - q->tail) & q->mask)) + { + int i = q->tail & q->mask; + /* invalidate queue id */ + if(q->q[i].x_queue_id) *q->q[i].x_queue_id = -1; + /* call callback */ + if(q->q[i].x_callback) (q->q[i].x_callback)(q->q[i].x_owner); + //else post("pdp_pq_tick: callback %d is disabled",i ); + q->tail++; + } + +} + +/* the clock method */ +static void pdp_procqueue_tick (t_pdp_procqueue *q) +{ + /* do work */ + //if (!(ticks % 1000)) post("pdp tick %d", ticks); + + if (!q->use_thread) return; + + /* call callbacks */ + pdp_procqueue_callback(q); + + /* increase counter */ + q->ticks++; + + /* set clock for next update */ + clock_delay(q->pdp_clock, q->deltime); +} + + + +void pdp_procqueue_use_thread(t_pdp_procqueue* q, int t) +{ + /* if thread usage is being disabled, + wait for thread to finish processing first */ + if (t == 0) { + pdp_procqueue_wait(q); + q->use_thread = 0; + pdp_procqueue_callback(q); + clock_unset(q->pdp_clock); + } + else { + clock_unset(q->pdp_clock); + clock_delay(q->pdp_clock, q->deltime); + q->use_thread = 1; + } + +} + +void pdp_procqueue_init(t_pdp_procqueue *q, double milliseconds, int logsize) +{ + pthread_attr_t attr; + int size = 1 << logsize; + + /* setup pdp queue processor object */ + q->ticks = 0; + q->deltime = milliseconds; + + /* setup queue data */ + q->mask = size - 1; + q->head = 0; + q->tail = 0; + q->curr = 0; + q->q = pdp_alloc(size * sizeof(t_process_queue_item)); + memset(q->q, 0, size * sizeof(t_process_queue_item)); + + /* enable threads */ + q->use_thread = 1; + + /* setup synchro stuff */ + pthread_mutex_init(&q->mut, NULL); + pthread_cond_init(&q->cond_dataready, NULL); + pthread_cond_init(&q->cond_processingdone, NULL); + + + /* allocate the clock */ + q->pdp_clock = clock_new(q, (t_method)pdp_procqueue_tick); + + /* set the clock */ + clock_delay(q->pdp_clock, 0); + + /* start processing thread */ + + /* glibc doc says SCHED_OTHER is default, + but it seems not to be when initiated from a RT thread + so we explicitly set it here */ + pthread_attr_init (&attr); + //pthread_attr_setschedpolicy(&attr, SCHED_FIFO); + pthread_attr_setschedpolicy(&attr, SCHED_OTHER); + + D post("pdp_procqueue_init(%x): starting thread", q); + pthread_create(&q->thread_id, &attr, pdp_procqueue_thread, (void *)q); + D post("pdp_procqueue_init(%x): back in pd thread", q); + + /* wait for processing thread to finish */ + //pdp_procqueue_wait(q); + + /* set default disable/enable thread here */ + //post("pdp_queue: THREAD PROCESSING ON BY DEFAULT!!"); + pdp_procqueue_use_thread(q,0); + +} + + + + +/* the (static) pdp queue object */ +static t_pdp_procqueue pdp_queue; + + +/* get the default queue */ +t_pdp_procqueue *pdp_queue_get_queue(void){return &pdp_queue;} + + +#if 1 +/* default pdp queue shortcut methods */ +void pdp_queue_wait() {pdp_procqueue_wait(&pdp_queue);} +void pdp_queue_finish(int index) { pdp_procqueue_finish(&pdp_queue, index);} +void pdp_queue_add(void *owner, void *process, void *callback, int *queue_id) { + pdp_procqueue_add(&pdp_queue, owner, process, callback, queue_id); +} +void pdp_queue_use_thread(int t) {pdp_procqueue_use_thread(&pdp_queue, t);} +void pdp_queue_setup(void){ + pdp_procqueue_init(&pdp_queue, PDP_QUEUE_DELTIME, PDP_QUEUE_LOGSIZE); + pdp_procqueue_use_thread(&pdp_queue,0); +} +#endif + + + + + + + +#ifdef __cplusplus +} +#endif diff --git a/puredata/pdp_ut.c b/puredata/pdp_ut.c new file mode 100644 index 0000000..a1369e3 --- /dev/null +++ b/puredata/pdp_ut.c @@ -0,0 +1,262 @@ +/* + * Pure Data Packet - Utility toolkit objects. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 file contains some small utility pd objects that make working with + pdp objects a lot easier. Mainly as glue to be used in the abstractions + in the distro. */ + + +#include "pdp_pd.h" +#include <math.h> + +/* this object does an add, scale, clip operation */ + +t_class *pdp_ut_addscaleclip_class; + +typedef struct pdp_ut_addscaleclip_struct +{ + t_object x_obj; + t_outlet *x_outlet0; + t_float x_min; + t_float x_max; + t_float x_offset; + t_float x_scale; +} t_pdp_ut_addscaleclip; + + +static void pdp_ut_addscaleclip_float(t_pdp_ut_addscaleclip *x, t_floatarg f) +{ + f += x->x_offset; + f *= x->x_scale; + f = (f < x->x_min) ? x->x_min : f; + f = (f > x->x_max) ? x->x_max : f; + outlet_float(x->x_outlet0, f); +} + +static void pdp_ut_addscaleclip_free(t_pdp_ut_addscaleclip *x){} + +void *pdp_ut_addscaleclip_new(t_floatarg offset, t_floatarg scale, t_floatarg min, t_floatarg max) +{ + t_pdp_ut_addscaleclip *x = (t_pdp_ut_addscaleclip *)pd_new(pdp_ut_addscaleclip_class); + x->x_outlet0 = outlet_new(&x->x_obj, &s_float); + x->x_offset = offset; + x->x_scale = scale; + x->x_min = min; + x->x_max = max; + return (void *)x; +} + +void pdp_ut_addscaleclip_setup(void) +{ + pdp_ut_addscaleclip_class = class_new(gensym("pdp_ut_addscaleclip"), (t_newmethod)pdp_ut_addscaleclip_new, + (t_method)pdp_ut_addscaleclip_free, sizeof(t_pdp_ut_addscaleclip), 0, + A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL); + class_addfloat(pdp_ut_addscaleclip_class, pdp_ut_addscaleclip_float); +} + + +/* pdp_ut_logmap does a logarithmic parameter mapping [0->1] x -> min(max/min)^x max an add, scale, clip operation */ +/* pdp_ut_logmap_comp does x -> min(max/min)^(1-x) */ +/* pdp_ut_linmap dos x -> min + (max - min * x */ + +t_class *pdp_ut_linmap_class; +t_class *pdp_ut_logmap_class; +t_class *pdp_ut_logmap_comp_class; + +typedef struct pdp_ut_map_struct +{ + t_object x_obj; + t_outlet *x_outlet0; + t_float x_min; + t_float x_max; +} t_pdp_ut_map; + + +static void pdp_ut_logmap_float(t_pdp_ut_map *x, t_floatarg f) +{ + f = (f < 0.0f) ? 0.0f : f; + f = (f > 1.0f) ? 1.0f : f; + + f = x->x_min * pow((x->x_max / x->x_min), f); + + outlet_float(x->x_outlet0, f); +} + +static void pdp_ut_linmap_float(t_pdp_ut_map *x, t_floatarg f) +{ + f = (f < 0.0f) ? 0.0f : f; + f = (f > 1.0f) ? 1.0f : f; + + f = x->x_min + ((x->x_max - x->x_min) * f); + + outlet_float(x->x_outlet0, f); +} + +static void pdp_ut_logmap_comp_float(t_pdp_ut_map *x, t_floatarg f) +{ + f = (f < 0.0f) ? 0.0f : f; + f = (f > 1.0f) ? 1.0f : f; + + f = x->x_min * pow((x->x_max / x->x_min), (1.0f - f)); + + outlet_float(x->x_outlet0, f); +} + +static void pdp_ut_map_free(t_pdp_ut_map *x){} + + +void pdp_ut_map_init(t_pdp_ut_map *x, t_floatarg min, t_floatarg max) +{ + x->x_outlet0 = outlet_new(&x->x_obj, &s_float); + x->x_min = min; + x->x_max = max; +} + +void *pdp_ut_logmap_new(t_floatarg min, t_floatarg max) +{ + t_pdp_ut_map *x = (t_pdp_ut_map *)pd_new(pdp_ut_logmap_class); + pdp_ut_map_init(x, min, max); + return (void *)x; +} + +void *pdp_ut_linmap_new(t_floatarg min, t_floatarg max) +{ + t_pdp_ut_map *x = (t_pdp_ut_map *)pd_new(pdp_ut_linmap_class); + pdp_ut_map_init(x, min, max); + return (void *)x; +} + +void *pdp_ut_logmap_comp_new(t_floatarg min, t_floatarg max) +{ + t_pdp_ut_map *x = (t_pdp_ut_map *)pd_new(pdp_ut_logmap_comp_class); + pdp_ut_map_init(x, min, max); + return (void *)x; +} + +void pdp_ut_logmap_setup(void) +{ + pdp_ut_logmap_class = class_new(gensym("pdp_ut_logmap"), (t_newmethod)pdp_ut_logmap_new, + (t_method)pdp_ut_map_free, sizeof(t_pdp_ut_map), 0, + A_FLOAT, A_FLOAT, A_NULL); + class_addfloat(pdp_ut_logmap_class, pdp_ut_logmap_float); +} + +void pdp_ut_logmap_comp_setup(void) +{ + pdp_ut_logmap_comp_class = class_new(gensym("pdp_ut_logmap_comp"), (t_newmethod)pdp_ut_logmap_comp_new, + (t_method)pdp_ut_map_free, sizeof(t_pdp_ut_map), 0, + A_FLOAT, A_FLOAT, A_NULL); + class_addfloat(pdp_ut_logmap_comp_class, pdp_ut_logmap_comp_float); +} + +void pdp_ut_linmap_setup(void) +{ + pdp_ut_linmap_class = class_new(gensym("pdp_ut_linmap"), (t_newmethod)pdp_ut_linmap_new, + (t_method)pdp_ut_map_free, sizeof(t_pdp_ut_map), 0, + A_FLOAT, A_FLOAT, A_NULL); + class_addfloat(pdp_ut_linmap_class, pdp_ut_linmap_float); +} + + + +t_class *pdp_ut_rgb2ycrcb_class; + +typedef struct pdp_ut_rgb2ycrcb +{ + t_object x_obj; + t_outlet *x_outlet_luma; + t_outlet *x_outlet_chroma_red; + t_outlet *x_outlet_chroma_blue; + + t_float x_red, x_green, x_blue; + +} t_pdp_ut_rgb2ycrcb; + + +static void pdp_ut_rgb2ycrcb_bang (t_pdp_ut_rgb2ycrcb* x) +{ + + float luma = 0.299f * x->x_red + 0.587f * x->x_green + 0.114f * x->x_blue; + float chroma_red = (x->x_red - luma) * 0.713f; + float chroma_blue = (x->x_blue - luma) * 0.565f; + + outlet_float(x->x_outlet_chroma_blue, chroma_blue); + outlet_float(x->x_outlet_chroma_red, chroma_red); + outlet_float(x->x_outlet_luma, luma); + +} + + +static void pdp_ut_rgb2ycrcb_red (t_pdp_ut_rgb2ycrcb* x, t_floatarg f) {x->x_red = f; pdp_ut_rgb2ycrcb_bang(x);} +static void pdp_ut_rgb2ycrcb_green (t_pdp_ut_rgb2ycrcb* x, t_floatarg f) {x->x_green = f; pdp_ut_rgb2ycrcb_bang(x);} +static void pdp_ut_rgb2ycrcb_blue (t_pdp_ut_rgb2ycrcb* x, t_floatarg f) {x->x_blue = f; pdp_ut_rgb2ycrcb_bang(x);} + + + +static void pdp_ut_rgb2ycrcb_free (t_pdp_ut_rgb2ycrcb* x) {} +static void* pdp_ut_rgb2ycrcb_new(void) +{ + t_pdp_ut_rgb2ycrcb *x = (t_pdp_ut_rgb2ycrcb *)pd_new(pdp_ut_rgb2ycrcb_class); + + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("green")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("blue")); + + x->x_outlet_luma = outlet_new(&x->x_obj, &s_float); + x->x_outlet_chroma_red = outlet_new(&x->x_obj, &s_float); + x->x_outlet_chroma_blue = outlet_new(&x->x_obj, &s_float); + + x->x_red = 0.0f; + x->x_green = 0.0f; + x->x_blue = 0.0f; + + + return (void *)x; +} + +void pdp_ut_rgb2ycrcb_setup(void) +{ + pdp_ut_rgb2ycrcb_class = class_new(gensym("pdp_ut_rgb2ycrcb"), (t_newmethod)pdp_ut_rgb2ycrcb_new, + (t_method)pdp_ut_rgb2ycrcb_free, sizeof(t_pdp_ut_rgb2ycrcb), 0, A_NULL); + class_addfloat(pdp_ut_rgb2ycrcb_class, pdp_ut_rgb2ycrcb_red); + class_addmethod(pdp_ut_rgb2ycrcb_class, (t_method)pdp_ut_rgb2ycrcb_green, gensym("green"), A_FLOAT, A_NULL); + class_addmethod(pdp_ut_rgb2ycrcb_class, (t_method)pdp_ut_rgb2ycrcb_blue, gensym("blue"), A_FLOAT, A_NULL); +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + +void pdp_ut_setup(void) +{ + pdp_ut_addscaleclip_setup(); + pdp_ut_logmap_setup(); + pdp_ut_logmap_comp_setup(); + pdp_ut_linmap_setup(); + pdp_ut_rgb2ycrcb_setup(); +} + + +#ifdef __cplusplus +} +#endif diff --git a/scaf/COPYING b/scaf/COPYING new file mode 100644 index 0000000..7f87ef8 --- /dev/null +++ b/scaf/COPYING @@ -0,0 +1,340 @@ + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR PDP.LICENSE, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/scaf/Makefile b/scaf/Makefile new file mode 100644 index 0000000..d9af670 --- /dev/null +++ b/scaf/Makefile @@ -0,0 +1,43 @@ +include Makefile.config + +all: pdp_scaf.pd_linux + +pdp_scaf_all: + make -C include + make -C compiler + make -C rules + make -C pdp + +clean: + rm -f *~ + rm -f pdp_scaf.pd_linux + make -C include clean + make -C compiler clean + make -C rules clean + make -C pdp clean + +mrproper: clean + rm -rf configure + rm -rf config.status + rm -rf config.log + rm -rf autom4te.cache + #this needs to stay in + #rm -rf Makefile.config + +pdp_scaf.pd_linux: pdp_scaf_all + rm -f pdp_scaf.pd_linux + gcc -export_dynamic -shared -o pdp_scaf.pd_linux pdp/*.o $(PDP_CA_LIBS) + +install: all + install -d $(prefix)/lib/scaf + install -m 755 compiler/scafc $(prefix)/bin || echo failed + install -m 755 compiler/scafc.pl $(prefix)/lib/scaf || echo failed + install -m 644 compiler/kernel.scaf $(prefix)/lib/scaf || echo failed + install -m 644 compiler/scafmacro.s $(prefix)/lib/scaf || echo failed + install -m 644 compiler/optim.rules $(prefix)/lib/scaf || echo failed + install -m 755 rules/carules.scafo $(prefix)/lib/scaf/default.scafo || echo failed + #Check if pd is installed in $(prefix)/lib/pd. + #If this fails the pdp_scaf lib and the docs won't be installed. + test -d $(prefix)/lib/pd + install -m 755 pdp_scaf.pd_linux $(prefix)/lib/pd/externs + install -m 644 doc/*.pd $(prefix)/lib/pd/doc/5.reference diff --git a/scaf/Makefile.config b/scaf/Makefile.config new file mode 100644 index 0000000..4faea70 --- /dev/null +++ b/scaf/Makefile.config @@ -0,0 +1,30 @@ +# build flags + +# define the include paths here if configure can't find them +# PDP_CFLAGS=-I/somehere/pdp/include +# PD_CFLAGS=-I/somewhere/pd/src + + +prefix=/usr/local +PDP_CA_INCLUDE = -I/home/tom/pd/packet/include -I/home/tom/pd/packet/scaf/include +PDP_CA_LIBS = -ldl -lm +DEFAULT_RULES_LIB = /usr/local/lib/scaf/default.scafo +PDP_CA_AFLAGS = +#--gstabs +PDP_CA_CFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer -ffast-math \ + -Wall -W -Wstrict-prototypes -Werror \ + -Wno-unused -Wno-parentheses -Wno-switch -g $(PDP_CFLAGS) $(PD_CFLAGS) \ + -DPDP_CA_RULES_LIB=\"$(DEFAULT_RULES_LIB)\" +# -Wshadow + +# compiler and assembler +#CC = gcc-3.2 +#CC = gcc +#AS = as + +# build rules + +.c.o: + $(CC) $(PDP_CA_CFLAGS) $(PDP_CA_INCLUDE) $(PDP_CA_DEFS) -o $*.o -c $*.c +.s.o: + $(AS) -o $*.o $*.s $(PDP_CA_AFLAGS) diff --git a/scaf/Makefile.config.in b/scaf/Makefile.config.in new file mode 100644 index 0000000..12927d3 --- /dev/null +++ b/scaf/Makefile.config.in @@ -0,0 +1,30 @@ +# build flags + +# define the include paths here if configure can't find them +# PDP_CFLAGS=-I/somehere/pdp/include +# PD_CFLAGS=-I/somewhere/pd/src + + +prefix=@prefix@ +PDP_CA_INCLUDE = @CPPFLAGS@ +PDP_CA_LIBS = @LIBS@ +DEFAULT_RULES_LIB = @DEFAULT_RULES_LIB@ +PDP_CA_AFLAGS = +#--gstabs +PDP_CA_CFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer -ffast-math \ + -Wall -W -Wstrict-prototypes -Werror \ + -Wno-unused -Wno-parentheses -Wno-switch -g $(PDP_CFLAGS) $(PD_CFLAGS) \ + -DPDP_CA_RULES_LIB=\"$(DEFAULT_RULES_LIB)\" +# -Wshadow + +# compiler and assembler +#CC = gcc-3.2 +#CC = gcc +#AS = as + +# build rules + +.c.o: + $(CC) $(PDP_CA_CFLAGS) $(PDP_CA_INCLUDE) $(PDP_CA_DEFS) -o $*.o -c $*.c +.s.o: + $(AS) -o $*.o $*.s $(PDP_CA_AFLAGS) diff --git a/scaf/README b/scaf/README new file mode 100644 index 0000000..e71d1c9 --- /dev/null +++ b/scaf/README @@ -0,0 +1,92 @@ +PDP_SCAF for pdp v0.7 +Cellular Automata modules for PDP + +Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + +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. + +The GNU Public Licence can be found in the file COPYING + + +------------------------------------------------------------------ + +This is a pdp extension lib that contains modules for cellular +automata built on a (very) minimal forth-like virtual system +(scaf - simple cellular automaton forth) to define update rules. a +compiler is included to produce scafo object code that can be +dynamically loaded into the pdp_ca module. so it is possible to +add/change rules without restarting pd (note however you need to close +all lib files before the dynamic loader reloads the lib). see +scaf/README for details. + + +pdp_ca2image and pdp_image2ca are included for conversion between +CA packets and image packets. (pdp_ca2image produces greyscale +images) + +Have a look at the patches in test/ for some crude docs. The file +README.scaf contains some more info on the internals. + + +Requirements: + +* pd +* pdp +* linux +* perl for the forth compiler +* an intel/amd processor that supports MMX + + +Building: + +./configure +make +make install + +If you don't have both libraries in the same dir and want to keep +it that way, hardcode the paths in Makefile.config.in and run +configure. You need to do "make install" to install the scaf compiler +"scafc" and the default ruleset. This is to be able to load plain +(text) rule files and have the default rules loaded when you create +a pdp_ca object. + +Using: + +add "-lib <SCAF_DIR>/pdp_scaf" to the pd command line after the +"-lib <PDP_DIR>/pdp" part. + + + +launch pd with the options -lib $PDP_DIR/pdp -path $PDP_DIR/abstractions + +Directory structure: + +include/ header files +pdp/ pdp external code +compiler/ forth system code +test/ some test patches (cryptic doc) +rules/ ca rule libraries + + + +Please let me know if you discover a bug or think something doesn't work +right. Code, documentation or example patches are more than welcome of +course. + +Have Fun, + +Tom + +last modified: 2003/01/12 diff --git a/scaf/README.scaf b/scaf/README.scaf new file mode 100644 index 0000000..0035899 --- /dev/null +++ b/scaf/README.scaf @@ -0,0 +1,98 @@ +SCAF - simple cellular automaton forth + +scaf is a virtual machine / forth environment for binary arithmic +tailored to 2D 1 cell neighbourhood cellular automata. + +scaf is a compiled language. programs run inside a "feeder" +(sort of operating system if you want) + +the feeder is responsable for loading/storing CA cells +from/to memory. data in memory is organized as a scanline +encoded toroidial bitplane (lsb = left). to simplify the feeder +and the stack machine, the top left corner of the rectangular grid +of pixels will shift down every processing step. this enables +to keep a cell neighbourhood in a couple of registers. + +the stack machine has the following architecture: +CA stack: (%esi), TOS: %mm0 (32x2 cells. lsb = top left) +CA horizon: (%edi) (64x4 cells. (%edi) = top row. lsb = left) + +scratch register: %mm1, %mm2 +bitmask register: %mm3 = 0xffffffffffffffff + +4 bit counter: %mm4-%mm7 + +the stack size / organization is not known to the stack machine. +it can be thought of as operating on a 3x3 cell neightbourhood. +the only purpose of the forth program is to determine the CA local update rule. + +the machine is supposed to be very minimal. no looping control. +no adressing modes. no conditional code. so recursion is not allowed +(no way to stop it) there are 9 words to load the cell neigbourhood +on the stack. the rest is just logic and stack manips. + +the counter can be used for counting neighbourhood cells, like in the +game of life. the zero test and sign bit can be used for comparisons. +there are kernel words for loading constants into the counter register, +and for communication between stack and register. + +the horizon is limited to 3x3, however it can be easily extended to +32x3. extending it further than that would require a redesign of the +forth + feeder. + + +HOW TO CREATE NEW CA RULES + +edit scaf/modules/carules.scaf or create your own source lib and add +the name to the scaf/modules/Makefile. type make in scaf/modules +to compile. if you get error messages from the assembler saying things +like + + Error: no such instruction: `xxx' + + or + Error: invalid character '_' in mnemonic + +this means there are undefined words in your source file. since not +all characters are allowed in an asm file, the offending characters are +converted to _SOMETHINGELSE_ + +if you are stuck somewhere, just look at the output of scaf.pl on +your .scaf file to determine where the problem is. + +words that can be accessed from inside pdp_ca have to start with the +prefix rule_ and have to leave a single item on the data stack (the return +value) other rules can have all the stack effect you want, but for safety +reasons they can't be accessed from within pdp_ca. + + + +FORTH SYSTEM CODE + +the forth system is made up of the following files: + +kernel.scaf: a collection of forth kernel words +scafmacro.s: a set of asm macro definitions used in kernel.scaf +optim.rules: some substitution rules to eliminate redundant + stack manipulations + +scaf.pl: the compiler + +scaf.pl is run like this: + +scaf.pl -Isystemdir source.scaf + +if the -I switch is left out, the current directory is searched +for the system files. the compiler produces an assembler source +that includes scafmacro.s on standard output. + +the code it produces is relatively fast. it only uses and/or/xor +and shift mmx instructions. it's not optimal use of silicon but +it's pretty fast given what's possible. the feeder routine could +be improved though. + +porting to another platform would require a rewrite of scafmacro.s +the rest can be reused. if the target machine has 64 bit registers +(or if you can emulate this one using more registers) porting is +relatively easy. for larger registers a small change needs to +be made to the feeder routine in pdp_ca.c diff --git a/scaf/TODO b/scaf/TODO new file mode 100644 index 0000000..bbeebec --- /dev/null +++ b/scaf/TODO @@ -0,0 +1,3 @@ +* add decimating to pdp_ca2image +* clean up library +* add translation option to pdp_ca (modify so horizontal shifts by 1 are possible) diff --git a/scaf/compiler/Makefile b/scaf/compiler/Makefile new file mode 100644 index 0000000..16e82cd --- /dev/null +++ b/scaf/compiler/Makefile @@ -0,0 +1,6 @@ +all: + +clean: + rm -f *~ + rm -f *.o + diff --git a/scaf/compiler/kernel.scaf b/scaf/compiler/kernel.scaf new file mode 100644 index 0000000..0bc2788 --- /dev/null +++ b/scaf/compiler/kernel.scaf @@ -0,0 +1,130 @@ +( Pure Data Packet - scaforth kernel. ) +( Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> ) +( ) +( 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 file contains the inline words in the scaforth kernel. ) +( when a file is compiled to asm, it will consist of word ) +( definition asm routines, macros and jmp call ret instructions. ) +( ) +( all words in this file are defined in terms of asm macros ) +( defined in scafmacros.s ) + + + +( stack manip words ) + +: over dup dropover ; + +( neighbourhood cell fetch words ) + +: @-+ dup dropldTL ; +: @0+ dup dropldTM ; +: @++ dup dropldTR ; +: @-0 dup dropldML ; +: @00 dup dropldMM ; +: @+0 dup dropldMR ; +: @-- dup dropldBL ; +: @0- dup dropldBM ; +: @+- dup dropldBR ; + +( boolean logic ) + +: or overor nip ; +: xor overxor nip ; +: and overand nip ; + +( binary constant loading ) + +: 1 dup dropone ; +: 0 dup dropzero ; + +( 4,3,2,1 bit add stack to register, leave carry on stack ) + +: ++++ adb0 adb1 adb2 adb3 ; +: +++ adb0 adb1 adb2 ; +: ++ adb0 adb1 ; +: + adb0 ; + +( 4,3,2 bit shifted 1 add ) + +: ++++<<1 adb1 adb2 adb3 ; +: +++<<1 adb1 adb2 ; +: ++<<1 adb1 ; + +( 4,3 bit shifted 2 add ) + +: ++++<<2 adb2 adb3 ; +: +++<<2 adb2 ; + +( 4 bit shifted 3 add ) + +: ++++<<3 adb3 ; + +( 4 bit accumulator access ) + +: !a0 dupsta0 drop ; +: !a1 dupsta1 drop ; +: !a2 dupsta2 drop ; +: !a3 dupsta3 drop ; + +: @a0 dup droplda0 ; +: @a1 dup droplda1 ; +: @a2 dup droplda2 ; +: @a3 dup droplda3 ; + +( 4,3,2,1 bit accumulator zero tests ) + +: ?anz dup dropisnonzero4 ; +: ?anz4 dup dropisnonzero4 ; +: ?anz3 dup dropisnonzero3 ; +: ?anz2 dup dropisnonzero2 ; +: ?anz1 dup dropisnonzero1 ; + +( load constants into accumulator ) + +: a0 a0000 ; +: a-0 a0000 ; +: a+0 a0000 ; +: a+1 a0001 ; +: a+2 a0010 ; +: a+3 a0011 ; +: a+4 a0100 ; +: a+5 a0101 ; +: a+6 a0110 ; +: a+7 a0111 ; + +: a+8 a1000 ; +: a+9 a1001 ; +: a+10 a1010 ; +: a+11 a1011 ; +: a+12 a1100 ; +: a+13 a1101 ; +: a+14 a1110 ; +: a+15 a1111 ; + +: a-8 a1000 ; +: a-7 a1001 ; +: a-6 a1010 ; +: a-5 a1011 ; +: a-4 a1100 ; +: a-3 a1101 ; +: a-2 a1110 ; +: a-1 a1111 ; + diff --git a/scaf/compiler/optim.rules b/scaf/compiler/optim.rules new file mode 100644 index 0000000..282caf4 --- /dev/null +++ b/scaf/compiler/optim.rules @@ -0,0 +1,74 @@ +# Pure Data Packet - scaf optimization rules. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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 file contains scaf source optimization rules for scaf compiler +# applied after kernel word inlining and before compilation to asm + +# one rule that's not in here, and is the responsability for the +# final compilation step: "word ;" is "jmp word" instead of "call word ret" + +# TODO: think about order! + +# no discrimination between pre inline and post inline optimization ops yet + +# pre inline optimizations + +"over xor" -> "overxor" +"over and" -> "overand" +"over or" -> "overor" + +"drop 1" -> "dropone" +"drop 0" -> "dropzero" +"over add" -> "overadd" +"over addc" -> "overaddc" + +"dup !a0" -> "dupsta0" +"dup !a1" -> "dupsta1" +"dup !a2" -> "dupsta2" +"dup !a3" -> "dupsta3" + +"drop @a0" -> "droplda0" +"drop @a1" -> "droplda1" +"drop @a2" -> "droplda2" +"drop @a3" -> "droplda3" + +"drop ?anz" -> "dropisnonzero4" +"drop ?anz4" -> "dropisnonzero4" +"drop ?anz3" -> "dropisnonzero3" +"drop ?anz2" -> "dropisnonzero2" +"drop ?anz1" -> "dropisnonzero1" + +"drop @-+" -> "dropldTL" +"drop @0+" -> "dropldTM" +"drop @++" -> "dropldTR" +"drop @-0" -> "dropldML" +"drop @00" -> "dropldMM" +"drop @+0" -> "dropldMR" +"drop @--" -> "dropldBL" +"drop @0-" -> "dropldBM" +"drop @+-" -> "dropldBR" + + +# post inline optimizations + +"dup drop" -> "" +"swap drop" -> "nip" +"dup swap" -> "dup" +"drop dup" -> "dropdup" +"drop over" -> "dropover" +"nip dup" -> "nipdup" diff --git a/scaf/compiler/scafc b/scaf/compiler/scafc new file mode 100755 index 0000000..ae800e5 --- /dev/null +++ b/scaf/compiler/scafc @@ -0,0 +1,44 @@ +#!/bin/sh +#scaf->scafo compiler + +if test "xx$1" == "xx" +then + echo + echo "scaf rules compiler" + echo "usage:" + echo " scafc source [dest]" + echo + exit 0 +fi + +if test "xx$2" == "xx" +then + DEST=$1o +else + DEST=$2 +fi + +if ! test -f $1 +then + echo "source module $1 not found." + exit 1 +fi + +SCAFDIR=`dirname $0` +if ! test -f $SCAFDIR/scafc.pl; +then + SCAFDIR=`dirname $SCAFDIR` + SCAFDIR="$SCAFDIR/lib/scaf" + if ! test -f $SCAFDIR/scafc.pl + then + echo "scaf library not found in $SCAFDIR" + exit 1 + fi +fi + +TMP_S=`tempfile -s .s` +$SCAFDIR/scafc.pl -I$SCAFDIR $1 > $TMP_S \ +&& gcc -export_dynamic -shared -o $DEST $TMP_S \ +&& strip --strip-unneeded $DEST \ +&& rm $TMP_S \ +|| exit 1 diff --git a/scaf/compiler/scafc.pl b/scaf/compiler/scafc.pl new file mode 100755 index 0000000..ee6b969 --- /dev/null +++ b/scaf/compiler/scafc.pl @@ -0,0 +1,269 @@ +#!/usr/bin/perl + +# Pure Data Packet - scafc: scaf compiler. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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. +# + +# set this if you want to enable/disable optimizing + +$optimize = 1; + + +# this parses a single scaf line +# it is not very intelligent. only looks for 1 def on a line +# todo: change later so it can read multiple lines + + +sub remove_illegal_characters { + my $line = shift; + $$line =~ s/\+/_PLUS_/g; + $$line =~ s/-/_MINUS_/g; + $$line =~ s/\@/_AT_/g; + $$line =~ s/:/_COLON_/g; + $$line =~ s/\?/_QMARK_/g; + $$line =~ s/<</_SHIFT_/g; + $$line =~ s/</_ST_/g; + $$line =~ s/>/_GT_/g; + $$line =~ s/=/_EQ_/g; + $$line =~ s/\(/_OPEN_/g; + $$line =~ s/\)/_CLOSE_/g; +} + +sub parse_scaf_line { + my $word, $def, $sub; + shift; + + # this transforms the source into a parsed assembly like form + # a word label: "<word>:<ret>" + # a word definition line "<tab><word><ret>" + # last def = <ret><ret> + + # dont process if line doesn't have a def + + # first remove comments + s/\(\s+(\S+\s+)*?\)//g; + + if (m/:\s+/){ + + # separate word and definition + m/:\s+(\S+)\s+(.*)/; + $word = $1; + $def = $2; + + # remove illegal characters; + remove_illegal_characters \$word; + remove_illegal_characters \$def; + + # format definition in asm style + $def =~ s/(\S+)(\s*)/\t$1\n/g; + + # replace ; by r + $def =~ s/\s+;\s*/\n\tr\n/; + + # put word: def into one string + $sub = "$word:\n$def\n"; + + # debug + #$sub =~ s/\t/<tab>/g; + #$sub =~ s/\n/<ret>\n/g; + #print "$sub"; + + return $sub; + + } + +}; + + + +# load and parse scaf source file +sub load_source { + my $filename = shift; + open(SOURCE, $filename) or die "Can't locate source module $filename\n"; + my @parsedsource; + while (<SOURCE>){ + my $sub = parse_scaf_line $_; + if ($sub) { + push @parsedsource, ($sub); + } + + } + close(SOURCE); + return @parsedsource; + +} + +# this routine parses the optimization rules +sub load_optim { + my $filename = shift; + open(OPTIM, $filename) or die "Can't locate optimization rule file $filename\n"; + my @parsedoptim; + while (<OPTIM>){ + unless (m/\A\#/){ + + if (m/\"\s*(.*?)\s*\".*?\"\s*(.*?)\s*\"/) + { + my $source = $1; + my $dest = $2; + + $source =~ s/\s+/\n\t/; + $dest =~ s/\s+/\n\t/; + $source = "\t$source\n"; + $dest = "\t$dest\n"; + + remove_illegal_characters \$source; + remove_illegal_characters \$dest; + + push @parsedoptim, ("$source:$dest"); + } + } + } + close(OPTIM); + + return @parsedoptim; + + +} + + + +# inline one parsed source's definitions into another parsed source's +sub inline_defs { + my $dest = shift; + my $source = shift; + + #print @$dest; + #print @$source; + + + # loop over file with inline defs + foreach (@$source) { + #print "<SUB>$_</SUB>\n"; + m/(\S+):\n(.*)\tr\n/s; + + my $def = "\t$1\n"; + my $body = $2; + + #print "<DEF>$def</DEF>\n"; + #print "<BODY>$body</BODY>\n"; + + foreach (@$dest) { + s/$def/$body/g; + } + + } + +} + +# this changes <WORD> to c <WORD> or j <WORD> all defined words +# the undefined words are supposed to be asm macros +sub call_defs { + my $dest = shift; + + foreach (@$dest){ + m/(\S+):\n/s; + my $word = $1; + foreach (@$dest){ + s/\t$word\n\tr\n/\tj $word\n/sg; + s/\t$word\n/\tc $word\n/sg; + } + } +} + +# substitue word sequences in dest using optim table +sub subst_optim { + my $dest = shift; + my $optim = shift; + foreach (@$optim){ + m/(.*?):(.*)/s; + my $key = $1; + my $subst = $2; + + foreach (@$dest){ + s/$key/$subst/sg; + } + } +} + +# add directives to produce global symbols +# global symbols need to start with carule_ +sub global_syms { + my $source = shift; + foreach (@$source){ + s/rule_(\S+):\n/.globl\trule_$1\n.type\trule_$1,\@function\nrule_$1:\n/sg; + } +} + +# create an array with names for bookkeeping +sub name_array { + my @namearray; + my $source = shift; + push @namearray, (".globl rulenames\nrulenames:\n"); + foreach (@$source){ + if (m/rule_(\S+):/s){ + push @namearray, (".asciz\t\"$1\"\n"); + } + } + push @namearray, (".byte\t0\n"); + return @namearray; + +} + +# main program body + +$dir="."; + +$source = "-"; + + +# parse command line +foreach (@ARGV){ + if (m/-I(.*)/) { + $dir = $1; + } + else { + $source = $_; + } +} + +$kernel = "$dir/kernel.scaf"; +$macro = "$dir/scafmacro.s"; +$rules = "$dir/optim.rules"; + + + +# load files +@psource = load_source $source; +@pkernel = load_source $kernel; +@poptim = load_optim $rules; + + +# substitute kernel defs in source +if ($optimize) {subst_optim \@psource, \@poptim;} +inline_defs \@psource, \@pkernel; + +if ($optimize) {subst_optim \@psource, \@poptim;} + +call_defs \@psource; +global_syms \@psource; +@pnames = name_array \@psource; + +# print out asm file +print ".include \"$macro\"\n\n"; +print @psource; +print @pnames; + diff --git a/scaf/compiler/scafmacro.s b/scaf/compiler/scafmacro.s new file mode 100644 index 0000000..04e6537 --- /dev/null +++ b/scaf/compiler/scafmacro.s @@ -0,0 +1,487 @@ + # Pure Data Packet - scaf assembler macros. + # Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + # + # 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 file contains pure asm macros. it is to be included before assembly + # after scaforth.pl has processed the .scaf file + + # *************************** JMP CALL RET ************************************** + # j c r + + .macro j address + jmp \address + .endm + + .macro c address + call \address + .endm + + .macro r + ret + .endm + + + # *************************** CA CELL ACCESS MACROS ***************************** + # dropldTL - dropldBR + + # shift / load rectangle macros: + + # shift rectangle horizontal + # result is in reg1 + .macro shift reg1 reg2 count + psllq $(16-\count), \reg1 + psrlq $(16+\count), \reg2 + psrlq $32, \reg1 + psllq $32, \reg2 + por \reg2, \reg1 + .endm + + .macro ldtop reg1 reg2 + movq (%edi), \reg1 + movq 8(%edi), \reg2 + .endm + + .macro ldcenter reg1 reg2 + movq 8(%edi), \reg1 + movq 16(%edi), \reg2 + .endm + + .macro ldbottom reg1 reg2 + movq 16(%edi), \reg1 + movq 24(%edi), \reg2 + .endm + + + # dropld from top row + + # dropld the top left square + .macro dropldTL + ldtop %mm0, %mm1 + shift %mm0, %mm1, -1 + .endm + + # dropld the top mid square + .macro dropldTM + ldtop %mm0, %mm1 + shift %mm0, %mm1, 0 + .endm + + # dropld the top right square + .macro dropldTR + ldtop %mm0, %mm1 + shift %mm0, %mm1, 1 + .endm + + + + # dropld from center row + + # dropld the mid left square + .macro dropldML + ldcenter %mm0, %mm1 + shift %mm0, %mm1, -1 + .endm + + # dropld the mid mid square + .macro dropldMM + ldcenter %mm0, %mm1 + shift %mm0, %mm1, 0 + .endm + + # dropld the mid right square + .macro dropldMR + ldcenter %mm0, %mm1 + shift %mm0, %mm1, 1 + .endm + + + + + + # dropld from bottom row + + # dropld the bottom left square + .macro dropldBL + ldbottom %mm0, %mm1 + shift %mm0, %mm1, -1 + .endm + + # dropld the bottom mid square + .macro dropldBM + ldbottom %mm0, %mm1 + shift %mm0, %mm1, 0 + .endm + + # dropld the bottom right square + .macro dropldBR + ldbottom %mm0, %mm1 + shift %mm0, %mm1, 1 + .endm + + + + # *************************** CA STACK MANIP MACROS ***************************** + # these are the only asm macros that have a stack effect other than + # just replacing the TOS + # + # dup drop dropdup swap nip dropover + + .macro dup + lea -8(%esi), %esi + movq %mm0, (%esi) + .endm + + .macro drop + movq (%esi), %mm0 + lea 8(%esi), %esi + .endm + + .macro dropdup + movq (%esi), %mm0 + .endm + + .macro nipdup + movq %mm0, (%esi) + .endm + + .macro swap + movq (%esi), %mm1 + movq %mm0, (%esi) + movq %mm1, %mm0 + .endm + + .macro nip + lea 8(%esi), %esi + .endm + + .macro dropover + movq 8(%esi), %mm0 + .endm + + + # *************************** CA BOOLEAN LOGIC MACROS ***************************** + # overxor overand overor not + + .macro overxor + pxor (%esi), %mm0 + .endm + + .macro overand + pand (%esi), %mm0 + .endm + + .macro overor + por (%esi), %mm0 + .endm + + .macro not + pxor %mm3, %mm0 + .endm + + + + # *************************** CONSTANTS ***************************** + # dropzero dropone + + .macro dropzero + pxor %mm0, %mm0 + .endm + + .macro dropone + pcmpeqw %mm0, %mm0 + .endm + + + # *************************** 4 BIT REG ACCESS ****************************** + # dupsta0 - dupsta4 droplda0 - droplda4 + # store bit in accumulator + + # bit store + + .macro dupsta0 + movq %mm0, %mm4 + .endm + + .macro dupsta1 + movq %mm0, %mm5 + .endm + + .macro dupsta2 + movq %mm0, %mm6 + .endm + + .macro dupsta3 + movq %mm0, %mm7 + .endm + + # load bit from accumulator + + .macro droplda0 + movq %mm4, %mm0 + .endm + + .macro droplda1 + movq %mm5, %mm0 + .endm + + .macro droplda2 + movq %mm6, %mm0 + .endm + + .macro droplda3 + movq %mm7, %mm0 + .endm + + + # *************************** LOAD 4 BIT CONSTANT IN REG ****************************** + # a0000 - a1111 + + .macro ldbit0 value + .ifeq \value + movq %mm1, %mm4 + .else + movq %mm3, %mm4 + .endif + .endm + + .macro ldbit1 value + .ifeq \value + movq %mm1, %mm5 + .else + movq %mm3, %mm5 + .endif + .endm + + .macro ldbit2 value + .ifeq \value + movq %mm1, %mm6 + .else + movq %mm3, %mm6 + .endif + .endm + + .macro ldbit3 value + .ifeq \value + movq %mm1, %mm7 + .else + movq %mm3, %mm7 + .endif + .endm + + .macro ldbin b3 b2 b1 b0 + pxor %mm1, %mm1 + ldbit0 \b0 + ldbit1 \b1 + ldbit2 \b2 + ldbit3 \b3 + .endm + + .macro a0000 + ldbin 0 0 0 0 + .endm + + .macro a0001 + ldbin 0 0 0 1 + .endm + + .macro a0010 + ldbin 0 0 1 0 + .endm + + .macro a0011 + ldbin 0 0 1 1 + .endm + + .macro a0100 + ldbin 0 1 0 0 + .endm + + .macro a0101 + ldbin 0 1 0 1 + .endm + + .macro a0110 + ldbin 0 1 1 0 + .endm + + .macro a0111 + ldbin 0 1 1 1 + .endm + + .macro a1000 + ldbin 1 0 0 0 + .endm + + .macro a1001 + ldbin 1 0 0 1 + .endm + + .macro a1010 + ldbin 1 0 1 0 + .endm + + .macro a1011 + ldbin 1 0 1 1 + .endm + + .macro a1100 + ldbin 1 1 0 0 + .endm + + .macro a1101 + ldbin 1 1 0 1 + .endm + + .macro a1110 + ldbin 1 1 1 0 + .endm + + .macro a1111 + ldbin 1 1 1 1 + .endm + + + + + # *************************** 4 BIT COUNTER ****************************** + # adds TOS to bit of counter and returns carry in TOS + # + # adb0 - adb3 + + + .macro adb0 + movq %mm4, %mm2 + pxor %mm0, %mm4 + pand %mm2, %mm0 + .endm + + .macro adb1 + movq %mm5, %mm2 + pxor %mm0, %mm5 + pand %mm2, %mm0 + .endm + + .macro adb2 + movq %mm6, %mm2 + pxor %mm0, %mm6 + pand %mm2, %mm0 + .endm + + .macro adb3 + movq %mm7, %mm2 + pxor %mm0, %mm7 + pand %mm2, %mm0 + .endm + + + # *************************** ACCUMULATOR TESTS *************************** + # dropisnonzero4 - dropisnonzero1 + + .macro dropisnonzero4 + movq %mm4, %mm0 + por %mm5, %mm0 + por %mm6, %mm0 + por %mm7, %mm0 + .endm + + .macro dropisnonzero3 + movq %mm4, %mm0 + por %mm5, %mm0 + por %mm6, %mm0 + .endm + + .macro dropisnonzero2 + movq %mm4, %mm0 + por %mm5, %mm0 + .endm + + .macro dropisnonzero1 + movq %mm4, %mm0 + .endm + + + # *************************** REGISTER SHIFT OPERATIONS ********************** + # shift and leave shifted out byte on stack + # rotate trough top of stack + + .macro dropshiftright + movq %mm4, %mm0 + movq %mm5, %mm4 + movq %mm6, %mm5 + movq %mm7, %mm6 + pxor %mm7, %mm7 + .endm + + .macro dropshiftleft + movq %mm7, %mm0 + movq %mm6, %mm7 + movq %mm5, %mm6 + movq %mm4, %mm5 + pxor %mm4, %mm4 + .endm + + .macro dropshiftrighta + movq %mm4, %mm0 + movq %mm5, %mm4 + movq %mm6, %mm5 + movq %mm7, %mm6 + .endm + + .macro rotateright + movq %mm4, %mm1 + movq %mm5, %mm4 + movq %mm6, %mm5 + movq %mm7, %mm6 + movq %mm1, %mm7 + .endm + + .macro rotateleft + movq %mm7, %mm1 + movq %mm6, %mm7 + movq %mm5, %mm6 + movq %mm4, %mm5 + movq %mm1, %mm4 + .endm + + .macro rotaterightstack + movq %mm0, %mm1 + movq %mm4, %mm0 + movq %mm5, %mm4 + movq %mm6, %mm5 + movq %mm7, %mm6 + movq %mm1, %mm7 + .endm + + .macro rotateleftstack + movq %mm0, %mm1 + movq %mm7, %mm0 + movq %mm6, %mm7 + movq %mm5, %mm6 + movq %mm4, %mm5 + movq %mm1, %mm4 + .endm + + # *************************** OTHER REGISTER OPERATIONS ********************** + # anot : complement reg (can be used to implement subtraction) + + .macro anot + pxor %mm3, %mm4 + pxor %mm3, %mm5 + pxor %mm3, %mm6 + pxor %mm3, %mm7 + .endm diff --git a/scaf/configure b/scaf/configure new file mode 100755 index 0000000..9e19e2d --- /dev/null +++ b/scaf/configure @@ -0,0 +1,4124 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.59. +# +# Copyright (C) 2003 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_config_libobj_dir=. +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +ac_unique_file="pdp/pdp_ca_system.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include <stdio.h> +#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#if HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#if STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#else +# if HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#if HAVE_STRINGS_H +# include <strings.h> +#endif +#if HAVE_INTTYPES_H +# include <inttypes.h> +#else +# if HAVE_STDINT_H +# include <stdint.h> +# endif +#endif +#if HAVE_UNISTD_H +# include <unistd.h> +#endif" + +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP PDP_CONFIG DEFAULT_RULES_LIB LIBOBJS LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have + headers in a nonstandard directory <include dir> + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd "$ac_popdir" + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF + +Copyright (C) 2003 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.59. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_sep= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------- ## +## Output files. ## +## ------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h | sort + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5 + (eval $ac_compiler --version </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5 + (eval $ac_compiler -v </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5 + (eval $ac_compiler -V </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std1 is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std1. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include <stdlib.h> +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ctype.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + + +if test $prefix == "NONE"; +then + prefix=/usr/local +fi + +# Extract the first word of "pdp-config", so it can be a program name with args. +set dummy pdp-config; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_path_PDP_CONFIG+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $PDP_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PDP_CONFIG="$PDP_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_PDP_CONFIG="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_path_PDP_CONFIG" && ac_cv_path_PDP_CONFIG=""no"" + ;; +esac +fi +PDP_CONFIG=$ac_cv_path_PDP_CONFIG + +if test -n "$PDP_CONFIG"; then + echo "$as_me:$LINENO: result: $PDP_CONFIG" >&5 +echo "${ECHO_T}$PDP_CONFIG" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + + +echo "$as_me:$LINENO: checking for sin in -lm" >&5 +echo $ECHO_N "checking for sin in -lm... $ECHO_C" >&6 +if test "${ac_cv_lib_m_sin+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char sin (); +int +main () +{ +sin (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_m_sin=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_m_sin=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_m_sin" >&5 +echo "${ECHO_T}$ac_cv_lib_m_sin" >&6 +if test $ac_cv_lib_m_sin = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBM 1 +_ACEOF + + LIBS="-lm $LIBS" + +fi + + +echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dl_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dl_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 +if test $ac_cv_lib_dl_dlopen = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBDL 1 +_ACEOF + + LIBS="-ldl $LIBS" + +else + echo libdl not found. sorry... || exit 1 +fi + + + +TOPSRC=`pwd` +PARENT=`dirname $TOPSRC` + +if ! test $PDP_CONFIG == "no" +then + PDP_CPPFLAGS=`$PDP_CONFIG --cflags` + +elif test -f $PARENT/include/pdp.h +then + PDP_CPPFLAGS="-I$PARENT/include" +fi + +CPPFLAGS="$CPPFLAGS $PDP_CPPFLAGS" +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +if test "${ac_cv_header_m_pd_h+set}" = set; then + echo "$as_me:$LINENO: checking for m_pd.h" >&5 +echo $ECHO_N "checking for m_pd.h... $ECHO_C" >&6 +if test "${ac_cv_header_m_pd_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_m_pd_h" >&5 +echo "${ECHO_T}$ac_cv_header_m_pd_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking m_pd.h usability" >&5 +echo $ECHO_N "checking m_pd.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <m_pd.h> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking m_pd.h presence" >&5 +echo $ECHO_N "checking m_pd.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <m_pd.h> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: m_pd.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: m_pd.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: m_pd.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: m_pd.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: m_pd.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: m_pd.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: m_pd.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: m_pd.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: m_pd.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: m_pd.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: m_pd.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: m_pd.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: m_pd.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: m_pd.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: m_pd.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: m_pd.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------ ## +## Report this to the AC_PACKAGE_NAME lists. ## +## ------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for m_pd.h" >&5 +echo $ECHO_N "checking for m_pd.h... $ECHO_C" >&6 +if test "${ac_cv_header_m_pd_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_m_pd_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_m_pd_h" >&5 +echo "${ECHO_T}$ac_cv_header_m_pd_h" >&6 + +fi +if test $ac_cv_header_m_pd_h = yes; then + : +else + PD_OK=no +fi + + +if test "${ac_cv_header_pdp_h+set}" = set; then + echo "$as_me:$LINENO: checking for pdp.h" >&5 +echo $ECHO_N "checking for pdp.h... $ECHO_C" >&6 +if test "${ac_cv_header_pdp_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_pdp_h" >&5 +echo "${ECHO_T}$ac_cv_header_pdp_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking pdp.h usability" >&5 +echo $ECHO_N "checking pdp.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <pdp.h> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking pdp.h presence" >&5 +echo $ECHO_N "checking pdp.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <pdp.h> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: pdp.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: pdp.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: pdp.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: pdp.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: pdp.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: pdp.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: pdp.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: pdp.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: pdp.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: pdp.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: pdp.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: pdp.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: pdp.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: pdp.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: pdp.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: pdp.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------ ## +## Report this to the AC_PACKAGE_NAME lists. ## +## ------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for pdp.h" >&5 +echo $ECHO_N "checking for pdp.h... $ECHO_C" >&6 +if test "${ac_cv_header_pdp_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_pdp_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_pdp_h" >&5 +echo "${ECHO_T}$ac_cv_header_pdp_h" >&6 + +fi +if test $ac_cv_header_pdp_h = yes; then + : +else + PDP_OK=no +fi + + + +if test PD_OK == "no"; +then + echo "WARNING: m_pd.h not found. Is PD installed? + echo "WARNING: You can ignore this warning if you have set the PD_CFLAGS manually in Makefile.config.in +fi + +if test PDP_OK == "no"; +then + echo "WARNING: pdp.h not found. Is PDP installed? + echo "WARNING: You can ignore this warning if you have set the PDP_CFLAGS manually in Makefile.config.in +fi + +CPPFLAGS="$CPPFLAGS $PDFLAGS $PDPFLAGS -I$TOPSRC/include" + +DEFAULT_RULES_LIB=$prefix/lib/scaf/default.scafo; + + + ac_config_files="$ac_config_files Makefile.config" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then we branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +cat >confdef2opt.sed <<\_ACEOF +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g +t quote +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g +t quote +d +: quote +s,[ `~#$^&*(){}\\|;'"<>?],\\&,g +s,\[,\\&,g +s,\],\\&,g +s,\$,$$,g +p +_ACEOF +# We use echo to avoid assuming a particular line-breaking character. +# The extra dot is to prevent the shell from consuming trailing +# line-breaks from the sub-command output. A line-break within +# single-quotes doesn't work because, if this script is created in a +# platform that uses two characters for line-breaks (e.g., DOS), tr +# would break. +ac_LF_and_DOT=`echo; echo .` +DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'` +rm -f confdef2opt.sed + + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by $as_me, which was +generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Report bugs to <bug-autoconf@gnu.org>." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.59, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2003 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + + + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile.config" ) CONFIG_FILES="$CONFIG_FILES Makefile.config" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@CPP@,$CPP,;t t +s,@EGREP@,$EGREP,;t t +s,@PDP_CONFIG@,$PDP_CONFIG,;t t +s,@DEFAULT_RULES_LIB@,$DEFAULT_RULES_LIB,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/scaf/configure.ac b/scaf/configure.ac new file mode 100644 index 0000000..4b15a18 --- /dev/null +++ b/scaf/configure.ac @@ -0,0 +1,53 @@ +AC_INIT(pdp/pdp_ca_system.c) +AC_PROG_CC +AC_HEADER_STDC + +dnl default install prefix is /usr/local +if test $prefix == "NONE"; +then + prefix=/usr/local +fi + +AC_PATH_PROG(PDP_CONFIG,pdp-config,"no", $PATH) + +AC_CHECK_LIB(m,sin) +AC_CHECK_LIB(dl,dlopen,, echo libdl not found. sorry... || exit 1) + + +TOPSRC=`pwd` +PARENT=`dirname $TOPSRC` + +dnl if pdp-config is found use it to get the cflags +if ! test $PDP_CONFIG == "no" +then + PDP_CPPFLAGS=`$PDP_CONFIG --cflags` + +dnl if not, check in the parent dir (in case we are distributed with the pdp package) +elif test -f $PARENT/include/pdp.h +then + PDP_CPPFLAGS="-I$PARENT/include" +fi + +CPPFLAGS="$CPPFLAGS $PDP_CPPFLAGS" +AC_CHECK_HEADER(m_pd.h,,PD_OK=no) +AC_CHECK_HEADER(pdp.h,,PDP_OK=no) + +if test PD_OK == "no"; +then + echo "WARNING: m_pd.h not found. Is PD installed? + echo "WARNING: You can ignore this warning if you have set the PD_CFLAGS manually in Makefile.config.in +fi + +if test PDP_OK == "no"; +then + echo "WARNING: pdp.h not found. Is PDP installed? + echo "WARNING: You can ignore this warning if you have set the PDP_CFLAGS manually in Makefile.config.in +fi + +CPPFLAGS="$CPPFLAGS $PDFLAGS $PDPFLAGS -I$TOPSRC/include" + +DEFAULT_RULES_LIB=$prefix/lib/scaf/default.scafo; +AC_SUBST(DEFAULT_RULES_LIB) + +AC_CONFIG_FILES(Makefile.config) +AC_OUTPUT diff --git a/scaf/doc/pdp_ca.pd b/scaf/doc/pdp_ca.pd new file mode 100644 index 0000000..64e7e27 --- /dev/null +++ b/scaf/doc/pdp_ca.pd @@ -0,0 +1,78 @@ +#N canvas 62 0 753 664 10; +#X obj 46 613 pdp_ca; +#X obj 45 254 metro 40; +#X msg 45 206 bang; +#X msg 84 206 stop; +#X msg 184 340 random; +#X msg 181 137 rule gameoflife; +#X floatatom 185 586 5 0 0 0 - - -; +#X obj 185 558 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 46 638 pdp_ca2image; +#X msg 181 215 rules; +#X msg 185 434 close; +#X floatatom 96 228 5 0 0 0 - - -; +#X obj 46 662 pdp_xv; +#X floatatom 183 285 5 0 0 0 - - -; +#X msg 183 314 vshift \$1; +#X msg 185 486 2D; +#X msg 185 535 fullscreen1D \$1; +#X obj 185 513 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X text 197 606 1st inlet: active input (bang or ca); +#X text 197 621 2nd inlet: passive input (ca); +#X text 196 638 3rd inlet: nb of iterations; +#X text 307 137 set a rule by name; +#X text 308 206 print rules in library; +#X msg 181 187 ruleindex \$1; +#X text 307 183 set a rule by index; +#X floatatom 181 165 5 0 0 0 - - -; +#X text 313 534 off: compute one line at a time; +#X text 313 548 on: update entire image (all lines); +#X text 313 520 specify how to compute a 1D ca; +#X text 313 464 interpret rules as a 1D ca with (space+time); +#X text 313 493 interpret rules as a 2D ca with (space); +#X msg 185 465 1D; +#X text 314 436 close current library; +#X obj 179 43 openpanel; +#X msg 179 66 open \$1; +#X msg 184 370 dim 64 64; +#X text 314 371 set ca dimensions; +#X obj 179 24 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X text 306 22 open a source rule file or compiled rule library; +#X text 306 38 (when it's a source file \, make sure the "scafc" compiler +is in the system path); +#X msg 340 70 opensrc \$1; +#X msg 446 70 openlib \$1; +#X text 306 72 use; +#X text 419 71 and; +#X text 306 89 to explicitly open source or library; +#X text 314 342 init ca with random noise; +#X text 314 312 vertical shift compensation; +#X text 181 257 bang computes next iteration(s); +#X msg 185 397 dim 512 512; +#X connect 0 0 8 0; +#X connect 1 0 0 0; +#X connect 2 0 1 0; +#X connect 3 0 1 0; +#X connect 4 0 0 0; +#X connect 5 0 0 0; +#X connect 6 0 0 2; +#X connect 7 0 6 0; +#X connect 8 0 12 0; +#X connect 9 0 0 0; +#X connect 10 0 0 0; +#X connect 11 0 1 1; +#X connect 13 0 14 0; +#X connect 14 0 0 0; +#X connect 15 0 0 0; +#X connect 16 0 0 0; +#X connect 17 0 16 0; +#X connect 23 0 0 0; +#X connect 25 0 23 0; +#X connect 33 0 34 0; +#X connect 34 0 0 0; +#X connect 35 0 0 0; +#X connect 37 0 33 0; +#X connect 48 0 0 0; diff --git a/scaf/include/Makefile b/scaf/include/Makefile new file mode 100644 index 0000000..1aba02c --- /dev/null +++ b/scaf/include/Makefile @@ -0,0 +1,6 @@ +current: + + +clean: + rm -f *~ + diff --git a/scaf/include/pdp_ca.h b/scaf/include/pdp_ca.h new file mode 100644 index 0000000..3d77133 --- /dev/null +++ b/scaf/include/pdp_ca.h @@ -0,0 +1,74 @@ +/* + * Cellular Automata Extension Module for pdp - Main header file + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +#ifndef PDP_CA_H +#define PDP_CA_H + +#include "pdp.h" + + + +/* 2D CA DATA PACKET */ +typedef struct +{ + unsigned int encoding; /* CA data format */ + unsigned int width; /* CA width (in 1 bit cells) */ + unsigned int height; /* CA height (in 1 bit cells) */ + unsigned int offset; /* bit offset of upper left corner */ + unsigned int currow; /* current row to compute for 1D CA */ + +} t_ca; + +/* CA encodings */ +#define PDP_CA_STANDARD 1 /* rectangular CA */ + +/* pdp data packet types */ +#define PDP_CA 2 /* 1bit toroidial shifted scanline encoded cellular automaton */ + + +/* all symbols are C-style */ +#ifdef __cplusplus +extern "C" +{ +#endif + +/* constructor */ +int pdp_packet_new_ca(int encoding, int width, int height); + +/* some utility methods for CA */ +int pdp_packet_ca_isvalid(int packet); +int pdp_type_ca2grey(int packet); +int pdp_type_grey2ca(int packet, short int threshold); + +/* returns a pointer to the ca subheader given the pdp header */ +t_ca *pdp_type_ca_info(t_pdp *x); + +/* mmx feeder routine */ +unsigned long long scaf_feeder(void *tos, void *reg, void (*ca_rule)(void), void *env); + + + + + +#ifdef __cplusplus +} +#endif + +#endif //PDP_CA_H diff --git a/scaf/pdp/Makefile b/scaf/pdp/Makefile new file mode 100644 index 0000000..5ec8a0d --- /dev/null +++ b/scaf/pdp/Makefile @@ -0,0 +1,13 @@ +current: all_modules + +include ../Makefile.config + +OBJECTS = pdp_ca.o pdp_ca_system.o scaf_feeder.o + + +all_modules: $(OBJECTS) + +clean: + rm -f *~ + rm -f *.o + diff --git a/scaf/pdp/pdp_ca.c b/scaf/pdp/pdp_ca.c new file mode 100644 index 0000000..3f80a75 --- /dev/null +++ b/scaf/pdp/pdp_ca.c @@ -0,0 +1,919 @@ +/* + * Pure Data Packet module for cellular automata + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include "pdp_ca.h" +#include "pdp_internals.h" +#include <dlfcn.h> +#include <stdio.h> + +t_class *pdp_ca_class; // a cellular automaton processor: single input - single output +//t_class *pdp_ca2_class; // double input - single output +t_class *pdp_ca2image_class; // converter from ca -> grey/yv12 +t_class *pdp_image2ca_class; // converter from grey/yv12 -> ca + + +// *********************** CA CLASS STUFF ********************* + + +// this is defined in the makefile +// #define PDP_CA_RULES_LIB "/path/default.scafo" + +#define PDP_CA_STACKSIZE 256 +#define PDP_CA_MODE_1D 1 +#define PDP_CA_MODE_2D 2 + +typedef struct pdp_ca_data_struct +{ + unsigned int env[2*4]; + unsigned int reg[2*4]; + unsigned int stack[2*PDP_CA_STACKSIZE]; + short int random_seed[4]; +} t_pdp_ca_data; + +typedef struct pdp_ca_struct +{ + t_object x_obj; + t_float x_f; + + t_outlet *x_outlet0; + int x_queue_id; + + /* double buffering data packets */ + int x_packet0; + int x_packet1; + + /* some data on the ca_routine */ + void (*x_ca_routine)(void); + void *x_ca_libhandle; + char *x_ca_rulenames; + int x_ca_nbrules; + char ** x_ca_rulename; + t_symbol *x_lastrule; + + /* nb of iterations */ + int x_iterations; + + /* shift ca on output */ + int x_horshift; + int x_vershift; + + /* operation mode */ + int x_mode; + int x_fullscreen1d; + + /* aligned vector data */ + t_pdp_ca_data *x_data; + + /* output packet type */ + t_symbol *x_packet_type; + +} t_pdp_ca; + + +/* 1D: process from packet0 -> packet0 */ +static void pdp_ca_process_ca_1D(t_pdp_ca *x) +{ + t_pdp *header = pdp_packet_header(x->x_packet0); + unsigned int *data = (unsigned int *)pdp_packet_data (x->x_packet0); + + int width = pdp_type_ca_info(header)->width; + int height = pdp_type_ca_info(header)->height; + int i; + + unsigned int saved; + + /* load TOS in middle of buffer to limit the effect of stack errors */ + unsigned int *tos = &x->x_data->stack[2*(PDP_CA_STACKSIZE/2)]; + unsigned int *env = &x->x_data->env[0]; + unsigned int *reg = &x->x_data->reg[0]; + void *ca_routine = x->x_ca_routine; + unsigned int rtos; + + /* double word width: number of unsigned ints per row */ + int dwwidth = width >> 5; + int currow = pdp_type_ca_info(header)->currow; + + unsigned long long result = 0; + + unsigned short temp; + unsigned short *usdata; + + /* set destination row to 4th row from top (ca time horizon is 3 deep) */ + int dwrow0 = (((currow + height - 3) % height) * width) >> 5; + int dwrow1 = (((currow + height - 2) % height) * width) >> 5; + int dwrow2 = (((currow + height - 1) % height) * width) >> 5; + int dwrow3 = (currow * width) >> 5; + + /* exit if there isn't a valid routine */ + if(!ca_routine) return; + + + /* compute new row */ + for(i=0; i < (dwwidth-1) ; i+=1){ + env[0] = data[dwrow0 + i]; + env[1] = data[dwrow0 + i + 1]; + env[2] = data[dwrow1 + i]; + env[3] = data[dwrow1 + i + 1]; + env[4] = data[dwrow2 + i]; + env[5] = data[dwrow2 + i + 1]; + result = scaf_feeder(tos, reg, ca_routine, env); + data[dwrow3 + i] = result & 0xffffffff; + } + // i == dwwidth-1 + + /* compute last column in row */ + env[0] = data[dwrow0 + i]; + env[1] = data[dwrow0]; + env[2] = data[dwrow1 + i]; + env[3] = data[dwrow1]; + env[4] = data[dwrow2 + i]; + env[5] = data[dwrow2]; + result = scaf_feeder(tos, reg, ca_routine, env); + data[dwrow3 + i] = result & 0xffffffff; + + + /* undo the shift */ + usdata = (unsigned short *)(&data[dwrow3]); + temp = usdata[(dwwidth*2)-1]; + for (i = (dwwidth*2 - 1); i > 0; i--){ + usdata[i] = usdata[i-1]; + } + usdata[0] = temp; + + /* check data stack pointer */ + rtos = (unsigned int)tos; + + if (env[0] != rtos){ + if (env[0] > rtos) post("pdp_ca: ERROR: stack underflow detected in ca routine"); + if (env[0] < rtos) post("pdp_ca: ERROR: ca routine returned more than one item"); + x->x_ca_routine = 0; + post("pdp_ca: rule disabled"); + + } + + /* save current row */ + pdp_type_ca_info(header)->currow = (currow + 1) % height; + +} + + +/* 2D: process from packet0 -> packet1 */ +static void pdp_ca_process_ca_2D(t_pdp_ca *x) +{ + t_pdp *header0 = pdp_packet_header(x->x_packet0); + t_pdp *header1 = pdp_packet_header(x->x_packet1); + unsigned int *data0 = (unsigned int *)pdp_packet_data (x->x_packet0); + unsigned int *data1 = (unsigned int *)pdp_packet_data (x->x_packet1); + + + int width = pdp_type_ca_info(header0)->width; + int height = pdp_type_ca_info(header0)->height; + int i,j; + + /* load TOS in middle of buffer to limit the effect of stack errors */ + unsigned int *tos = &x->x_data->stack[2*(PDP_CA_STACKSIZE/2)]; + unsigned int *env = &x->x_data->env[0]; + unsigned int *reg = &x->x_data->reg[0]; + void *ca_routine = x->x_ca_routine; + unsigned int rtos; + + int offset = pdp_type_ca_info(header0)->offset; + int xoffset = offset % width; + int yoffset = offset / width; + + /* double word width: number of unsigned ints per row */ + int dwwidth = width >> 5; + + unsigned long long result = 0; + + /* exit if there isn't a valid routine */ + if(!ca_routine) return; + if(!header0) return; + if(!header1) return; + + //post("pdp_ca: PRE offset: %d, xoffset: %d, yoffset: %d", offset, xoffset, yoffset); + + /* calculate new offset: lines shift up, rows shift left by 16 cells */ + xoffset = (xoffset + width - 16) % width; + yoffset = (yoffset + height - 1) % height; + + offset = yoffset * width + xoffset; + + //post("pdp_ca: PST offset: %d, xoffset: %d, yoffset: %d", offset, xoffset, yoffset); + + + pdp_type_ca_info(header1)->offset = offset; + + + for(j=0; j<dwwidth*(height - 2); j+=(dwwidth<<1)){ + for(i=0; i < (dwwidth-1) ; i+=1){ + env[0] = data0[i + j]; + env[1] = data0[i + j + 1]; + env[2] = data0[i + j + dwwidth]; + env[3] = data0[i + j + dwwidth + 1]; + env[4] = data0[i + j + (dwwidth<<1)]; + env[5] = data0[i + j + (dwwidth<<1) + 1]; + env[6] = data0[i + j + (dwwidth<<1) + dwwidth]; + env[7] = data0[i + j + (dwwidth<<1) + dwwidth + 1]; + result = scaf_feeder(tos, reg, ca_routine, env); + data1[i + j] = result & 0xffffffff; + data1[i + j + dwwidth] = result >> 32; + } + // i == dwwidth-1 + + env[0] = data0[i + j]; + env[1] = data0[j]; + env[2] = data0[i + j + dwwidth]; + env[3] = data0[j + dwwidth]; + env[4] = data0[i + j + (dwwidth<<1)]; + env[5] = data0[j + (dwwidth<<1)]; + env[6] = data0[i + j + (dwwidth<<1) + dwwidth]; + env[7] = data0[j + (dwwidth<<1) + dwwidth]; + result = scaf_feeder(tos, reg, ca_routine, env); + data1[i + j] = result & 0xffffffff; + data1[i + j + dwwidth] = result >> 32; + } + + // j == dwwidth*(height - 2) + for(i=0; i < (dwwidth-1) ; i+=1){ + env[0] = data0[i + j]; + env[1] = data0[i + j + 1]; + env[2] = data0[i + j + dwwidth]; + env[3] = data0[i + j + dwwidth + 1]; + env[4] = data0[i]; + env[5] = data0[i + 1]; + env[6] = data0[i + dwwidth]; + env[7] = data0[i + dwwidth + 1]; + result = scaf_feeder(tos, reg, ca_routine, env); + data1[i + j] = result & 0xffffffff; + data1[i + j + dwwidth] = result >> 32; + } + // j == dwwidth*(height - 2) + // i == dwwidth-1 + env[0] = data0[i + j]; + env[1] = data0[j]; + env[2] = data0[i + j + dwwidth]; + env[3] = data0[j + dwwidth]; + env[4] = data0[i]; + env[5] = data0[0]; + env[6] = data0[i + dwwidth]; + env[7] = data0[dwwidth]; + result = scaf_feeder(tos, reg, ca_routine, env); + data1[i + j] = result & 0xffffffff; + data1[i + j + dwwidth] = result >> 32; + + + + /* check data stack pointer */ + rtos = (unsigned int)tos; + + if (env[0] != rtos){ + if (env[0] > rtos) post("pdp_ca: ERROR: stack underflow detected in ca routine"); + if (env[0] < rtos) post("pdp_ca: ERROR: ca routine returned more than one item"); + x->x_ca_routine = 0; + post("pdp_ca: rule disabled"); + + } + + return; +} + + +static void pdp_ca_swappackets(t_pdp_ca *x) +{ + /* swap packets */ + int packet = x->x_packet1; + x->x_packet1 = x->x_packet0; + x->x_packet0 = packet; +} + + + + + +/* tick advance CA one timestep */ +static void pdp_ca_bang_thread(t_pdp_ca *x) +{ + int encoding; + int packet; + int i; + int iterations = x->x_iterations; + + /* invariant: the two packets are allways valid and compatible + so a bang is allways possible. this means that in the pdp an + invalid packet needs to be converted to a valid one */ + + if (-1 == x->x_packet0) pdp_post("warning: packet 0 invalid"); + if (-1 == x->x_packet1) pdp_post("warning: packet 1 invalid"); + + if (PDP_CA_MODE_2D == x->x_mode){ + for(i=0; i < iterations; i++){ + + /* process form packet0 -> packet1 */ + pdp_ca_process_ca_2D(x); + + /* swap */ + pdp_ca_swappackets(x); + } + } + else if (PDP_CA_MODE_1D == x->x_mode){ + if (x->x_fullscreen1d){ + t_pdp *header0 = pdp_packet_header(x->x_packet0); + pdp_type_ca_info(header0)->currow = 0; + pdp_type_ca_info(header0)->offset = 0; + iterations = pdp_type_ca_info(header0)->height; + } + for(i=0; i < iterations; i++){ + + pdp_ca_process_ca_1D(x); + } + } + +} + +static void pdp_ca_sendpacket(t_pdp_ca *x) +{ + + /* adjust offset before sending */ + t_pdp *header0 = pdp_packet_header(x->x_packet0); + int offset, width, height, xoffset, yoffset, horshift, vershift; + + if (!header0) return; + + offset = pdp_type_ca_info(header0)->offset; + width = pdp_type_ca_info(header0)->width; + height = pdp_type_ca_info(header0)->height; + xoffset = offset % width; + yoffset = offset / width; + horshift = x->x_horshift; + vershift = x->x_vershift; + + horshift %= width; + if (horshift < 0) horshift += width; + vershift %= height; + if (vershift < 0) vershift += height; + + xoffset = (xoffset + horshift) % width; + yoffset = (yoffset + vershift) % height; + offset = yoffset * width + xoffset; + + pdp_type_ca_info(header0)->offset = offset; + + + + /* output the packet */ + outlet_pdp(x->x_outlet0, x->x_packet0); +} + +static void pdp_ca_bang(t_pdp_ca *x) +{ + /* we don't use input packets for testing dropping here + but check the queue_id to see if processing is + still going on */ + + if (-1 == x->x_queue_id){ + pdp_queue_add(x, pdp_ca_bang_thread, pdp_ca_sendpacket, &x->x_queue_id); + } + + else{ + pdp_control_notify_drop(-1); + } +} + + +/* this method stores the packet into x->x_packet0 (the packet + to be processed) if it is valid. x->x_packet1 is not compatible + it is regenerated so that it is + + in short, when this routine returns both packets are valid + and compatible. +*/ + + +static void pdp_ca_copy_rw_if_valid(t_pdp_ca *x, int packet) +{ + t_pdp *header = pdp_packet_header(packet); + t_pdp *header1 = pdp_packet_header(x->x_packet1); + + + int grabpacket; + int convertedpacket; + + /* check if header is valid */ + if (!header) return; + + if (PDP_CA != header->type) return; + if (PDP_CA_STANDARD != pdp_type_ca_info(header)->encoding) return; + + + /* packet is a ca, register it */ + pdp_packet_mark_unused(x->x_packet0); + x->x_packet0 = pdp_packet_copy_rw(packet); + + + /* make sure we have the right header */ + header = pdp_packet_header(x->x_packet0); + + + /* make sure that the other packet is compatible */ + if ((pdp_type_ca_info(header1)->width != pdp_type_ca_info(header)->width) || + (pdp_type_ca_info(header1)->height != pdp_type_ca_info(header)->height)) { + + /* if not, throw away and clone the new one */ + pdp_packet_mark_unused(x->x_packet1); + x->x_packet1 = pdp_packet_clone_rw(x->x_packet0); + } + + if (-1 == x->x_packet0) pdp_post("warning: packet 0 invalid"); + if (-1 == x->x_packet1) pdp_post("warning: packet 1 invalid"); + + +}; + +/* hot packet inlet */ +static void pdp_ca_input_0(t_pdp_ca *x, t_symbol *s, t_floatarg f) +{ + + if (s == gensym("register_rw")){ + pdp_ca_copy_rw_if_valid(x, (int)f); + } + else if (s == gensym("process")){ + pdp_ca_bang(x); + } + + +} + +/* cold packet inlet */ +static void pdp_ca_input_1(t_pdp_ca *x, t_symbol *s, t_floatarg f) +{ + + if (s == gensym("register_rw")) + { + pdp_ca_copy_rw_if_valid(x, (int)f); + } + +} + + +static void pdp_ca_rule_string(t_pdp_ca *x, char *c) +{ + char tmp[256]; + void (*ca_routine)(void); + + + /* check if we can find string */ + sprintf(tmp, "rule_%s", c); + if (!(ca_routine = dlsym(x->x_ca_libhandle, tmp))){ + post("pdp_ca: can't fine ca rule %s (symbol: %s)", c, tmp); + return; + } + /* ok, so store routine address */ + else{ + x->x_ca_routine = ca_routine; + x->x_lastrule = gensym(c); + } +} + + +static void pdp_ca_rule(t_pdp_ca *x, t_symbol *s) +{ + /* make sure lib is loaded */ + if (!x->x_ca_libhandle) return; + + /* set rule by name */ + pdp_ca_rule_string(x, s->s_name); +} + +static void pdp_ca_rule_index(t_pdp_ca *x, t_float f) +{ + int i = (int)f; + + /* make sure lib is loaded */ + if (!x->x_ca_libhandle) return; + + /* check index */ + if (i<0) return; + if (i>=x->x_ca_nbrules) return; + + /* set rule by index */ + pdp_ca_rule_string(x, x->x_ca_rulename[i]); + +} + + +static void pdp_ca_close(t_pdp_ca *x) +{ + if (x->x_ca_libhandle){ + dlclose(x->x_ca_libhandle); + x->x_ca_libhandle = 0; + x->x_ca_routine = 0; + if (x->x_ca_rulename){ + free (x->x_ca_rulename); + x->x_ca_rulename = 0; + } + + + } +} + + +static void pdp_ca_printrules(t_pdp_ca *x) +{ + int i; + + if (!(x->x_ca_libhandle)) return; + post("pdp_ca: found %d rules: ", x->x_ca_nbrules); + for(i=0;i<x->x_ca_nbrules; i++) post("%3d: %s ", i, x->x_ca_rulename[i]); + + +} + +/* open code library */ +static void pdp_ca_openlib(t_pdp_ca *x, t_symbol *s) +{ + + char *c; + int words; + + /* close current lib, if one */ + pdp_ca_close(x); + + /* try to open new lib */ + if (!(x->x_ca_libhandle = dlopen(s->s_name, RTLD_NOW))){ + post("pdp_ca: can't open ca library %s\n%s", s->s_name, dlerror()); + x->x_ca_libhandle = 0; + return; + } + + /* scan for valid rules */ + if (!(x->x_ca_rulenames = (char *)dlsym(x->x_ca_libhandle, "rulenames"))){ + post("pdp_ca: ERROR: %s does not contain a name table. closing.", s->s_name); + pdp_ca_close(x); + return; + } + + /* count rules */ + words = 0; + for(c = (char *)x->x_ca_rulenames; *c;){ + words++; + while(*c++); + } + x->x_ca_nbrules = words; + x->x_ca_rulename = (char **)malloc(sizeof(char *) * words); + + /* build name array */ + words = 0; + for(c = (char *)x->x_ca_rulenames; *c;){ + x->x_ca_rulename[words] = c; + words++; + while(*c++); + } + + /* ok, we're done */ + post("pdp_ca: opened rule library %s", s->s_name ,x->x_ca_nbrules); + + /* print rule names */ + //pdp_ca_printrules(x); + + /* set last selected rule */ + pdp_ca_rule(x, x->x_lastrule); + + +} + +/* compile source file and open resulting code library */ +static void pdp_ca_opensrc(t_pdp_ca *x, t_symbol *s) +{ + #define TMPSIZE 1024 + char commandline[TMPSIZE]; + char library[TMPSIZE]; + int status; + + /* setup compiler args */ + snprintf(library, TMPSIZE, "%so", s->s_name); + snprintf(commandline, TMPSIZE, "scafc %s %s", s->s_name, library); + + + + /* call compiler */ + if (system(commandline)) + { + post ("pdp_ca: error compiling %s", s->s_name); + } + else + { + post("pdp_ca: compiled %s", s->s_name); + pdp_ca_openlib(x, gensym(library)); + } +} + +/* open a source file or a library, depending on extension */ +static void pdp_ca_open(t_pdp_ca *x, t_symbol *s) +{ + char *name = s->s_name; + char *end = name; + while(*end) end++; + if (end == name){ + post("pdp_ca: invalid file name"); + return; + } + /* if the name ends with 'o' assume it is a library */ + if (end[-1] == 'o'){ + pdp_ca_openlib(x, s); + } + /* otherwize, assume it is a source file */ + else{ + pdp_ca_opensrc(x, s); + } + +} + +/* init the current packet with random noise */ +static void pdp_ca_rand(t_pdp_ca *x){ + + t_pdp *header = pdp_packet_header(x->x_packet0); + short int *data = (short int *) pdp_packet_data(x->x_packet0); + int i; + + int nbshortints = (pdp_type_ca_info(header)->width >> 4) * pdp_type_ca_info(header)->height; + + for(i=0; i<nbshortints; i++) + data[i] = random(); + +} + + +static void pdp_ca_newca(t_pdp_ca *x, t_float width, t_float height) +{ + /* delete old packets */ + pdp_packet_mark_unused(x->x_packet0); + pdp_packet_mark_unused(x->x_packet1); + + + /* create new packets */ + x->x_packet0 = pdp_packet_new_ca(PDP_CA, width, height); + x->x_packet1 = pdp_packet_clone_rw(x->x_packet0); + +} + + +static void pdp_ca_iterations(t_pdp_ca *x, t_float f) +{ + int i = (int)f; + + if (i < 0) i = 0; + + x->x_iterations = i; +} + +static void pdp_ca_horshift16(t_pdp_ca *x, t_float f) +{ + x->x_horshift = 16 * (int)f; +} + +static void pdp_ca_vershift(t_pdp_ca *x, t_float f) +{ + x->x_vershift = (int)f; +} + +static void pdp_ca_set1d(t_pdp_ca *x) +{ + x->x_mode = PDP_CA_MODE_1D; +} + +static void pdp_ca_set2d(t_pdp_ca *x) +{ + x->x_mode = PDP_CA_MODE_2D; +} + +static void pdp_ca_fullscreen1d(t_pdp_ca *x, t_floatarg f) +{ + if (f == 0.0f) x->x_fullscreen1d = 0; + if (f == 1.0f) x->x_fullscreen1d = 1; +} + +static void pdp_ca_free(t_pdp_ca *x) +{ + pdp_packet_mark_unused(x->x_packet0); + pdp_packet_mark_unused(x->x_packet1); + pdp_ca_close(x); + free(x->x_data); +} + + + +void *pdp_ca_new(void) +{ + t_pdp_ca *x = (t_pdp_ca *)pd_new(pdp_ca_class); + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("iterations")); + + x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + + x->x_packet0 = -1; + x->x_packet1 = -1; + x->x_queue_id = -1; + + x->x_data = (t_pdp_ca_data *)malloc(sizeof(t_pdp_ca_data)); + x->x_ca_routine = 0; + x->x_ca_libhandle = 0; + x->x_ca_rulename = 0; + + x->x_horshift = 0; + x->x_vershift = 0; + + pdp_ca_newca(x, 64, 64); + pdp_ca_iterations(x, 1); + pdp_ca_set2d(x); + pdp_ca_fullscreen1d(x, 0); + + x->x_packet_type = gensym("grey"); + x->x_lastrule = gensym("gameoflife"); + pdp_ca_openlib(x, gensym(PDP_CA_RULES_LIB)); + + return (void *)x; +} + + +// *********************** CA CONVERTER CLASSES STUFF ********************* +// TODO: move this to a separate file later together with other converters (part of system?) + +#define PDP_CA2IMAGE 1 +#define PDP_IMAGE2CA 2 + +typedef struct pdp_ca_conv_struct +{ + t_object x_obj; + t_float x_f; + + + int x_threshold; + + int x_packet; + + t_outlet *x_outlet0; + + /* solve identity crisis */ + int x_whoami; + + /* output packet type */ + /* only greyscale for now */ + t_symbol *x_packet_type; + +} t_pdp_ca_conv; + +/* hot packet inlet */ +static void pdp_ca_conv_input_0(t_pdp_ca_conv *x, t_symbol *s, t_floatarg f) +{ + int packet = -1; + + if (s == gensym("register_ro")){ + pdp_packet_mark_unused(x->x_packet); + x->x_packet = pdp_packet_copy_ro((int)f); + return; + } + else if (s == gensym("process")){ + switch(x->x_whoami){ + case PDP_CA2IMAGE: + packet = pdp_type_ca2grey(x->x_packet); + break; + case PDP_IMAGE2CA: + packet = pdp_type_grey2ca(x->x_packet, x->x_threshold); + break; + } + + /* throw away the original packet */ + pdp_packet_mark_unused(x->x_packet); + x->x_packet = -1; + + + /* pass the fresh packet */ + pdp_packet_pass_if_valid(x->x_outlet0, &packet); + + /* unregister the freshly created packet */ + //pdp_packet_mark_unused(packet); + + /* output if valid */ + //if (-1 != packet) outlet_pdp(x->x_outlet0, packet); + } + + +} + +void pdp_ca_conv_free(t_pdp_ca_conv *x) +{ + pdp_packet_mark_unused(x->x_packet); +} + + +void pdp_image2ca_threshold(t_pdp_ca_conv *x, t_float f) +{ + f *= 0x8000; + + if (f < -0x7fff) f = -0x7fff; + if (f > 0x7fff) f = 0x7fff; + + x->x_threshold = (short int)f; +} + +void *pdp_ca2image_new(void) +{ + t_pdp_ca_conv *x = (t_pdp_ca_conv *)pd_new(pdp_ca2image_class); + x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + x->x_packet_type = gensym("grey"); + x->x_packet = -1; + x->x_whoami = PDP_CA2IMAGE; + return (void *)x; +} + +void *pdp_image2ca_new(void) +{ + t_pdp_ca_conv *x = (t_pdp_ca_conv *)pd_new(pdp_image2ca_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("threshold")); + x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + x->x_packet_type = gensym("grey"); + x->x_packet = -1; + x->x_whoami = PDP_IMAGE2CA; + x->x_threshold = 0x4000; + return (void *)x; +} + + +// *********************** CLASS SETUP FUNCTIONS ********************* + +#ifdef __cplusplus +extern "C" +{ +#endif + + + +void pdp_ca2image_setup(void) +{ + pdp_ca2image_class = class_new(gensym("pdp_ca2image"), (t_newmethod)pdp_ca2image_new, + (t_method)pdp_ca_conv_free, sizeof(t_pdp_ca), 0, A_NULL); + class_addmethod(pdp_ca2image_class, (t_method)pdp_ca_conv_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); +} + +void pdp_image2ca_setup(void) +{ + pdp_image2ca_class = class_new(gensym("pdp_image2ca"), (t_newmethod)pdp_image2ca_new, + (t_method)pdp_ca_conv_free, sizeof(t_pdp_ca), 0, A_NULL); + class_addmethod(pdp_image2ca_class, (t_method)pdp_ca_conv_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_image2ca_class, (t_method)pdp_image2ca_threshold, gensym("threshold"), A_FLOAT, A_NULL); +} + +void pdp_ca_setup(void) +{ + + + pdp_ca_class = class_new(gensym("pdp_ca"), (t_newmethod)pdp_ca_new, + (t_method)pdp_ca_free, sizeof(t_pdp_ca), 0, A_NULL); + + + class_addmethod(pdp_ca_class, (t_method)pdp_ca_iterations, gensym("iterations"), A_FLOAT, A_NULL); + class_addmethod(pdp_ca_class, (t_method)pdp_ca_bang, gensym("bang"), A_NULL); + class_addmethod(pdp_ca_class, (t_method)pdp_ca_printrules, gensym("rules"), A_NULL); + class_addmethod(pdp_ca_class, (t_method)pdp_ca_rand, gensym("random"), A_NULL); + class_addmethod(pdp_ca_class, (t_method)pdp_ca_newca, gensym("ca"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_ca_class, (t_method)pdp_ca_newca, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(pdp_ca_class, (t_method)pdp_ca_horshift16, gensym("hshift16"), A_FLOAT, A_NULL); + class_addmethod(pdp_ca_class, (t_method)pdp_ca_vershift, gensym("vshift"), A_FLOAT, A_NULL); + class_addmethod(pdp_ca_class, (t_method)pdp_ca_close, gensym("close"), A_NULL); + class_addmethod(pdp_ca_class, (t_method)pdp_ca_openlib, gensym("openlib"), A_SYMBOL, A_NULL); + class_addmethod(pdp_ca_class, (t_method)pdp_ca_opensrc, gensym("opensrc"), A_SYMBOL, A_NULL); + class_addmethod(pdp_ca_class, (t_method)pdp_ca_open, gensym("open"), A_SYMBOL, A_NULL); + class_addmethod(pdp_ca_class, (t_method)pdp_ca_rule, gensym("rule"), A_SYMBOL, A_NULL); + class_addmethod(pdp_ca_class, (t_method)pdp_ca_rule_index, gensym("ruleindex"), A_FLOAT, A_NULL); + class_addmethod(pdp_ca_class, (t_method)pdp_ca_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_ca_class, (t_method)pdp_ca_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_ca_class, (t_method)pdp_ca_set1d, gensym("1D"), A_NULL); + class_addmethod(pdp_ca_class, (t_method)pdp_ca_set2d, gensym("2D"), A_NULL); + class_addmethod(pdp_ca_class, (t_method)pdp_ca_fullscreen1d, gensym("fullscreen1D"), A_FLOAT, A_NULL); + +} + +#ifdef __cplusplus +} +#endif diff --git a/scaf/pdp/pdp_ca_system.c b/scaf/pdp/pdp_ca_system.c new file mode 100644 index 0000000..acbab34 --- /dev/null +++ b/scaf/pdp/pdp_ca_system.c @@ -0,0 +1,324 @@ +/* + * Cellular Automata Extension Module for pdp - Main system code + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +#include "pdp_ca.h" +#include "pdp_internals.h" + +/* all symbols are C-style */ +#ifdef __cplusplus +extern "C" +{ +#endif + + +/* check if packet is a valid ca packet */ +int pdp_packet_ca_isvalid(int packet) +{ + t_pdp *header = pdp_packet_header(packet); + if (!header) return 0; + if (PDP_CA != header->type) return 0; + if (PDP_CA_STANDARD != pdp_type_ca_info(header)->encoding) return 0; + + return 1; +} + + +static t_pdp_symbol *pdp_packet_ca_get_description(int packet) +{ + t_pdp *header = pdp_packet_header(packet); + char description[1024]; + char *c = description; + int encoding; + + if (!header) return pdp_gensym("invalid"); + if (header->type == PDP_CA){ + c += sprintf(c, "ca"); + switch(pdp_type_ca_info(header)->encoding){ + case PDP_CA_STANDARD: c += sprintf(c, "/1bit2D"); break; + default: + c += sprintf(c, "/unknown"); goto exit; + } + c += sprintf(c, "/%dx%d", + pdp_type_ca_info(header)->width, + pdp_type_ca_info(header)->height); + + exit: + return pdp_gensym(description); + } + else return pdp_gensym("unknown"); +} + +/* create a new ca packet */ +int pdp_packet_new_ca(int encoding, int width, int height) +{ + int p; + int w = (int)width; + int h = (int)height; + int bytesize; + t_pdp *header; + + /* ensure with = multiple of 64 */ + w &= 0xffffffc0; + + /* ensure height = multiple of 4 */ + w &= 0xfffffffc; + + w = (w<64) ? 64 : w; + h = (h<4) ? 4 : h; + + bytesize = (w>>3) * h; + + + /* create new packets */ + p = pdp_packet_new(PDP_CA, bytesize); + header = pdp_packet_header(p); + if (!header) { + pdp_post("error: can't create CA packet"); + return -1; + } + + pdp_type_ca_info(header)->encoding = PDP_CA_STANDARD; + pdp_type_ca_info(header)->width = w; + pdp_type_ca_info(header)->height = h; + pdp_type_ca_info(header)->offset = 0; + pdp_type_ca_info(header)->currow = 0; /* only used for 1D ca */ + pdp_type_ca_info(header)->currow = 0; + header->desc = 0; + header->desc = pdp_packet_ca_get_description(p); + //post("creating %s", header->desc->s_name); + return p; + +} + + +/* convert a CA packet to greyscale */ + +inline void _pdp_type_ca2grey_convert_word(unsigned short int source, short int *dest) +{ + + int i; + for (i = 15; i>=0; i--){ + dest[i] = ((unsigned short)(((short int)(source & 0x8000)) >> 14)) >> 1; + source <<= 1; + } +} + +int pdp_type_ca2grey(int packet) +{ + int w, h, s, x, y, srcindex; + long long offset, xoffset, yoffset; + short int *dest; + unsigned short int *source; + t_pdp *header; + t_pdp *newheader; + int newpacket; + if (!(pdp_packet_ca_isvalid(packet))) return -1; + + header = pdp_packet_header(packet); + w = pdp_type_ca_info(header)->width; + h = pdp_type_ca_info(header)->height; + s = w*h; + source = (unsigned short int *)pdp_packet_data(packet); + offset = pdp_type_ca_info(header)->offset; + yoffset = (offset / w) * w; + xoffset = offset % w; + + //post("pdp_type_ca2grey: offset: %d, xoffset: %d, yoffset: %d", offset, xoffset, yoffset); + + newpacket = pdp_packet_new_image_grey(w, h); + newheader = pdp_packet_header(newpacket); + + if (!newheader) return -1; + + //newheader->info.image.width = w; + //newheader->info.image.height = h; + //newheader->info.image.encoding = PDP_IMAGE_GREY; + dest = (short int *)pdp_packet_data(newpacket); + + +#define check_srcindex \ +if (srcindex >= (s >> 4)) post ("pdp_type_ca2grey: srcindex out of bound"); + +#define check_dstindex \ +if ((x+y) >= s) post ("pdp_type_ca2grey: dstindex out of bound"); + + + /* debug : dont' shift offset + if (0){ + for(y=0; y< (h*w); y+=w){ + for(x=0; x<w; x+=16){ + _pdp_type_ca2grey_convert_word (source[(x+y)>>4], &dest[x+y]); + } + } + return newpacket; + } + */ + + /* create top left */ + for (y=0; y < (h*w) - yoffset; y+=w) { + for (x=0; x< (w - xoffset); x+=16) { + srcindex = (x+xoffset + y+yoffset) >> 4; + //check_srcindex; + //check_dstindex; + _pdp_type_ca2grey_convert_word (source[srcindex], &dest[x+y]); + } + } + + /* create top right */ + for (y=0; y < (h*w) - yoffset; y+=w) { + for (x = (w - xoffset); x < w; x+=16) { + srcindex = (x+xoffset-w + y+yoffset) >> 4; + //check_srcindex; + //check_dstindex; + _pdp_type_ca2grey_convert_word (source[srcindex], &dest[x+y]); + } + } + + /* create bottom left */ + for (y=(h*w) - yoffset; y < h*w; y+=w) { + for (x=0; x< (w - xoffset); x+=16) { + srcindex = (x+xoffset + y+yoffset-(w*h)) >> 4; + //check_srcindex; + //check_dstindex; + _pdp_type_ca2grey_convert_word (source[srcindex], &dest[x+y]); + } + } + + /* create bottom right */ + for (y=(h*w) - yoffset; y < h*w; y+=w) { + for (x = (w - xoffset); x < w; x+=16) { + srcindex = (x+xoffset-w + y+yoffset-(w*h)) >> 4; + //check_srcindex; + //check_dstindex; + _pdp_type_ca2grey_convert_word (source[srcindex], &dest[x+y]); + } + } + + + return newpacket; + +} + + +inline unsigned short int _pdp_type_grey2ca_convert_word(short int *src, short int threshold) +{ + short int tmp; + short int dest = 0; + int i; + + for (i = 15; i >= 0; i--){ + dest <<= 1; + dest |= (src[i] > threshold); + } + + return dest; +} + + + +int pdp_type_grey2ca(int packet, short int threshold) +{ + int w, h, s, x, y, srcindex; + long long offset, xoffset, yoffset; + short int *dest; + short int *source; + t_pdp *header; + t_pdp *newheader; + int newpacket; + if (!(pdp_packet_image_isvalid(packet))) return -1; + + header = pdp_packet_header(packet); + w = header->info.image.width; + h = header->info.image.height; + s = w*h; + source = (unsigned short int *)pdp_packet_data(packet); + + if ( (PDP_IMAGE_GREY != header->info.image.encoding) + && (PDP_IMAGE_YV12 != header->info.image.encoding)) return -1; + + newpacket = pdp_packet_new_ca(PDP_CA_STANDARD, w, h); + newheader = pdp_packet_header(newpacket); + + if (!newheader) return -1; + + dest = (short int *)pdp_packet_data(newpacket); + + for(y=0; y< (h*w); y+=w){ + for(x=0; x<w; x+=16){ + dest[(x+y)>>4] = _pdp_type_grey2ca_convert_word (&source[x+y], threshold); + } + } + return newpacket; + + +} + +/* returns a pointer to the ca subheader given the pdp header */ +t_ca *pdp_type_ca_info(t_pdp *x){return (t_ca *)(&x->info.raw);} + + +void pdp_ca_setup(void); +void pdp_ca2image_setup(void); +void pdp_image2ca_setup(void); + + +static int _ca_to_image(int packet, t_pdp_symbol *template) +{ + return pdp_type_ca2grey(packet); +} + +static int _image_to_ca(int packet, t_pdp_symbol *template) +{ + // convert with default threshold == 0.5 + return pdp_type_grey2ca(packet, 0.5f); +} + +void pdp_scaf_setup(void) +{ + + t_pdp_conversion_program *program; + + /* babble */ + post ("PDP: pdp_scaf extension library"); + + /* setup modules */ + pdp_ca_setup(); + pdp_ca2image_setup(); + pdp_image2ca_setup(); + + /* setup type conversion */ + program = pdp_conversion_program_new(_ca_to_image, 0); + pdp_type_register_conversion(pdp_gensym("ca/*/*"), pdp_gensym("image/*/*"), program); + pdp_type_register_conversion(pdp_gensym("ca/*/*"), pdp_gensym("image/grey/*"), program); + + program = pdp_conversion_program_new(_image_to_ca, 0); + pdp_type_register_conversion(pdp_gensym("image/grey/*"), pdp_gensym("ca/*/*"), program); + + + + +} + + + + +#ifdef __cplusplus +} +#endif diff --git a/scaf/pdp/scaf_feeder.s b/scaf/pdp/scaf_feeder.s new file mode 100644 index 0000000..e7ef3c6 --- /dev/null +++ b/scaf/pdp/scaf_feeder.s @@ -0,0 +1,50 @@ +# Pure Data Packet - scaf feeder routine. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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. +# + +# for dup +.include "../compiler/scafmacro.s" + + +# *rg is only used for returning the stack pointer +# the 4 bit counter is using registers mm4-mm7 now +# long long scaf_feeder(void *tos, void *rg, *void() ca_rule, void *env) +.globl scaf_feeder +.type scaf_feeder, @function +scaf_feeder: + pushl %ebp + movl %esp, %ebp + push %esi + push %edi + + movl 20(%ebp), %edi # load env ptr + movl 8(%ebp), %esi # load TOS2 ptr + movl 16(%ebp), %eax # address of ca routine + pcmpeqw %mm3, %mm3 # load 1 reg + + call *%eax # TOS = 32x2 cell result + dup # push %mm0 to memory + movl (%esi), %eax + movl 4(%esi), %edx + lea 16(%esi), %esi # discard stack + movl %esi, (%edi) # store for stack underflow check + + emms + pop %edi + pop %esi + leave + ret diff --git a/scaf/rules/Makefile b/scaf/rules/Makefile new file mode 100644 index 0000000..997207c --- /dev/null +++ b/scaf/rules/Makefile @@ -0,0 +1,14 @@ +OBJ = carules.scafo + +.SUFFIXES: .scaf +.SUFFIXES: .scafo + +.scaf.scafo: + ../compiler/scafc $*.scaf + +all: $(OBJ) + +clean: + rm -f *.scafo + rm -f *.s + rm -f *~ diff --git a/scaf/rules/carules.scaf b/scaf/rules/carules.scaf new file mode 100644 index 0000000..6725641 --- /dev/null +++ b/scaf/rules/carules.scaf @@ -0,0 +1,118 @@ +( Pure Data Packet - ca rules library. ) +( Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> ) +( ) +( 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 is the standard ca rules library ) +( a rule that is accessible from the ouside should start with "rule_" ) +( and has to return exactly one item on the stack (this is checked in pdp_ca) ) + + +( a word is a sequence of non whitespace characters (\S+) ) +( words are separated by whitespace (\s+) ) +( so "word ;" is not the same as "word;" ) + +( all words between the "(" word and the ")" word are ignored ) + +( ":" starts a definition, the next word is the name of the new word ) +( newline ends a definition ) + +( no more than one definition per line ) +( no more than one line per definition ) + +( ";" returns to calling word ) +( if no ";" is encountered the next defined word is executed ) +( this is to have multiple entry points ) +( multiple exit points don't make sense since there are no conditional words ) + + + +: +(4) ++++ ; ( 4 bit add TOS - carry on TOS ) +: +(3) +++ ; ( 3 bit add TOS - carry on TOS ) +: +(2) ++ ; ( 2 bit add TOS - carry on TOS ) + +: +top @-+ +(4) drop @0+ +(4) drop @++ +(4) ; ( add top row to reg - carry on TOS ) +: +mid @-0 +(4) drop @00 +(4) drop @+0 +(4) ; ( add mid row to reg - carry on TOS ) +: +bot @-- +(4) drop @0- +(4) drop @+- +(4) ; ( add bot row to reg - carry on TOS ) +: +all +top drop +mid drop +bot ; ( add all cells to reg - carry on TOS ) + +: +mid-1 @-0 +(4) drop @+0 +(4) ; ( add mid row except center element to reg - carry on TOS ) +: +all-1 +top drop +mid-1 drop +bot ; ( add all cells expet middle one to reg - carry on TOS ) + + +: countall a-0 +all drop ; ( count all cells - no stack effect ) +: countall-1 a-0 +all-1 drop ; ( count all cells except middle one - no stack effect ) + +: +topbot @0+ +(3) drop @0- +(3) ; +: +leftright @+0 +(3) drop @-0 +(3) ; +: +star +topbot drop +leftright ; +: countstar a-0 +star drop ; + +: =2or3? @a2 not @a1 and ; ( sum equal to 2 or 3? only checks 3 bits ) +: =3? =2or3? @a0 and ; ( sum equal to 3 ? ) +: =2? =2or3? @a0 not and ; ( sum equal to 2 ? ) +: =4? @a2 @a1 not and @a0 not and ; ( sum equal to 4 ? ) + + + +( some test rules ) + +( : rule_one 1 ; ) +( : rule_zero 0 ; ) +( : rule_id @00 ; ) + + +: rule_shiftleft @+0 ; +: rule_shifttop @0- ; +: rule_shiftbot @0+ ; +: rule_shifttopright @-- ; +: rule_strobe @00 not ; + +( game of life ) + +: rule_gameoflife countall-1 =2? @00 and =3? or ; + +( wolfram's rule 110) + +: rule_w110 @00 @+0 and not @-0 @00 @+0 or or and ; + + +( some other rules ) + +: rule_w110mod @0+ @+0 and not @-+ @0+ @++ or or and ; + +: rule_w110mod2 @0+ @+0 and not @-+ @0+ @+0 or or and ; +: rule_w110mod3 @0+ @++ and not @-+ @0+ @++ or or and @-0 @00 @+0 or or and ; + +: rule_golmod countall-1 =3? @00 and =2? or ; +: rule_golmod2 countall-1 =2? @0+ and =3? or ; +: rule_golmod3 countall-1 =2? @++ and =3? or ; +: rule_golmod4 countall-1 =2? @++ @-- or and =3? or ; +: rule_golmod5 countall-1 =2? @++ @-- or and =3? @+- and or ; +: rule_golmod6 countall-1 =2? @++ @-- or and =3? @+- and or @0+ or ; +: rule_golmod7 countall-1 =2? @++ @-- or and =3? @+- and or @0+ or @00 and ; + +( ca's with a short settling time ) + +: rule_block countstar =4? not =2? and @00 or ; +: rule_noiseedges countstar =4? =3? or not =2? and @00 or @++ xor ; +: rule_noiseplanes countstar =4? =3? or not =2? and @00 or @++ xor @-- xor ; + + +( : rule_noiseplanes countstar =4? =3? or not =2? and @00 or @++ xor @-- xor ; ) + +: rule_fire countall-1 =2? @0+ and =3? or ; diff --git a/scaf/test/test_pdp_ca.pd b/scaf/test/test_pdp_ca.pd new file mode 100644 index 0000000..1b84312 --- /dev/null +++ b/scaf/test/test_pdp_ca.pd @@ -0,0 +1,132 @@ +#N canvas 650 350 625 557 10; +#X obj 287 82 openpanel; +#X msg 287 56 bang; +#X msg 288 110 open \$1; +#X obj 230 191 pdp_ca; +#X obj 193 76 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 223 80 metro 40; +#X msg 211 56 bang; +#X msg 247 56 stop; +#X obj 146 235 pdp_xv; +#X obj 28 31 t b b b; +#X obj 11 7 loadbang; +#X msg 99 80 rule id; +#X msg 328 155 ca 256 256; +#X msg 256 296 rule shifttopright; +#X msg 331 134 ca 64 64; +#X msg 262 270 rule shiftleft; +#X msg 298 216 random; +#X msg 251 321 rule gameoflife; +#X floatatom 344 52 5 0 0; +#X msg 331 184 ca 1024 1024; +#X floatatom 279 154 5 0 0; +#X msg 357 106 ca 512 512; +#X msg 363 80 ca 320 240; +#X obj 211 120 pdp_v4l; +#X obj 179 99 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 138 53 metro 40; +#X msg 126 29 bang; +#X msg 162 29 stop; +#X floatatom 205 28 5 0 0; +#X msg 243 348 rule w110; +#X msg 245 371 rule w110mod; +#X msg 54 371 rule w110mod2; +#X msg 387 47 ca 640 394; +#X obj 481 289 count; +#X obj 397 248 route 0 1 2 3; +#X floatatom 517 254 5 0 0; +#X msg 466 184 bang; +#X msg 502 184 stop; +#X floatatom 552 171 5 0 0; +#X obj 478 208 metro 1000; +#X msg 258 403 rule golmod; +#X floatatom 34 129 5 0 0; +#X obj 90 207 pdp_bqt; +#X msg 62 107 dim 64 64; +#X msg 44 167 hpf \$1 0.5; +#X msg 272 430 rule golmod2; +#X msg 273 467 rule golmod3; +#X msg 277 494 rule golmod4; +#X msg 280 515 rule golmod5; +#X msg 283 537 rule golmod6; +#X msg 380 403 rule golmod7; +#X obj 46 267 pdp_mix; +#X floatatom 120 297 5 0 0; +#X msg 61 462 type grey; +#X msg 112 407 rule w110mod3; +#X msg 64 490 type yv12; +#X msg 438 471 dim 512 512; +#X obj 270 134 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 463 111 ca 1024 512; +#X msg 105 4 open /home/tom/pd/packet/scaf/modules/carules.scafo; +#X msg 163 468 rule toomuch; +#X msg 165 500 rule underflow; +#X connect 0 0 2 0; +#X connect 1 0 0 0; +#X connect 2 0 3 0; +#X connect 3 0 8 0; +#X connect 4 0 3 0; +#X connect 5 0 3 0; +#X connect 6 0 5 0; +#X connect 7 0 5 0; +#X connect 9 1 11 0; +#X connect 9 2 59 0; +#X connect 10 0 9 0; +#X connect 11 0 3 0; +#X connect 12 0 3 0; +#X connect 13 0 3 0; +#X connect 14 0 3 0; +#X connect 15 0 3 0; +#X connect 16 0 3 0; +#X connect 17 0 3 0; +#X connect 18 0 5 1; +#X connect 19 0 3 0; +#X connect 20 0 3 2; +#X connect 21 0 3 0; +#X connect 22 0 3 0; +#X connect 23 0 51 1; +#X connect 23 0 3 1; +#X connect 24 0 23 0; +#X connect 25 0 24 0; +#X connect 26 0 25 0; +#X connect 27 0 25 0; +#X connect 28 0 25 1; +#X connect 29 0 3 0; +#X connect 30 0 3 0; +#X connect 31 0 3 0; +#X connect 32 0 3 0; +#X connect 33 0 34 0; +#X connect 34 0 30 0; +#X connect 34 1 17 0; +#X connect 34 2 40 0; +#X connect 34 3 17 0; +#X connect 35 0 33 1; +#X connect 36 0 39 0; +#X connect 37 0 39 0; +#X connect 38 0 39 1; +#X connect 39 0 33 0; +#X connect 40 0 3 0; +#X connect 41 0 44 0; +#X connect 42 0 8 0; +#X connect 43 0 23 0; +#X connect 44 0 42 0; +#X connect 45 0 3 0; +#X connect 46 0 3 0; +#X connect 47 0 3 0; +#X connect 48 0 3 0; +#X connect 49 0 3 0; +#X connect 50 0 3 0; +#X connect 51 0 8 0; +#X connect 52 0 51 2; +#X connect 53 0 23 0; +#X connect 54 0 3 0; +#X connect 55 0 23 0; +#X connect 56 0 8 0; +#X connect 57 0 20 0; +#X connect 58 0 3 0; +#X connect 59 0 3 0; +#X connect 60 0 3 0; +#X connect 61 0 3 0; diff --git a/scaf/test/test_pdp_ca2.pd b/scaf/test/test_pdp_ca2.pd new file mode 100644 index 0000000..9561d9d --- /dev/null +++ b/scaf/test/test_pdp_ca2.pd @@ -0,0 +1,154 @@ +#N canvas 454 152 625 557 10; +#X obj 325 83 openpanel; +#X msg 325 57 bang; +#X msg 326 111 open \$1; +#X obj 428 234 pdp_ca; +#X obj 256 149 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 223 80 metro 40; +#X msg 211 56 bang; +#X msg 247 56 stop; +#X obj 402 407 pdp_xv; +#X obj 28 31 t b b b; +#X obj 11 7 loadbang; +#X msg 391 99 ca 256 256; +#X msg 394 78 ca 64 64; +#X msg 298 216 random; +#X msg 251 321 rule gameoflife; +#X floatatom 490 187 5 0 0; +#X msg 420 50 ca 512 512; +#X obj 107 188 pdp_v4l; +#X obj 97 127 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 243 348 rule w110; +#X msg 245 371 rule w110mod; +#X msg 258 403 rule golmod; +#X msg 272 430 rule golmod2; +#X msg 273 467 rule golmod3; +#X msg 277 494 rule golmod4; +#X msg 280 515 rule golmod5; +#X msg 283 537 rule golmod6; +#X obj 481 167 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 526 55 ca 1024 512; +#X obj 426 294 pdp_ca2image; +#X obj 104 228 pdp_image2ca; +#X obj 136 155 metro 40; +#X msg 124 131 bang; +#X msg 160 131 stop; +#X floatatom 510 273 5 0 0; +#X obj 501 253 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 468 416 rule gameoflife; +#X msg 450 455 rule golmod6; +#X msg 380 440 rule golmod3; +#X msg 159 287 rules; +#X floatatom 27 213 5 0 0; +#X msg 40 319 ruleindex \$1; +#X obj 31 254 t b f; +#X msg 52 78 rule gameoflife; +#X floatatom 193 198 5 0 0; +#X msg 504 143 close; +#X msg 149 448 rule test1; +#X obj 181 178 hsl 128 15 0 1 0 0 empty empty empty -2 -6 0 8 -262144 +-1 -1 0 1; +#X msg 5 129 dim 640 480; +#X obj 156 51 pdp_qt; +#X msg 174 23 open /home/ben/MOV/test1.mov; +#X floatatom 93 31 5 0 0; +#X msg 65 56 autoplay 1; +#X obj 144 25 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 22 94 loop 1; +#X obj 439 483 osc~ 150; +#X obj 439 508 *~ 0.1; +#X obj 437 536 dac~; +#X floatatom 282 57 5 0 0; +#X msg 503 113 ca 32 32; +#X obj 428 322 pdp_motion_blur; +#X obj 488 349 pdp_gradient; +#X obj 425 382 pdp_mix; +#X floatatom 508 380 5 0 0; +#X floatatom 204 128 5 0 0; +#X obj 39 399 pdp_control; +#X obj 83 476 pdp_control; +#X obj 84 519 print two; +#X obj 39 438 print one; +#X obj 275 149 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 265 128 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 38 374 thread \$1; +#X obj 32 349 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X msg 105 4 open /home/tom/pd/packet/scaf/rules/carules.scafo; +#X connect 0 0 2 0; +#X connect 1 0 0 0; +#X connect 2 0 3 0; +#X connect 3 0 29 0; +#X connect 4 0 3 0; +#X connect 5 0 3 0; +#X connect 6 0 5 0; +#X connect 7 0 5 0; +#X connect 9 1 43 0; +#X connect 9 2 73 0; +#X connect 10 0 9 0; +#X connect 11 0 3 0; +#X connect 12 0 3 0; +#X connect 13 0 3 0; +#X connect 14 0 3 0; +#X connect 15 0 3 2; +#X connect 16 0 3 0; +#X connect 17 0 30 0; +#X connect 17 0 62 1; +#X connect 18 0 17 0; +#X connect 19 0 3 0; +#X connect 20 0 3 0; +#X connect 21 0 3 0; +#X connect 22 0 3 0; +#X connect 23 0 3 0; +#X connect 24 0 3 0; +#X connect 25 0 3 0; +#X connect 26 0 3 0; +#X connect 27 0 15 0; +#X connect 28 0 3 0; +#X connect 29 0 61 0; +#X connect 30 0 3 0; +#X connect 31 0 17 0; +#X connect 32 0 31 0; +#X connect 33 0 31 0; +#X connect 35 0 34 0; +#X connect 39 0 3 0; +#X connect 40 0 42 0; +#X connect 41 0 3 0; +#X connect 42 0 13 0; +#X connect 42 1 41 0; +#X connect 43 0 3 0; +#X connect 44 0 30 1; +#X connect 45 0 3 0; +#X connect 46 0 3 0; +#X connect 47 0 44 0; +#X connect 48 0 17 0; +#X connect 49 0 30 0; +#X connect 50 0 49 0; +#X connect 51 0 49 0; +#X connect 52 0 49 0; +#X connect 53 0 49 0; +#X connect 54 0 49 0; +#X connect 55 0 56 0; +#X connect 56 0 57 0; +#X connect 56 0 57 1; +#X connect 58 0 5 1; +#X connect 59 0 3 0; +#X connect 61 0 62 0; +#X connect 62 0 8 0; +#X connect 63 0 62 2; +#X connect 64 0 31 1; +#X connect 65 0 68 0; +#X connect 66 0 67 0; +#X connect 69 0 3 0; +#X connect 70 0 4 0; +#X connect 70 0 69 0; +#X connect 71 0 65 0; +#X connect 72 0 71 0; +#X connect 73 0 3 0; diff --git a/scaf/test/test_pdp_ca3.pd b/scaf/test/test_pdp_ca3.pd new file mode 100644 index 0000000..1dde086 --- /dev/null +++ b/scaf/test/test_pdp_ca3.pd @@ -0,0 +1,161 @@ +#N canvas 540 210 625 557 10; +#X obj 325 83 openpanel; +#X msg 325 57 bang; +#X msg 326 111 open \$1; +#X obj 427 212 pdp_ca; +#X obj 202 87 metro 40; +#X msg 211 56 bang; +#X msg 247 56 stop; +#X obj 391 414 pdp_xv; +#X obj 28 31 t b b b; +#X obj 11 7 loadbang; +#X msg 391 99 ca 256 256; +#X msg 394 78 ca 64 64; +#X msg 229 230 random; +#X msg 251 321 rule gameoflife; +#X floatatom 490 187 5 0 0; +#X msg 420 50 ca 512 512; +#X obj 97 127 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 243 348 rule w110; +#X msg 245 371 rule w110mod; +#X msg 258 403 rule golmod; +#X msg 272 430 rule golmod2; +#X msg 273 467 rule golmod3; +#X msg 277 494 rule golmod4; +#X msg 280 515 rule golmod5; +#X msg 283 537 rule golmod6; +#X obj 481 167 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 526 55 ca 1024 512; +#X obj 427 236 pdp_ca2image; +#X floatatom 530 253 5 0 0; +#X msg 468 416 rule gameoflife; +#X msg 450 455 rule golmod6; +#X msg 380 440 rule golmod3; +#X msg 159 287 rules; +#X floatatom 27 213 5 0 0; +#X msg 40 319 ruleindex \$1; +#X obj 31 254 t b f; +#X msg 52 78 rule gameoflife; +#X msg 504 143 close; +#X msg 149 448 rule test1; +#X obj 156 51 pdp_qt; +#X msg 174 23 open /home/ben/MOV/test1.mov; +#X floatatom 93 31 5 0 0; +#X msg 65 56 autoplay 1; +#X obj 144 25 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X floatatom 282 57 5 0 0; +#X msg 503 113 ca 32 32; +#X obj 39 399 pdp_control; +#X obj 83 476 pdp_control; +#X obj 84 519 print two; +#X obj 39 438 print one; +#X msg 38 374 thread \$1; +#X obj 32 349 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X obj 428 352 pdp_zrot; +#X obj 428 324 pdp_mix; +#X floatatom 523 305 5 0 0; +#X floatatom 523 327 5 0 0; +#X floatatom 523 349 5 0 0; +#X obj 427 264 pdp_blur; +#X obj 428 289 pdp_gain; +#X floatatom 530 277 5 0 0; +#X floatatom 260 120 5 0 0; +#X obj 433 159 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 375 364 pdp_xv; +#X floatatom 144 162 5 0 0; +#X msg 144 191 vshift \$1; +#X msg 549 160 1D; +#X msg 579 160 2D; +#X msg 253 183 fullscreen1D \$1; +#X obj 253 164 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 583 272 3; +#X msg 586 324 1.05; +#X msg 586 351 2; +#X msg 588 297 0.97; +#X msg 581 243 0.1; +#X msg 444 25 ca 512 256; +#X obj 434 385 pdp_gain; +#X floatatom 507 380 5 0 0; +#X msg 105 4 open /home/tom/pd/packet/scaf/rules/carules.scafo; +#X msg 248 295 rule fire; +#X msg 140 141 0; +#X msg 175 140; +#X connect 0 0 2 0; +#X connect 1 0 0 0; +#X connect 2 0 3 0; +#X connect 3 0 27 0; +#X connect 4 0 3 0; +#X connect 5 0 4 0; +#X connect 6 0 4 0; +#X connect 8 1 36 0; +#X connect 8 2 77 0; +#X connect 9 0 8 0; +#X connect 10 0 3 0; +#X connect 11 0 3 0; +#X connect 12 0 3 0; +#X connect 13 0 3 0; +#X connect 14 0 3 2; +#X connect 15 0 3 0; +#X connect 17 0 3 0; +#X connect 18 0 3 0; +#X connect 19 0 3 0; +#X connect 20 0 3 0; +#X connect 21 0 3 0; +#X connect 22 0 3 0; +#X connect 23 0 3 0; +#X connect 24 0 3 0; +#X connect 25 0 14 0; +#X connect 26 0 3 0; +#X connect 27 0 57 0; +#X connect 27 0 62 0; +#X connect 28 0 57 1; +#X connect 32 0 3 0; +#X connect 33 0 35 0; +#X connect 34 0 3 0; +#X connect 35 0 12 0; +#X connect 35 1 34 0; +#X connect 36 0 3 0; +#X connect 37 0 3 0; +#X connect 38 0 3 0; +#X connect 40 0 39 0; +#X connect 41 0 39 0; +#X connect 42 0 39 0; +#X connect 43 0 39 0; +#X connect 44 0 4 1; +#X connect 45 0 3 0; +#X connect 50 0 46 0; +#X connect 51 0 50 0; +#X connect 52 0 53 1; +#X connect 52 0 75 0; +#X connect 53 0 52 0; +#X connect 54 0 53 2; +#X connect 55 0 52 1; +#X connect 56 0 52 2; +#X connect 57 0 58 0; +#X connect 58 0 53 0; +#X connect 59 0 58 1; +#X connect 61 0 3 0; +#X connect 63 0 64 0; +#X connect 64 0 3 0; +#X connect 65 0 3 0; +#X connect 66 0 3 0; +#X connect 67 0 3 0; +#X connect 68 0 67 0; +#X connect 69 0 59 0; +#X connect 70 0 55 0; +#X connect 71 0 56 0; +#X connect 72 0 54 0; +#X connect 73 0 28 0; +#X connect 74 0 3 0; +#X connect 75 0 7 0; +#X connect 76 0 75 1; +#X connect 77 0 3 0; +#X connect 78 0 3 0; +#X connect 79 0 63 0; +#X connect 80 0 63 0; diff --git a/system/CONTENTS b/system/CONTENTS new file mode 100644 index 0000000..a1dd455 --- /dev/null +++ b/system/CONTENTS @@ -0,0 +1,9 @@ +X11 x window specific code +forth packet forth code +image image processing code +kernel the core pdp system +mmx mmx assembly code +net networking support +png png support +type different packet type implementations + diff --git a/system/Makefile b/system/Makefile new file mode 100644 index 0000000..eba38f9 --- /dev/null +++ b/system/Makefile @@ -0,0 +1,30 @@ + +include ../Makefile.config + +all: $(PDP_TARGET) pdp.o + +common: + make -C net + make -C X11 + make -C png + make -C type + make -C kernel + make -C image $(PDP_TARGET) + +linux_mmx: common + make -C mmx + +linux: common + +darwin: common + +clean: + rm -f *~ + rm -f *.o + make -C mmx clean + make -C net clean + make -C X11 clean + make -C png clean + make -C image clean + make -C type clean + make -C kernel clean diff --git a/system/X11/Makefile b/system/X11/Makefile new file mode 100644 index 0000000..205f975 --- /dev/null +++ b/system/X11/Makefile @@ -0,0 +1,11 @@ + +OBJECTS = $(PDP_X11MOD) + + +include ../../Makefile.config + +all: $(OBJECTS) + +clean: + rm -f *~ + rm -f *.o diff --git a/system/X11/pdp_xvideo.c b/system/X11/pdp_xvideo.c new file mode 100644 index 0000000..dab060d --- /dev/null +++ b/system/X11/pdp_xvideo.c @@ -0,0 +1,201 @@ +/* + * Pure Data Packet system module. - x window glue code (fairly tied to pd and pdp) + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 code is fairly tied to pd and pdp. serves mainly as reusable glue code +// for pdp_xv, pdp_glx, pdp_3d_windowcontext, ... + +#include <string.h> + +#include "pdp_xwindow.h" +#include "pdp_xvideo.h" +#include "pdp_post.h" +#include "pdp_packet.h" + +#define D if(0) + + + + +/************************************* PDP_XVIDEO ************************************/ + +static void pdp_xvideo_create_xvimage(t_pdp_xvideo *xvid, int width, int height) +{ + int i; + long size; + + //post("pdp_xvideo_create_xvimage"); + + xvid->width = width; + xvid->height = height; + size = (xvid->width * xvid->height + (((xvid->width>>1)*(xvid->height>>1))<<1)); + //post("create xvimage %d %d", xvid->width, xvid->height); + xvid->data = (unsigned char *)pdp_alloc(size); + for (i=0; i<size; i++) xvid->data[i] = i; + xvid->xvi = XvCreateImage(xvid->xdpy->dpy, xvid->xv_port, xvid->xv_format, (char *)xvid->data, xvid->width, xvid->height); + xvid->last_encoding = -1; + if ((!xvid->xvi) || (!xvid->data)) pdp_post ("ERROR CREATING XVIMAGE"); + //pdp_post("created xvimag data:%x xvi:%x",xvid->data,xvid->xvi); + +} + +static void pdp_xvideo_destroy_xvimage(t_pdp_xvideo *xvid) +{ + if(xvid->data) pdp_dealloc(xvid->data); + if (xvid->xvi) XFree(xvid->xvi); + xvid->xvi = 0; + xvid->data = 0; +} + +void pdp_xvideo_display_packet(t_pdp_xvideo *xvid, t_pdp_xwindow *xwin, int packet) +{ + t_pdp *header = pdp_packet_header(packet); + void *data = pdp_packet_data(packet); + t_bitmap * bm = pdp_packet_bitmap_info(packet); + unsigned int width, height, encoding, size, nbpixels; + + /* some checks: only display when initialized and when pacet is bitmap YV12 */ + if (!xvid->initialized) return; + if (!header) return; + if (!bm) return; + + width = bm->width; + height = bm->height; + encoding = bm->encoding; + size = (width * height + (((width>>1)*(height>>1))<<1)); + nbpixels = width * height; + + if (PDP_BITMAP != header->type) return; + if (PDP_BITMAP_YV12 != encoding) return; + + /* check if xvimage needs to be recreated */ + if ((width != xvid->width) || (height != xvid->height)){ + //pdp_post("pdp_xv: replace image"); + pdp_xvideo_destroy_xvimage(xvid); + pdp_xvideo_create_xvimage(xvid, width, height); + } + + /* copy the data to the XvImage buffer */ + memcpy(xvid->data, data, size); + + /* display */ + XvPutImage(xvid->xdpy->dpy,xvid->xv_port, xwin->win,xwin->gc,xvid->xvi, + 0,0,xvid->width,xvid->height, 0,0,xwin->winwidth,xwin->winheight); + XFlush(xvid->xdpy->dpy); + + + +} + + + +void pdp_xvideo_close(t_pdp_xvideo* xvid) +{ + if (xvid->initialized){ + if (xvid->xvi) pdp_xvideo_destroy_xvimage(xvid); + XvUngrabPort(xvid->xdpy->dpy, xvid->xv_port, CurrentTime); + xvid->xv_port = 0; + xvid->xdpy = 0; + xvid->last_encoding = -1; + xvid->initialized = false; + } +} + +void pdp_xvideo_cleanup(t_pdp_xvideo* xvid) +{ + // close xvideo port (and delete XvImage) + pdp_xvideo_close(xvid); + + // no more dynamic data to free + +} + +void pdp_xvideo_free(t_pdp_xvideo* xvid){ + pdp_xvideo_cleanup(xvid); + pdp_dealloc(xvid); +} + +void pdp_xvideo_init(t_pdp_xvideo *xvid) +{ + + xvid->xdpy = 0; + + xvid->xv_format = FOURCC_YV12; + xvid->xv_port = 0; + + xvid->width = 320; + xvid->height = 240; + + xvid->data = 0; + xvid->xvi = 0; + + xvid->initialized = 0; + xvid->last_encoding = -1; + +} +t_pdp_xvideo *pdp_xvideo_new(void) +{ + t_pdp_xvideo *xvid = pdp_alloc(sizeof(*xvid)); + pdp_xvideo_init(xvid); + return xvid; +} + +int pdp_xvideo_open_on_display(t_pdp_xvideo *xvid, t_pdp_xdisplay *d) +{ + unsigned int ver, rel, req, ev, err, i, j; + unsigned int adaptors; + int formats; + XvAdaptorInfo *ai; + + if (xvid->initialized) return 1; + if (!d) return 0; + xvid->xdpy = d; + + if (Success != XvQueryExtension(xvid->xdpy->dpy,&ver,&rel,&req,&ev,&err)) return 0; + + /* find + lock port */ + if (Success != XvQueryAdaptors(xvid->xdpy->dpy,DefaultRootWindow(xvid->xdpy->dpy),&adaptors,&ai)) + return 0; + for (i = 0; i < adaptors; i++) { + if ((ai[i].type & XvInputMask) && (ai[i].type & XvImageMask)) { + for (j=0; j < ai[i].num_ports; j++){ + if (Success != XvGrabPort(xvid->xdpy->dpy,ai[i].base_id+j,CurrentTime)) { + //fprintf(stderr,"INFO: Xvideo port %ld on adapter %d: is busy, skipping\n",ai[i].base_id+j, i); + } + else { + xvid->xv_port = ai[i].base_id + j; + goto breakout; + } + } + } + } + + + breakout: + + XFree(ai); + if (0 == xvid->xv_port) return 0; + pdp_post("pdp_xvideo: grabbed port %d on adaptor %d", xvid->xv_port, i); + xvid->initialized = 1; + pdp_xvideo_create_xvimage(xvid, xvid->width, xvid->height); + return 1; +} + + diff --git a/system/X11/pdp_xwindow.c b/system/X11/pdp_xwindow.c new file mode 100644 index 0000000..9454dd7 --- /dev/null +++ b/system/X11/pdp_xwindow.c @@ -0,0 +1,623 @@ +/* + * Pure Data Packet system module. - x window glue code (fairly tied to pd and pdp) + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 code is fairly tied to pd and pdp. serves mainly as reusable glue code +// for pdp_xv, pdp_glx, pdp_3d_windowcontext, ... + + +#include <string.h> +#include "pdp_xwindow.h" +#include "pdp_post.h" +#include "pdp_debug.h" +#include "pdp_symbol.h" +#include "pdp_list.h" + +#define D if(0) + + +// xwin->xdisplay->screen = DefaultScreen(xwin->xdisplay->dpy); + +/* x display class +typedef struct _pdp_xdisplay +{ + Display *dpy; // the display connection + int screen; // the screen + t_pdp_list *windowlist; // all windows belonging to this connection + // this contains (xwindow object, eventlist) +} t_pdp_xdisplay; */ + + +/************************************* PDP_XDISPLAY ************************************/ + + +t_pdp_xdisplay *pdp_xdisplay_new(char *dpy_string) +{ + t_pdp_xdisplay *d = pdp_alloc(sizeof(*d)); + if (!(d->dpy = XOpenDisplay(dpy_string))){ + pdp_post ("pdp_xdisplay_new: can't open display %s", dpy_string); + pdp_dealloc(d); + return (0); + } + + + d->windowlist = pdp_list_new(0); + d->screen = DefaultScreen(d->dpy); + d->dragbutton = -1; + return d; +} + +void pdp_xdisplay_free(t_pdp_xdisplay *d) +{ + XCloseDisplay(d->dpy); + PDP_ASSERT(0 == d->windowlist->elements); // make sure there are no dangling xwindow objects + pdp_list_free(d->windowlist); + pdp_dealloc(d); +} + +/* some private members */ +static int _windowset_contains(t_pdp_xdisplay *d, t_pdp_xwindow *w) +{ + t_pdp_atom *a; + for (a=d->windowlist->first; a; a=a->next){ + if (w == a->w.w_list->first->w.w_pointer) return 1; + } + return 0; +} + +static void _windowset_add(t_pdp_xdisplay *d, t_pdp_xwindow *w) +{ + t_pdp_list *l = pdp_list_new(0); // a new list for this window + t_pdp_list *l_ev = pdp_list_new(0); // the event list + pdp_list_add_back_pointer(l, w); + pdp_list_add_back(l, a_list, (t_pdp_word)l_ev); + + pdp_list_add_back(d->windowlist, a_list, (t_pdp_word)l); +} + +/* get the list describing this window */ +static t_pdp_list *_windowset_get_info_for_Window(t_pdp_xdisplay *d, Window win) +{ + t_pdp_atom *a; + for (a=d->windowlist->first; a; a=a->next){ + if (win == ((t_pdp_xwindow *)a->w.w_list->first->w.w_pointer)->win) return a->w.w_list; + } + return 0; +} + +static t_pdp_list *_windowset_get_info(t_pdp_xdisplay *d, t_pdp_xwindow *w) +{ + t_pdp_atom *a; + for (a=d->windowlist->first; a; a=a->next){ + if (w == a->w.w_list->first->w.w_pointer) return a->w.w_list; + } + return 0; +} + +static void _windowset_remove(t_pdp_xdisplay *d, t_pdp_xwindow *w) +{ + t_pdp_list *l = _windowset_get_info(d, w); + if (l){ + pdp_list_remove(d->windowlist, a_list, (t_pdp_word)l); + pdp_tree_free(l); + } +} + +void pdp_xdisplay_register_window(t_pdp_xdisplay *d, t_pdp_xwindow *w) +{ + + if (!_windowset_contains(d, w)) _windowset_add(d, w); +} +void pdp_xdisplay_unregister_window(t_pdp_xdisplay *d, t_pdp_xwindow *w) +{ + if (_windowset_contains(d, w)) _windowset_remove(d, w); +} + + +/* LOCKING !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1111*/ +/* get events from display and store in queues */ +void pdp_xdisplay_get_events(t_pdp_xdisplay *d) +{ + + unsigned int i; + XEvent e; + + /* event tags */ + char tag_drag[] = "drag0"; + char tag_press[] = "press0"; + char tag_release[] = "release0"; + char tag_motion[] = "motion0"; + + char *BUT(char *c) {return c + strlen(c) - 1;} + + /* button chars */ + char *but_drag = BUT(tag_drag); + char *but_press = BUT(tag_press); + char *but_release = BUT(tag_release); + char *but_motion = BUT(tag_motion); + + int nbEvents = XEventsQueued(d->dpy, QueuedAlready); + int bmask = Button1Mask + | Button2Mask + | Button3Mask + | Button4Mask + | Button5Mask; + + + while (XPending(d->dpy)){ + XNextEvent(d->dpy, &e); + + + /* get the window info list for this X11 Window */ + t_pdp_list *winfo = _windowset_get_info_for_Window(d, e.xany.window); + + /* get the window object */ + t_pdp_xwindow *xwin = (t_pdp_xwindow *)winfo->first->w.w_pointer; + + /* get the event list corresponding to this window */ + t_pdp_list *eventlist = winfo->first->next->w.w_list; + + /* set dim scalers */ + float inv_x = 1.0f / (float)(xwin->winwidth); + float inv_y = 1.0f / (float)(xwin->winheight); + + /* list to store new event */ + t_pdp_list *newevent = 0; + + /* event tag */ + char *tag; + char *but; + + + /* handle event */ + switch(e.type){ + case ConfigureNotify: + /* store new dimensions */ + xwin->winwidth = e.xconfigure.width; + xwin->winheight = e.xconfigure.height; + break; + + case ClientMessage: + if ((Atom)e.xclient.data.l[0] == xwin->WM_DELETE_WINDOW) { + newevent = pdp_list_new(1); + pdp_list_set_0(newevent, a_symbol, (t_pdp_word)pdp_gensym("close")); + pdp_list_add_back(eventlist, a_list, (t_pdp_word)newevent); + } + break; + + case KeyPress: + case KeyRelease: + newevent = pdp_list_new(2); + pdp_list_set_0(newevent, a_symbol, (t_pdp_word)pdp_gensym(e.type == KeyPress ? "keypress" : "keyrelease")); + pdp_list_set_1(newevent, a_int, (t_pdp_word)(int)e.xkey.keycode); + pdp_list_add_back(eventlist, a_list, (t_pdp_word)newevent); + break; + + case ButtonPress: + case ButtonRelease: + /* event specific stuff */ + if (e.type == ButtonPress){ + tag = tag_press; + but = but_press; + } + else { + tag = tag_release; + but = but_release; + } + + /* send generic event */ + *but = 0; + newevent = pdp_list_new(3); + pdp_list_set_0(newevent, a_symbol, (t_pdp_word)pdp_gensym(tag)); + pdp_list_set_1(newevent, a_float, (t_pdp_word)(inv_x * (float)e.xbutton.x)); + pdp_list_set_2(newevent, a_float, (t_pdp_word)(inv_y * (float)e.xbutton.y)); + pdp_list_add_back(eventlist, a_list, (t_pdp_word)newevent); + + /* send button specific event */ + *but = '1' + e.xbutton.button - Button1; + newevent = pdp_list_new(3); + pdp_list_set_0(newevent, a_symbol, (t_pdp_word)pdp_gensym(tag)); + pdp_list_set_1(newevent, a_float, (t_pdp_word)(inv_x * (float)e.xbutton.x)); + pdp_list_set_2(newevent, a_float, (t_pdp_word)(inv_y * (float)e.xbutton.y)); + pdp_list_add_back(eventlist, a_list, (t_pdp_word)newevent); + + /* save drag button */ + xwin->lastbut = *but; + + break; + + case MotionNotify: + if (e.xbutton.state & bmask){ + /* button is down: it is a drag event */ + tag = tag_drag; + but = but_drag; + + /* send generic event */ + *but = 0; + newevent = pdp_list_new(3); + pdp_list_set_0(newevent, a_symbol, (t_pdp_word)pdp_gensym(tag)); + pdp_list_set_1(newevent, a_float, (t_pdp_word)(inv_x * (float)e.xbutton.x)); + pdp_list_set_2(newevent, a_float, (t_pdp_word)(inv_y * (float)e.xbutton.y)); + pdp_list_add_back(eventlist, a_list, (t_pdp_word)newevent); + + /* send button specific event */ + *but = xwin->lastbut; + newevent = pdp_list_new(3); + pdp_list_set_0(newevent, a_symbol, (t_pdp_word)pdp_gensym(tag)); + pdp_list_set_1(newevent, a_float, (t_pdp_word)(inv_x * (float)e.xbutton.x)); + pdp_list_set_2(newevent, a_float, (t_pdp_word)(inv_y * (float)e.xbutton.y)); + pdp_list_add_back(eventlist, a_list, (t_pdp_word)newevent); + + } + else { + tag = tag_motion; + but = but_motion; + *but = 0; + + /* send generic event */ + newevent = pdp_list_new(3); + pdp_list_set_0(newevent, a_symbol, (t_pdp_word)pdp_gensym(tag)); + pdp_list_set_1(newevent, a_float, (t_pdp_word)(inv_x * (float)e.xbutton.x)); + pdp_list_set_2(newevent, a_float, (t_pdp_word)(inv_y * (float)e.xbutton.y)); + pdp_list_add_back(eventlist, a_list, (t_pdp_word)newevent); + + } + + + + default: + //pdp_post("pdp_xv: unknown event"); + break; + } + + + } + + +} + + +/* return a list containing event lists */ + +t_pdp_list *pdp_xdisplay_get_events_for_window(t_pdp_xdisplay *d, t_pdp_xwindow *w) +{ + t_pdp_list *info = _windowset_get_info(d, w); + t_pdp_list *eventlist; + PDP_ASSERT(info); + + /* get all pending events from display */ + pdp_xdisplay_get_events(d); + + /* get the event list for this window and create a new one */ + eventlist = info->first->next->w.w_list; + info->first->next->w.w_list = pdp_list_new(0); + + return eventlist; + +} + + +/************************************* PDP_XWINDOW ************************************/ + +void pdp_xwindow_warppointer(t_pdp_xwindow *xwin, int x, int y) +{ + if (xwin->initialized){ + XWarpPointer(xwin->xdisplay->dpy, None, xwin->win, 0, 0, 0, 0, x, y); + } +} + + + + +static void pdp_xwindow_overrideredirect(t_pdp_xwindow *xwin, int b) +{ + XSetWindowAttributes new_attr; + new_attr.override_redirect = b ? True : False; + XChangeWindowAttributes(xwin->xdisplay->dpy, xwin->win, CWOverrideRedirect, &new_attr); + //XFlush(xwin->xdisplay->dpy); + +} + + +void pdp_xwindow_moveresize(t_pdp_xwindow *xwin, int xoffset, int yoffset, int width, int height) +{ + + D pdp_post("_pdp_xwindow_moveresize"); + if ((width > 0) && (height > 0)){ + xwin->winwidth = width; + xwin->winheight = height; + xwin->winxoffset = xoffset; + xwin->winyoffset = yoffset; + + if (xwin->initialized){ + XMoveResizeWindow(xwin->xdisplay->dpy, xwin->win, xoffset, yoffset, width, height); + XFlush(xwin->xdisplay->dpy); + } + } +} + + +void pdp_xwindow_fullscreen(t_pdp_xwindow *xwin) +{ + XWindowAttributes rootwin_attr; + + D pdp_post("pdp_xwindow_fullscreen"); + + /* hmm.. fullscreen and xlib the big puzzle.. + if it looks like a hack it is a hack. */ + + if (xwin->initialized){ + + XGetWindowAttributes(xwin->xdisplay->dpy, RootWindow(xwin->xdisplay->dpy, xwin->xdisplay->screen), &rootwin_attr ); + + //pdp_xwindow_overrideredirect(xwin, 0); + pdp_xwindow_moveresize(xwin, 0, 0, rootwin_attr.width, rootwin_attr.height); + //pdp_xwindow_overrideredirect(xwin, 1); + //XRaiseWindow(xwin->xdisplay->dpy, xwin->win); + //pdp_xwindow_moveresize(xwin, 0, 0, rootwin_attr.width, rootwin_attr.height); + //pdp_xwindow_overrideredirect(xwin, 0); + + + + + } +} + + +void pdp_xwindow_tile(t_pdp_xwindow *xwin, int x_tiles, int y_tiles, int i, int j) +{ + XWindowAttributes rootwin_attr; + XSetWindowAttributes new_attr; + + D pdp_post("pdp_xwindow_fullscreen"); + + if (xwin->initialized){ + int tile_w; + int tile_h; + XGetWindowAttributes(xwin->xdisplay->dpy, RootWindow(xwin->xdisplay->dpy, xwin->xdisplay->screen), &rootwin_attr ); + + tile_w = rootwin_attr.width / x_tiles; + tile_h = rootwin_attr.height / y_tiles; + + xwin->winwidth = (x_tiles-1) ? rootwin_attr.width - (x_tiles-1)*tile_w : tile_w; + xwin->winheight = (y_tiles-1) ? rootwin_attr.height - (y_tiles-1)*tile_h : tile_h; + xwin->winxoffset = i * tile_w; + xwin->winyoffset = j * tile_h; + + //new_attr.override_redirect = True; + //XChangeWindowAttributes(xwin->xdisplay->dpy, xwin->win, CWOverrideRedirect, &new_attr ); + XMoveResizeWindow(xwin->xdisplay->dpy, xwin->win, xwin->winxoffset, xwin->winyoffset, xwin->winwidth, xwin->winheight); + + } +} + +/* resize window */ +void pdp_xwindow_resize(t_pdp_xwindow *xwin, int width, int height) +{ + D pdp_post("pdp_xwindow_resize"); + if ((width > 0) && (height > 0)){ + xwin->winwidth = width; + xwin->winheight = height; + if (xwin->initialized){ + XResizeWindow(xwin->xdisplay->dpy, xwin->win, width, height); + XFlush(xwin->xdisplay->dpy); + } + } + //_pdp_xwindow_moveresize(xwin, xwin->winxoffset, xwin->winyoffset, width, height); +} + +/* move window */ +void pdp_xwindow_move(t_pdp_xwindow *xwin, int xoffset, int yoffset) +{ + D pdp_post("pdp_xwindow_move"); + pdp_xwindow_moveresize(xwin, xoffset, yoffset, xwin->winwidth, xwin->winheight); +} + +/* send events to a pd outlet (don't call this outside the pd thread) */ +t_pdp_list *pdp_xwindow_get_eventlist(t_pdp_xwindow *xwin) +{ + t_pdp_list *eventlist; + + eventlist = pdp_xdisplay_get_events_for_window(xwin->xdisplay, xwin); + D pdp_list_print(eventlist); + + return eventlist; + +} + + + +/* set an arbitrary cursor image */ +void pdp_xwindow_cursor_image(t_pdp_xwindow *xwin, char *data, int width, int height) +{ + if (!xwin->initialized) return; + + Cursor cursor; + Pixmap pm; + XColor fg; + XColor bg; + + fg.red = fg.green = fg.blue = 0xffff; + bg.red = bg.green = bg.blue = 0x0000; + + pm = XCreateBitmapFromData(xwin->xdisplay->dpy, xwin->win, data, width, height); + cursor = XCreatePixmapCursor(xwin->xdisplay->dpy, pm, pm, &fg, + &bg, width/2, height/2); + XFreePixmap(xwin->xdisplay->dpy, pm); + XDefineCursor(xwin->xdisplay->dpy, xwin->win,cursor); +} + +/* enable / disable cursor */ +void pdp_xwindow_cursor(t_pdp_xwindow *xwin, int i){ + if (!xwin->initialized) return; + if (i == 0) { + char data[] = {0}; + pdp_xwindow_cursor_image(xwin, data, 1, 1); + } + else + XUndefineCursor(xwin->xdisplay->dpy, xwin->win); + + xwin->cursor = i; +} + + +void pdp_xwindow_title(t_pdp_xwindow *xwin, char *title) +{ + if (xwin->initialized) + XStoreName(xwin->xdisplay->dpy, xwin->win, title); +} + + +/* create xwindow */ +int pdp_xwindow_create_on_display(t_pdp_xwindow *xwin, t_pdp_xdisplay *d) +{ + XEvent e; + unsigned int i; + + /* check if already opened */ + if( xwin->initialized ){ + pdp_post("pdp_xwindow_create_on_display: window already created"); + goto exit; + } + + xwin->xdisplay = d; + PDP_ASSERT(xwin->xdisplay); + + /* create a window */ + xwin->win = XCreateSimpleWindow( + xwin->xdisplay->dpy, + RootWindow(xwin->xdisplay->dpy, xwin->xdisplay->screen), xwin->winxoffset, xwin->winyoffset, xwin->winwidth, xwin->winheight, 0, + BlackPixel(xwin->xdisplay->dpy, xwin->xdisplay->screen), + BlackPixel(xwin->xdisplay->dpy, xwin->xdisplay->screen)); + + + /* enable handling of close window event */ + xwin->WM_DELETE_WINDOW = XInternAtom(xwin->xdisplay->dpy, "WM_DELETE_WINDOW", True); + (void)XSetWMProtocols(xwin->xdisplay->dpy, xwin->win, &xwin->WM_DELETE_WINDOW, 1); + + if(!(xwin->win)){ + /* clean up mess */ + pdp_post("pdp_xwindow_create_on_display: could not create window. closing.\n"); + //XCloseDisplay(xwin->xdisplay->dpy); NOT OWNER + xwin->xdisplay = 0; + xwin->initialized = 0; + goto exit; + } + + /* select input events */ + XSelectInput(xwin->xdisplay->dpy, xwin->win, + StructureNotifyMask + | KeyPressMask + | KeyReleaseMask + | ButtonPressMask + | ButtonReleaseMask + | MotionNotify + | PointerMotionMask); + // | ButtonMotionMask); + //XSelectInput(xwin->xdisplay->dpy, xwin->win, StructureNotifyMask); + + + + /* map */ + XMapWindow(xwin->xdisplay->dpy, xwin->win); + + /* create graphics context */ + xwin->gc = XCreateGC(xwin->xdisplay->dpy, xwin->win, 0, 0); + + /* catch mapnotify */ + for(;;){ + XNextEvent(xwin->xdisplay->dpy, &e); + if (e.type == MapNotify) break; + } + + + /* we're done initializing */ + xwin->initialized = 1; + + /* disable/enable cursor */ + pdp_xwindow_cursor(xwin, xwin->cursor); + + /* set window title */ + pdp_xwindow_title(xwin, "pdp"); + + /* register window for events */ + /* TODO: move event selection ETC to xdisplay object */ + + pdp_xdisplay_register_window(xwin->xdisplay, xwin); + + exit: + return xwin->initialized; + +} + +void pdp_xwindow_init(t_pdp_xwindow *xwin) +{ + xwin->xdisplay = 0; + + xwin->winwidth = 320; + xwin->winheight = 240; + xwin->winxoffset = 0; + xwin->winyoffset = 0; + + xwin->initialized = 0; + + xwin->cursor = 0; + //xwin->dragbutton = gensym("drag1"); + +} +t_pdp_xwindow *pdp_xwindow_new(void) +{ + t_pdp_xwindow *xwin = pdp_alloc(sizeof(*xwin)); + pdp_xwindow_init(xwin); + return xwin; +} + + +void pdp_xwindow_close(t_pdp_xwindow *xwin) +{ + + XEvent e; + + if (xwin->initialized){ + XFreeGC(xwin->xdisplay->dpy, xwin->gc); + XDestroyWindow(xwin->xdisplay->dpy, xwin->win); + while(XPending(xwin->xdisplay->dpy)) XNextEvent(xwin->xdisplay->dpy, &e); + pdp_xdisplay_unregister_window(xwin->xdisplay, xwin); + xwin->xdisplay = 0; + xwin->initialized = 0; + } + +} + +void pdp_xwindow_cleanup(t_pdp_xwindow *x) +{ + // close win + pdp_xwindow_close(x); + + // no more dynamic data to free +} + +void pdp_xwindow_free(t_pdp_xwindow *xwin) +{ + pdp_xwindow_cleanup(xwin); + pdp_dealloc(xwin); +} + + diff --git a/system/image/Makefile b/system/image/Makefile new file mode 100644 index 0000000..f9ed52c --- /dev/null +++ b/system/image/Makefile @@ -0,0 +1,21 @@ +include ../../Makefile.config + +all: $(PDP_TARGET) + +OBJECTS = pdp_llconv.o pdp_resample.o pdp_imageproc_common.o + +OBJECTS_MMX = pdp_imageproc_mmx.o pdp_llconv_mmx.o +OBJECTS_PORTABLE = pdp_imageproc_portable.o pdp_llconv_portable.o + + + + +linux_mmx: $(OBJECTS_MMX) $(OBJECTS) + +linux: $(OBJECTS_PORTABLE) $(OBJECTS) + +darwin: $(OBJECTS_PORTABLE) $(OBJECTS) + +clean: + rm -f *~ + rm -f *.o diff --git a/system/image/pdp_imageproc_common.c b/system/image/pdp_imageproc_common.c new file mode 100644 index 0000000..184c418 --- /dev/null +++ b/system/image/pdp_imageproc_common.c @@ -0,0 +1,610 @@ +/* + * Pure Data Packet. common image processing routines. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 file contains common code for (portable) low level image processing objects + pdp_imageproc_* methods + The rest is int pdp_imageproc_<platform>.c + + There are also highlevel dispatcher methods that operate on packets: + pdp_imageproc_dispatch_* methods + +*/ + +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include "pdp_imageproc.h" +#include "pdp_image.h" +#include "pdp_mem.h" +#include "pdp_packet.h" + +#define CLAMP16(x) (((x) > 0x7fff) ? 0x7fff : (((x) < -0x7fff) ? -0x7fff : (x))) + +u32 pdp_imageproc_legalwidth(int i) +{ + if (i>1024) return 1024; + if (i>0) return ((((i-1)>>3)+1)<<3); + return 8; + +} + +u32 pdp_imageproc_legalheight(int i) +{ + if (i>1024) return 1024; + if (i>0) return ((((i-1)>>3)+1)<<3); + return 8; +} +u32 pdp_imageproc_legalwidth_round_down(int i) +{ + if (i>1024) return 1024; + if (i>8) return ((i>>3)<<3); + return 8; + +} + +u32 pdp_imageproc_legalheight_round_down(int i) +{ + if (i>1024) return 1024; + if (i>8) return ((i>>3)<<3); + return 8; +} + + +/* check if two packets are allocated and of the same type */ +bool pdp_packet_compat(int packet0, int packet1) +{ + + t_pdp *header0 = pdp_packet_header(packet0); + t_pdp *header1 = pdp_packet_header(packet1); + if (!(header1)) return 0; + if (!(header0)) return 0; + if (header0->type != header1->type) return 0; + return 1; +} + +/* some operations */ + +/* logic operators */ + +void pdp_imageproc_xor_process(void *x, u32 width, u32 height, s16 *image, s16 *image2) +{ + u32 *plane = (u32 *)image; + u32 *plane2 = (u32 *)image2; + int count = (width * height) >> 1; + int i; + + for (i=0; i<count; i++){ + plane[i] ^= plane2[i]; + } +} + +void pdp_imageproc_and_process(void *x, u32 width, u32 height, s16 *image, s16 *image2) +{ + u32 *plane = (u32 *)image; + u32 *plane2 = (u32 *)image2; + int count = (width * height) >> 1; + int i; + + for (i=0; i<count; i++){ + plane[i] &= plane2[i]; + } +} + +void pdp_imageproc_or_process(void *x, u32 width, u32 height, s16 *image, s16 *image2) +{ + u32 *plane = (u32 *)image; + u32 *plane2 = (u32 *)image2; + int count = (width * height) >> 1; + int i; + + for (i=0; i<count; i++){ + plane[i] |= plane2[i]; + } +} + +void pdp_imageproc_not_process(void *x, u32 width, u32 height, s16 *image) +{ + u32 *plane = (u32 *)image; + int count = (width * height) >> 1; + int i; + + for (i=0; i<count; i++){ + plane[i] ^= 0xffffffff; + } +} + +void pdp_imageproc_mask_process(void *x, u32 width, u32 height, s16 *image) +{ + u32 mask = (u32)x; + u32 *plane = (u32 *)image; + int count = (width * height) >> 1; + int i; + + mask = (mask & 0xffff) | (mask << 16); + + for (i=0; i<count; i++){ + plane[i] &= mask; + } +} + +// produce a plasma image +// note: random number generator can be platform specific +// however, it should be seeded. (same seed produces the same result) + +typedef struct +{ + u32 seed; + s32 scale; +} t_plasma; + +static inline s16 _rand_s16(void) +{ + return (s16)(random()<<0); +} + +static inline s16 _new_color(s32 one, s32 two, s32 scale) +{ + return CLAMP16((one >> 1) + (two >> 1) + ((scale * _rand_s16()) >> 16)); + //return (one >> 1) + (two >> 1); +} + +void *pdp_imageproc_plasma_new(void){return pdp_alloc(sizeof(t_plasma));} +void pdp_imageproc_plasma_delete(void *x){pdp_dealloc(x);} +void pdp_imageproc_plasma_setseed(void *x, float seed) +{ + *((float *)x) = seed; +} +void pdp_imageproc_plasma_setturbulence(void *x, float f) +{ + ((t_plasma *)x)->scale = CLAMP16(f * ((float)0x7fff)); +} + +static void _plasma_subdiv(u32 w, u32 h, u32 s, s16 *image, int calc_left, int calc_top, s32 scale) +{ + int w0 = ((w-1)>>1); // width of left segments + int h0 = ((h-1)>>1); // heigth of top segments + int w1 = w - w0; + int h1 = h - h0; + + /* conditions: w0 <= w1, h0 <= h1 */ + + /* original coordinates */ + int topleft = 0; + int topright = w-1; + int bottomleft = s * (h-1); + int bottomright = bottomleft + topright; + + /* new subdivision coordinates */ + int top = w0; + int left = s * h0; + int bottom = bottomleft + w0; + int right = topright + left; + int center = left + top; + + if (w0 && h0){ /* left-right and top-bottom subdivide */ + + /* calculate corner pixel colours */ + if (calc_top) image[top] = _new_color(image[topleft], image[topright], scale); + if (calc_left) image[left] = _new_color(image[topleft], image[bottomleft], scale); + image[right] = _new_color(image[topright], image[bottomright], scale); + image[bottom] = _new_color(image[bottomleft], image[bottomright], scale); + image[center] = (_new_color(image[top], image[bottom], scale) >> 1) + +(_new_color(image[left], image[right], scale) >> 1); + + + /* subdivide (with overlap) */ + _plasma_subdiv(w0+1, h0+1, s, &image[topleft], 1, 1, scale); + _plasma_subdiv(w1, h0+1, s, &image[top], 0, 1, scale); + _plasma_subdiv(w0+1, h1, s, &image[left], 1, 0, scale); + _plasma_subdiv(w1, h1, s, &image[center], 0, 0, scale); + + } + + + else if(h0) { /* top-bottom subdivide */ + + //post("h:%d", h); + + /* calculate corner pixel colours */ + if(calc_left) image[left] = _new_color(image[topleft], image[bottomleft], scale); + image[right] = _new_color(image[topright], image[bottomright], scale); + + /* subdivide (without overlap) */ + _plasma_subdiv(w, h0+1, s, &image[topleft], 1, 0, scale); + _plasma_subdiv(w, h1, s, &image[left], 1, 0, scale); + + } + + else if (w0){ /* left-right subdivide */ + + /* calculate corner pixel colours */ + if (calc_top) image[top] = _new_color(image[topleft], image[topright], scale); + image[bottom] = _new_color(image[bottomleft], image[bottomright],scale); + + /* subdivide with overlap */ + _plasma_subdiv(w0+1, h, s, &image[topleft], 0, 1, scale); + _plasma_subdiv(w1, h, s, &image[top], 0, 1, scale); + + } + +} + +void pdp_imageproc_plasma_process(void *x, u32 width, u32 height, s16 *image) +{ + s32 scale = (((t_plasma *)x)->scale); + srandom (((t_plasma *)x)->seed); + + /* set initial border colours */ + image[0] = _rand_s16(); + image[width-1] = _rand_s16(); + image[width * (height-1)] = _rand_s16(); + image[width * height - 1] = _rand_s16(); + + /* subdivide */ + _plasma_subdiv(width, height, width, image, 1, 1, scale); + + ((t_plasma *)x)->seed = random(); + +} + + + +void pdp_imageproc_zero_process(void *x, u32 width, u32 height, s16 *image) +{ + int bytesize = (width * height) << 1; + memset(image, 0, bytesize); +} + +void pdp_imageproc_constant_process(void *x, u32 width, u32 height, s16 *image) +{ + int i; + u32 value = (u32)x; + u32 *plane = (u32 *)image; + int wordsize = (width * height) >> 1; + value = (value & 0xffff) | (value << 16); + for (i=0; i<wordsize; i++){ + plane[i] = value; + } +} + + +/* other stateless operators */ + +/* some 2x16bit vector ops */ + +/* some bit shuffling to ensure 32 bit accesses + get the sign bit extended as a mask: - : 0xffff +: 0x0000 */ +static inline u32 _sign(s32 invec) +{ + s32 mask_top = invec; + s32 mask_bot = invec; + + mask_top &= 0x80000000; /* isolate top sign bit */ + mask_bot <<= 16; /* shift bottom word to top word */ + mask_bot &= 0x80000000; /* isolate bottom sign bit */ + mask_top >>= 15; /* shift sign bit into top word */ + mask_bot >>= 15; + mask_bot = (s32)(((u32)mask_bot) >> 16); /* shift top word into bottom word */ + return mask_top |mask_bot; +} + +/* clear the least significant bit of the top word + to ensure a decoupled vector add */ +static inline void _decouple(s32 *invec) +{ + *invec &= 0xfffeffff; +} + +void pdp_imageproc_abs_process(void *x, u32 width, u32 height, s16 *image) +{ + int i; + s32 *wimage = (s32 *)image; + int wsize = (width * height) >> 1; + for (i=0; i<wsize; i++){ + /* this computes c = (c >= 0) ? (c) : (~c) */ + /* not is used instead of neg to prevent overflow on 0x8000 */ + /* this maps both 0 and -1 to 0 */ + + wimage[i] ^= _sign(wimage[i]); + + } +} + +void pdp_imageproc_zthresh_process(void *x, u32 width, u32 height, s16 *image) +{ + int i; + s32 *wimage = (s32 *)image; + int wsize = (width * height) >> 1; + for (i=0; i<wsize; i++){ + /* this computes c = (c >= 0) ? (c) : (0) */ + wimage[i] &= ~_sign(wimage[i]); + } +} + +/* hard thresholding: x contains a positive unsigned short int */ +void pdp_imageproc_hardthresh_process(void *x, u32 width, u32 height, s16 *image) +{ + int i; + s32 thresh = (s32)x; + s32 sign1, isign2, a; + s32 *wimage = (s32 *)image; + int wsize = (width * height) >> 1; + thresh |= (thresh << 16); + for (i=0; i<wsize; i++){ + a = wimage[i]; + sign1 = _sign(a); + a ^= sign1; /* take abs */ + _decouple(&a); + a -= thresh; /* subtract threshold */ + isign2 = ~ _sign(a); + a &= isign2; /* zero thresh */ + _decouple(&a); + a += thresh & isign2; /* add threshold (if not zero thresholded)*/ + a ^= sign1; + wimage[i] = a; + } +} + +/* soft thresholding: x contains a positive unsigned short int */ +void pdp_imageproc_softthresh_process(void *x, u32 width, u32 height, s16 *image) +{ + int i; + s32 thresh = (s32)x; + s32 sign1, sign2, a; + s32 *wimage = (s32 *)image; + int wsize = (width * height) >> 1; + thresh |= thresh << 16; + for (i=0; i<wsize; i++){ + a = wimage[i]; + sign1 = _sign(a); + a ^= sign1; /* take abs */ + _decouple(&a); + a -= thresh; /* subtract threshold */ + sign2 = _sign(a); + a &= ~ sign2; /* zero thresh */ + _decouple(&a); + //a += thresh; /* add threshold */ + a ^= sign1; + wimage[i] = a; + + } + +} + + +/* turns an image into a positive andmask */ +void pdp_imageproc_ispositive_process(void *x, u32 width, u32 height, s16 *image) +{ + int i; + s32 *wimage = (s32 *)image; + int wsize = (width * height) >> 1; + for (i=0; i<wsize; i++){ + wimage[i] = ~_sign(wimage[i]); + } + +} + +/* get sign */ +void pdp_imageproc_sign_process(void *x, u32 width, u32 height, s16 *image) +{ + int i; + s32 *wimage = (s32 *)image; + int wsize = (width * height) >> 1; + for (i=0; i<wsize; i++){ + wimage[i] = _sign(wimage[i]) ^ 0x7fff7fff; + } + +} + +/* flip left <-> right */ +void pdp_imageproc_flip_lr_process(void *dummy, u32 width, u32 height, s16 *image) +{ + u32 y; + s16 tmp, *l, *r; + for (y=0; y<height; y++){ + l = image; + r = image + width - 1; + while (l < r){ + tmp = *l; + *l = *r; + *r = tmp; + l++; + r--; + } + image += width; + } + +} + +void pdp_llconv_flip_top_bottom(s16 *data, int width, int height, int pixelsize); + +void pdp_imageproc_flip_tb_process(void *dummy, u32 width, u32 height, s16 *image) +{ + pdp_llconv_flip_top_bottom(image, width, height, 2); +} + + +/* image processing dispatcher methods */ +/* if the first packet contains a nonzero channel mask, it will be used instead + of the one supplied as argument to the dispatcher functions. + the packet's channel mask will be reset to 0 */ + +void pdp_imageproc_dispatch_1buf(void (*process_routine)(void*, u32, u32, s16*), void *x, u32 chanmask, int packet0) +{ + t_pdp *header0; + t_image *image0; + s16 *idata0; + unsigned int w,h,d,plane_size,mask; + + /* if packet is not a valid image return without doing anything */ + if (!(pdp_packet_image_isvalid(packet0))) return; + + header0 = pdp_packet_header(packet0); + image0 = pdp_packet_image_info(packet0); + idata0 = pdp_packet_data (packet0); + + w = image0->width; + h = image0->height; + d = image0->depth; + plane_size = w*h; + + if (image0->chanmask) chanmask = image0->chanmask; + image0->chanmask = 0; + + + switch(image0->encoding){ + case PDP_IMAGE_GREY: + if (chanmask & 1) (*process_routine)(x, w, h, idata0); + break; + case PDP_IMAGE_YV12: + if (chanmask & 1) (*process_routine)(x, w, h, idata0); + idata0 += plane_size; + plane_size >>= 2; + w >>= 1; + h >>= 1; + if (chanmask & 2) (*process_routine)(x, w, h, idata0); + idata0 += plane_size; + if (chanmask & 4) (*process_routine)(x, w, h, idata0); + break; + case PDP_IMAGE_MCHP: + mask = 1; + while (d--){ + if (chanmask & mask) (*process_routine)(x, w, h, idata0); + idata0 += plane_size; + mask <<= 1; + } + break; + default: + break; + } +} + + +void pdp_imageproc_dispatch_2buf(void (*process_routine)(void*, u32, u32, s16*, s16 *), void *x, u32 chanmask, int packet0, int packet1) +{ + t_pdp *header0; + t_image *image0; + s16 *idata0, *idata1; + unsigned int w,h,d,plane_size,mask; + + /* if packets are not compatible images, return without doing anything */ + if (!(pdp_packet_image_compat(packet0, packet1))) return; + + header0 = pdp_packet_header(packet0); + image0 = pdp_packet_image_info(packet0); + idata0 = pdp_packet_data (packet0); + idata1 = pdp_packet_data (packet1); + + w = image0->width; + h = image0->height; + d = image0->depth; + plane_size = w*h; + + if (image0->chanmask) chanmask = image0->chanmask; + image0->chanmask = 0; + + switch(image0->encoding){ + case PDP_IMAGE_GREY: + if (chanmask & 1) (*process_routine)(x, w, h, idata0, idata1); + break; + case PDP_IMAGE_YV12: + if (chanmask & 1) (*process_routine)(x, w, h, idata0, idata1); + idata0 += plane_size; + idata1 += plane_size; + plane_size >>= 2; + w >>= 1; + h >>= 1; + if (chanmask & 2) (*process_routine)(x, w, h, idata0, idata1); + idata0 += plane_size; + idata1 += plane_size; + if (chanmask & 4) (*process_routine)(x, w, h, idata0, idata1); + break; + case PDP_IMAGE_MCHP: + mask = 1; + while (d--){ + if (chanmask & mask) (*process_routine)(x, w, h, idata0, idata1); + idata0 += plane_size; + idata1 += plane_size; + mask <<= 1; + } + break; + default: + break; + } +} +void pdp_imageproc_dispatch_3buf(void (*process_routine)(void*, u32, u32, s16*, s16 *, s16 *), void *x, u32 chanmask, int packet0, int packet1, int packet2) +{ + t_pdp *header0; + t_image *image0; + s16 *idata0, *idata1, *idata2; + unsigned int w,h,d,plane_size, mask; + + /* if packets are not compatible images, return without doing anything */ + if (!((pdp_packet_image_compat(packet0, packet1)) + &&(pdp_packet_image_compat(packet0, packet1)))) return; + + header0 = pdp_packet_header(packet0); + image0 = pdp_packet_image_info(packet0); + idata0 = pdp_packet_data (packet0); + idata1 = pdp_packet_data (packet1); + idata2 = pdp_packet_data (packet2); + + w = image0->width; + h = image0->height; + d = image0->depth; + plane_size = w*h; + + if (image0->chanmask) chanmask = image0->chanmask; + image0->chanmask = 0; + + switch(image0->encoding){ + case PDP_IMAGE_GREY: + if (chanmask & 1)(*process_routine)(x, w, h, idata0, idata1, idata2); + break; + case PDP_IMAGE_YV12: + if (chanmask & 1)(*process_routine)(x, w, h, idata0, idata1, idata2); + idata0 += plane_size; + idata1 += plane_size; + idata2 += plane_size; + plane_size >>= 2; + w >>= 1; + h >>= 1; + if (chanmask & 2)(*process_routine)(x, w, h, idata0, idata1, idata2); + idata0 += plane_size; + idata1 += plane_size; + idata2 += plane_size; + if (chanmask & 4)(*process_routine)(x, w, h, idata0, idata1, idata2); + break; + case PDP_IMAGE_MCHP: + mask = 1; + while (d--){ + if (chanmask & mask) (*process_routine)(x, w, h, idata0, idata1, idata2); + idata0 += plane_size; + idata1 += plane_size; + idata2 += plane_size; + mask <<= 1; + } + break; + default: + break; + } +} diff --git a/system/image/pdp_imageproc_mmx.c b/system/image/pdp_imageproc_mmx.c new file mode 100644 index 0000000..67f6e77 --- /dev/null +++ b/system/image/pdp_imageproc_mmx.c @@ -0,0 +1,594 @@ +/* + * Pure Data Packet. c wrapper for mmx image processing routines. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 is a c wrapper around platform specific (mmx) code */ +#include <stdlib.h> +#include <math.h> +#include "pdp_mmx.h" +#include "pdp_imageproc.h" + +/* pdp memory alloc/dealloc prototype */ +void *pdp_alloc(int size); +void pdp_dealloc(void *); + +// utility stuff +inline static s16 float2fixed(float f) +{ + if (f > 1) f = 1; + if (f < -1) f = -1; + f *= 0x7fff; + return (s16)f; +} + +inline static void setvec(s16 *v, float f) +{ + s16 a = float2fixed(f); + v[0] = a; + v[1] = a; + v[2] = a; + v[3] = a; +} + + + +// add two images +void pdp_imageproc_add_process(void *x, u32 width, u32 height, s16 *image, s16 *image2) +{ + unsigned int totalnbpixels = width * height; + pixel_add_s16(image, image2, totalnbpixels>>2); +} + +// mul two images +void pdp_imageproc_mul_process(void *x, u32 width, u32 height, s16 *image, s16 *image2) +{ + unsigned int totalnbpixels = width * height; + pixel_mul_s16(image, image2, totalnbpixels>>2); +} + + +// mix 2 images +#define MIX_SIZE 8*sizeof(s16) +void *pdp_imageproc_mix_new(void){return pdp_alloc(MIX_SIZE);} +int pdp_imageproc_mix_nb_stackwords(void){return PDP_IMAGEPROC_NB_STACKWORDS(MIX_SIZE);} +void pdp_imageproc_mix_delete(void *x) {pdp_dealloc (x);} +void pdp_imageproc_mix_setleftgain(void *x, float gain){setvec((s16 *)x, gain);} +void pdp_imageproc_mix_setrightgain(void *x, float gain){setvec((s16 *)x + 4, gain);} +void pdp_imageproc_mix_process(void *x, u32 width, u32 height, s16 *image, s16 *image2) +{ + s16 *d = (s16 *)x; + unsigned int totalnbpixels = width * height; + pixel_mix_s16(image, image2, totalnbpixels>>2, d, d+4); +} + + +// random mix 2 images +#define RANDMIX_SIZE 8*sizeof(s16) +void *pdp_imageproc_randmix_new(void){return pdp_alloc(RANDMIX_SIZE);} +int pdp_imageproc_randmix_nb_stackwords(void) {return PDP_IMAGEPROC_NB_STACKWORDS(RANDMIX_SIZE);} +void pdp_imageproc_randmix_delete(void *x) {pdp_dealloc (x);} +void pdp_imageproc_randmix_setthreshold(void *x, float threshold){setvec((s16 *)x, 2*threshold-1);} +void pdp_imageproc_randmix_setseed(void *x, float seed) +{ + s16 *d = (s16 *)x; + srandom((u32)seed); + d[4] = (s16)random(); + d[5] = (s16)random(); + d[6] = (s16)random(); + d[7] = (s16)random(); + +} +void pdp_imageproc_randmix_process(void *x, u32 width, u32 height, s16 *image, s16 *image2) +{ + s16 *d = (s16 *)x; + unsigned int totalnbpixels = width * height; + pixel_randmix_s16(image, image2, totalnbpixels>>2, d+4, d); +} + + +// 3x1 or 1x3 in place convolution +// orientation +typedef struct +{ + s16 min1[4]; + s16 zero[4]; + s16 plus1[4]; + s16 border[4]; + u32 orientation; + u32 nbpasses; +} t_conv; +void *pdp_imageproc_conv_new(void){return(pdp_alloc(sizeof(t_conv)));} +void pdp_imageproc_conv_delete(void *x){pdp_dealloc(x);} +void pdp_imageproc_conv_setmin1(void *x, float val){setvec(((t_conv *)x)->min1, val);} +void pdp_imageproc_conv_setzero(void *x, float val){setvec(((t_conv *)x)->zero, val);} +void pdp_imageproc_conv_setplus1(void *x, float val){setvec(((t_conv *)x)->plus1, val);} +void pdp_imageproc_conv_setbordercolor(void *x, float val){setvec(((t_conv *)x)->border, val);} +void pdp_imageproc_conv_setorientation(void *x, u32 val){((t_conv *)x)->orientation = val;} +void pdp_imageproc_conv_setnbpasses(void *x, u32 val){((t_conv *)x)->nbpasses = val;} +void pdp_imageproc_conv_process(void *x, u32 width, u32 height, s16 *image) + +{ + t_conv *d = (t_conv *)x; + + u32 orientation = d->orientation; + u32 nbp = d->nbpasses; + u32 i,j; + + if (orientation == PDP_IMAGEPROC_CONV_HORIZONTAL) + { + for(i=0; i<width*height; i+=width) + for (j=0; j<nbp; j++) + pixel_conv_hor_s16(image+i, width>>2, d->border, d->min1); + } + + else + { + for (j=0; j<nbp; j++) + for(i=0; i<width; i +=4) pixel_conv_ver_s16(image+i, height, width, d->border, d->min1); + } + + + +} + +// apply a gain to an image +void *pdp_imageproc_gain_new(void){return(pdp_alloc(8*sizeof(s16)));} +void pdp_imageproc_gain_delete(void *x){pdp_dealloc(x);} +void pdp_imageproc_gain_setgain(void *x, float gain) +{ + /* convert float to s16 + shift */ + s16 *d = (s16 *)x; + s16 g; + int i; + float sign; + int shift = 0; + + sign = (gain < 0) ? -1 : 1; + gain *= sign; + + /* max shift = 16 */ + for(i=0; i<=16; i++){ + if (gain < 0x4000){ + gain *= 2; + shift++; + } + else break; + } + + gain *= sign; + g = (s16) gain; + + //g = 0x4000; + //shift = 14; + + d[0]=g; + d[1]=g; + d[2]=g; + d[3]=g; + d[4]=(s16)shift; + d[5]=0; + d[6]=0; + d[7]=0; +} +void pdp_imageproc_gain_process(void *x, u32 width, u32 height, s16 *image) +{ + s16 *d = (s16 *)x; + pixel_gain_s16(image, (width*height)>>2, d, (u64 *)(d+4)); +} + +// colour rotation for 2 colour planes +void *pdp_imageproc_crot2d_new(void){return pdp_alloc(16*sizeof(s16));} +void pdp_imageproc_crot2d_delete(void *x){pdp_dealloc(x);} +void pdp_imageproc_crot2d_setmatrix(void *x, float *matrix) +{ + s16 *d = (s16 *)x; + setvec(d, matrix[0]); + setvec(d+4, matrix[1]); + setvec(d+8, matrix[2]); + setvec(d+12, matrix[3]); +} +void pdp_imageproc_crot2d_process(void *x, s16 *image, u32 width, u32 height) +{ + s16 *d = (s16 *)x; + pixel_crot2d_s16(image, width*height >> 2, d); +} + +// biquad and biquad time +typedef struct +{ + s16 ma1[4]; + s16 ma2[4]; + s16 b0[4]; + s16 b1[4]; + s16 b2[4]; + s16 u0[4]; + s16 u1[4]; + s16 u0_save[4]; + s16 u1_save[4]; + u32 nbpasses; + u32 direction; +} t_bq; + +void *pdp_imageproc_bq_new(void){return pdp_alloc(sizeof(t_bq));} +void pdp_imageproc_bq_delete(void *x){pdp_dealloc(x);} +void pdp_imageproc_bq_setcoef(void *x, float *coef) // a0,-a1,-a2,b0,b1,b2,u0,u1 +{ + t_bq *d = (t_bq *)x; + float ia0 = 1.0f / coef[0]; + + /* all coefs are s1.14 fixed point */ + /* representing values -2 < x < 2 */ + /* so scale down before using the ordinary s0.15 float->fixed routine */ + + ia0 *= 0.5f; + + // coef + setvec(d->ma1, ia0*coef[1]); + setvec(d->ma2, ia0*coef[2]); + setvec(d->b0, ia0*coef[3]); + setvec(d->b1, ia0*coef[4]); + setvec(d->b2, ia0*coef[5]); + + // state to reset too + setvec(d->u0_save, coef[6]); + setvec(d->u1_save, coef[7]); + +} +void pdp_imageproc_bq_setnbpasses(void *x, u32 nbpasses){((t_bq *)x)->nbpasses = nbpasses;} +void pdp_imageproc_bq_setdirection(void *x, u32 direction){((t_bq *)x)->direction = direction;} +void pdp_imageproc_bq_process(void *x, u32 width, u32 height, s16* image); + + +void pdp_imageproc_bqt_process(void *x, u32 width, u32 height, s16 *image, s16 *state0, s16 *state1) +{ + s16 *d = (s16 *)x; + pixel_biquad_time_s16(image, state0, state1, d, (width*height)>>2); +} + +void pdp_imageproc_bq_process(void *x, u32 width, u32 height, s16 *image) +{ + t_bq *d = (t_bq *)x; + s16 *c = d->ma1; /* coefs */ + s16 *s = d->u0; /* state */ + u32 direction = d->direction; + u32 nbp = d->nbpasses; + unsigned int i,j; + + + + /* VERTICAL */ + + if ((direction & PDP_IMAGEPROC_BIQUAD_TOP2BOTTOM) + && (direction & PDP_IMAGEPROC_BIQUAD_BOTTOM2TOP)){ + + for(i=0; i<width; i +=4){ + for (j=0; j<nbp; j++){ + pixel_biquad_vertb_s16(image+i, height>>2, width, c, s); + pixel_biquad_verbt_s16(image+i, height>>2, width, c, s); + } + } + } + + else if (direction & PDP_IMAGEPROC_BIQUAD_TOP2BOTTOM){ + for(i=0; i<width; i +=4){ + for (j=0; j<nbp; j++){ + pixel_biquad_vertb_s16(image+i, height>>2, width, c, s); + } + } + } + + else if (direction & PDP_IMAGEPROC_BIQUAD_BOTTOM2TOP){ + for(i=0; i<width; i +=4){ + for (j=0; j<nbp; j++){ + pixel_biquad_verbt_s16(image+i, height>>2, width, c, s); + } + } + } + + /* HORIZONTAL */ + + if ((direction & PDP_IMAGEPROC_BIQUAD_LEFT2RIGHT) + && (direction & PDP_IMAGEPROC_BIQUAD_RIGHT2LEFT)){ + + for(i=0; i<(width*height); i +=(width<<2)){ + for (j=0; j<nbp; j++){ + pixel_biquad_horlr_s16(image+i, width>>2, width, c, s); + pixel_biquad_horrl_s16(image+i, width>>2, width, c, s); + } + } + } + + else if (direction & PDP_IMAGEPROC_BIQUAD_LEFT2RIGHT){ + for(i=0; i<(width*height); i +=(width<<2)){ + for (j=0; j<nbp; j++){ + pixel_biquad_horlr_s16(image+i, width>>2, width, c, s); + } + } + } + + else if (direction & PDP_IMAGEPROC_BIQUAD_RIGHT2LEFT){ + for(i=0; i<(width*height); i +=(width<<2)){ + for (j=0; j<nbp; j++){ + pixel_biquad_horrl_s16(image+i, width>>2, width, c, s); + } + } + } + +} + +// produce a random image +// note: random number generator can be platform specific +// however, it should be seeded. (same seed produces the same result) +void *pdp_imageproc_random_new(void){return pdp_alloc(4*sizeof(s16));} +void pdp_imageproc_random_delete(void *x){pdp_dealloc(x);} +void pdp_imageproc_random_setseed(void *x, float seed) +{ + s16 *d = (s16 *)x; + srandom((u32)seed); + d[0] = (s16)random(); + d[1] = (s16)random(); + d[2] = (s16)random(); + d[3] = (s16)random(); + +} +void pdp_imageproc_random_process(void *x, u32 width, u32 height, s16 *image) +{ + s16 *d = (s16 *)x; + unsigned int totalnbpixels = width * height; + pixel_rand_s16(image, totalnbpixels>>2, d); +} + + +/* resampling stuff + this is quite a zoo of data structures + the major point is this: the resampler mmx code is shared for all resampling code + it uses data specified in t_resample_cbrd (Cooked Bilinear Resampler Data) + + then the there are several feeder algorithms. one is the linear mapper. it's + data is specified in t_resample_clrd (Cooked Linear Remapper Data) + + for each feeder algorithm, there are several high level algorithms. like zoom, + rotate, ... +*/ + +typedef struct +{ + u32 lineoffset; + s16 *image; + u32 width; + u32 height; + +} t_resample_id; // Image Data + +/* initialize image meta data (dimensions + location) */ +static void pdp_imageproc_resample_init_id(t_resample_id *x, u32 offset, s16* image, u32 w, u32 h) +{ + x->lineoffset = offset; + x->image = image; + x->width = w; + x->height = h; +} + +// mmx resampling source image resampling data + coefs +typedef struct +{ + // vector data for resampling routine (resampling computation) + u8 reserved[0x60]; //internal data + s16 *address[2]; //64 bit splatted offset address + s16 twowidthm1[4]; //64 bit splatted 2*(width-1) + s16 twoheightm1[4]; //64 bit splatted 2*(height-1) + s16 lineoffset[4]; //64 bit splatted line offset in pixels + +} t_resample_cid; // Cooked Image Data + +/* convert image meta data into a cooked format used by the resampler routine */ +static void pdp_imageproc_resample_init_cid(t_resample_cid *r, t_resample_id *i) +{ + u32 twowm1 = (i->width-1)<<1; + u32 twohm1 = (i->height-1)<<1; + r->address[0] = i->image; + r->address[1] = i->image; + r->twowidthm1[0] = twowm1; + r->twowidthm1[1] = twowm1; + r->twowidthm1[2] = twowm1; + r->twowidthm1[3] = twowm1; + r->twoheightm1[0] = twohm1; + r->twoheightm1[1] = twohm1; + r->twoheightm1[2] = twohm1; + r->twoheightm1[3] = twohm1; + r->lineoffset[0] = i->lineoffset; + r->lineoffset[1] = i->lineoffset; + r->lineoffset[2] = i->lineoffset; + r->lineoffset[3] = i->lineoffset; +} + +// linear mapping data struct (zoom, scale, rotate, shear, ...) +typedef struct +{ + s32 rowstatex[2]; // row state x coord + s32 rowstatey[2]; // row state y coord + s32 colstatex[2]; // column state x coord + s32 colstatey[2]; // column state y coord + s32 rowincx[2]; // row inc vector x coord + s32 rowincy[2]; // row inc vector y coord + s32 colincx[2]; // column inc vector x coord + s32 colincy[2]; // column inc vector y coord +} t_resample_clmd; // Cooked Linear Mapping Data + +/* convert incremental linear remapping vectors to internal cooked format */ +static void pdp_imageproc_resample_cookedlinmap_init(t_resample_clmd *l, s32 sx, s32 sy, s32 rix, s32 riy, s32 cix, s32 ciy) +{ + l->colstatex[0] = l->rowstatex[0] = sx; + l->colstatex[1] = l->rowstatex[1] = sx + rix; + l->colstatey[0] = l->rowstatey[0] = sy; + l->colstatey[1] = l->rowstatey[1] = sy + riy; + l->rowincx[0] = rix << 1; + l->rowincx[1] = rix << 1; + l->rowincy[0] = riy << 1; + l->rowincy[1] = riy << 1; + l->colincx[0] = cix; + l->colincx[1] = cix; + l->colincy[0] = ciy; + l->colincy[1] = ciy; +} + + +/* this struct contains all the data necessary for + bilin interpolation from src -> dst image + (src can be == dst) */ +typedef struct +{ + t_resample_cid csrc; //cooked src image meta data for bilinear interpolator + t_resample_id src; //src image meta + t_resample_id dst; //dst image meta +} t_resample_cbrd; //Bilinear Resampler Data + + +/* this struct contains high level zoom parameters, + all image relative */ +typedef struct +{ + float centerx; + float centery; + float zoomx; + float zoomy; + float angle; +} t_resample_zrd; + + +/* convert floating point center and zoom data to incremental linear remapping vectors */ +static void pdp_imageproc_resample_clmd_init_from_id_zrd(t_resample_clmd *l, t_resample_id *i, t_resample_zrd *z) +{ + double izx = 1.0f / (z->zoomx); + double izy = 1.0f / (z->zoomy); + double scale = (double)0xffffffff; + double scalew = scale / ((double)(i->width - 1)); + double scaleh = scale / ((double)(i->height - 1)); + double cx = ((double)z->centerx) * ((double)(i->width - 1)); + double cy = ((double)z->centery) * ((double)(i->height - 1)); + double angle = z->angle * (-M_PI / 180.0); + double c = cos(angle); + double s = sin(angle); + + /* affine x, y mappings in screen coordinates */ + double mapx(double x, double y){return cx + izx * ( c * (x-cx) + s * (y-cy));} + double mapy(double x, double y){return cy + izy * (-s * (x-cx) + c * (y-cy));} + + u32 tl_x = (u32)(scalew * mapx(0,0)); + u32 tl_y = (u32)(scaleh * mapy(0,0)); + + + u32 row_inc_x = (u32)(scalew * (mapx(1,0)-mapx(0,0))); + u32 row_inc_y = (u32)(scaleh * (mapy(1,0)-mapy(0,0))); + u32 col_inc_x = (u32)(scalew * (mapx(0,1)-mapx(0,0))); + u32 col_inc_y = (u32)(scaleh * (mapy(0,1)-mapy(0,0))); + + + pdp_imageproc_resample_cookedlinmap_init(l, tl_x, tl_y, row_inc_x, row_inc_y, col_inc_x, col_inc_y); +} + +/* this struct contains all data for the zoom object */ +typedef struct +{ + t_resample_cbrd cbrd; // Bilinear Resampler Data + t_resample_clmd clmd; // Cooked Linear Mapping data + t_resample_zrd zrd; // Zoom / Rotate Data +} t_resample_zoom_rotate; + +// zoom + rotate +void *pdp_imageproc_resample_affinemap_new(void) +{ + t_resample_zoom_rotate *z = (t_resample_zoom_rotate *)pdp_alloc(sizeof(t_resample_zoom_rotate)); + z->zrd.centerx = 0.5; + z->zrd.centery = 0.5; + z->zrd.zoomx = 1.0; + z->zrd.zoomy = 1.0; + z->zrd.angle = 0.0f; + return (void *)z; +} +void pdp_imageproc_resample_affinemap_delete(void *x){pdp_dealloc(x);} +void pdp_imageproc_resample_affinemap_setcenterx(void *x, float f){((t_resample_zoom_rotate *)x)->zrd.centerx = f;} +void pdp_imageproc_resample_affinemap_setcentery(void *x, float f){((t_resample_zoom_rotate *)x)->zrd.centery = f;} +void pdp_imageproc_resample_affinemap_setzoomx(void *x, float f){((t_resample_zoom_rotate *)x)->zrd.zoomx = f;} +void pdp_imageproc_resample_affinemap_setzoomy(void *x, float f){((t_resample_zoom_rotate *)x)->zrd.zoomy = f;} +void pdp_imageproc_resample_affinemap_setangle(void *x, float f){((t_resample_zoom_rotate *)x)->zrd.angle = f;} +void pdp_imageproc_resample_affinemap_process(void *x, u32 width, u32 height, s16 *srcimage, s16 *dstimage) +{ + t_resample_zoom_rotate *z = (t_resample_zoom_rotate *)x; + + /* setup resampler image meta data */ + pdp_imageproc_resample_init_id(&(z->cbrd.src), width, srcimage, width, height); + pdp_imageproc_resample_init_id(&(z->cbrd.dst), width, dstimage, width, height); + pdp_imageproc_resample_init_cid(&(z->cbrd.csrc),&(z->cbrd.src)); + + /* setup linmap data from zoom_rotate parameters */ + pdp_imageproc_resample_clmd_init_from_id_zrd(&(z->clmd), &(z->cbrd.src), &(z->zrd)); + + + /* call assembler routine */ + pixel_resample_linmap_s16(z); +} + + + +// polynomials + + +typedef struct +{ + u32 order; + u32 nbpasses; + s16 coefs[0]; +} t_cheby; + +void *pdp_imageproc_cheby_new(int order) +{ + t_cheby *z; + int i; + if (order < 2) order = 2; + z = (t_cheby *)pdp_alloc(sizeof(t_cheby) + (order + 1) * sizeof(s16[4])); + z->order = order; + setvec(z->coefs + 0*4, 0); + setvec(z->coefs + 1*4, 0.25); + for (i=2; i<=order; i++) setvec(z->coefs + i*4, 0); + + return z; +} +void pdp_imageproc_cheby_delete(void *x){pdp_dealloc(x);} +void pdp_imageproc_cheby_setcoef(void *x, u32 n, float f) +{ + t_cheby *z = (t_cheby *)x; + if (n <= z->order){ + setvec(z->coefs + n*4, f * 0.25); // coefs are in s2.13 format + } +} +void pdp_imageproc_cheby_setnbpasses(void *x, u32 n){((t_cheby *)x)->nbpasses = n;} + +void pdp_imageproc_cheby_process(void *x, u32 width, u32 height, s16 *image) +{ + t_cheby *z = (t_cheby *)x; + u32 iterations = z->nbpasses; + u32 i,j; + for (j=0; j < (height*width); j += width) + for (i=0; i<iterations; i++) + pixel_cheby_s16_3plus(image+j, width>>2, z->order+1, z->coefs); + + //pixel_cheby_s16_3plus(image, (width*height)>>2, z->order+1, z->coefs); +} diff --git a/system/image/pdp_imageproc_portable.c b/system/image/pdp_imageproc_portable.c new file mode 100644 index 0000000..112f729 --- /dev/null +++ b/system/image/pdp_imageproc_portable.c @@ -0,0 +1,681 @@ +/* + * Pure Data Packet. portable image processing routines. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include "pdp_imageproc.h" + +/* pdp memory alloc/dealloc prototype */ +void *pdp_alloc(int size); +void pdp_dealloc(void *); + + +// utility stuff +inline static s32 float2fixed(float f) +{ + if (f > 1) f = 1; + if (f < -1) f = -1; + f *= 0x7fff; + return (s32)f; +} + + + +#define CLAMP16(x) (((x) > 0x7fff) ? 0x7fff : (((x) < -0x7fff) ? -0x7fff : (x))) + +// add two images +void pdp_imageproc_add_process(void *x, u32 width, u32 height, s16 *image, s16 *image2) +{ + int a, b; + unsigned int i; + for (i=0; i<width*height; i++){ + a = (int)image[i]; + b = (int)image2[i]; + image[i] = (s16)(CLAMP16(a+b)); + } + +} + +// mul two images +void pdp_imageproc_mul_process(void *x, u32 width, u32 height, s16 *image, s16 *image2) +{ + int a, b; + unsigned int i; + for (i=0; i<width*height; i++){ + a = (int)image[i]; + b = (int)image2[i]; + image[i] = (s16)((a*b)>>15); + } + +} + +// mix 2 images +void *pdp_imageproc_mix_new(void){return pdp_alloc(2*sizeof(s32));} +int pdp_imageproc_mix_nb_stackwords(void) {return PDP_IMAGEPROC_NB_STACKWORDS(2*sizeof(s32));} +void pdp_imageproc_mix_delete(void *x) {pdp_dealloc (x);} +void pdp_imageproc_mix_setleftgain(void *x, float gain) +{ + s32 *d = (s32 *)x; + d[0] = float2fixed(gain); +} +void pdp_imageproc_mix_setrightgain(void *x, float gain) +{ + s32 *d = (s32 *)x; + d[1] = float2fixed(gain); +} +void pdp_imageproc_mix_process(void *x, u32 width, u32 height, s16 *image, s16 *image2) +{ + s32 *d = (s32 *)x; + u32 i; + s32 a,b; + + for(i=0; i<width*height; i++){ + a = (s32)image[i]; + b = (s32)image2[i]; + a = (a*d[0] + b*d[1]) >> 15; + image[i] = (s16)CLAMP16(a); + } + +} + + +// random mix 2 images +void *pdp_imageproc_randmix_new(void){return pdp_alloc(2*sizeof(s32));;} +int pdp_imageproc_randmix_nb_stackwords(void) {return PDP_IMAGEPROC_NB_STACKWORDS(2*sizeof(s32));} +void pdp_imageproc_randmix_delete(void *x) {pdp_dealloc(x);} +void pdp_imageproc_randmix_setthreshold(void *x, float threshold) +{ + s32 *d = (s32 *)x; + if (threshold > 1.0f) threshold = 1.0f; + if (threshold < 0.0f) threshold = 0.0f; + d[0] = float2fixed(threshold); +} +void pdp_imageproc_randmix_setseed(void *x, float seed) +{ + s32 *d = (s32 *)x; + d[1] = float2fixed(seed); +} +void pdp_imageproc_randmix_process(void *x, u32 width, u32 height, s16 *image, s16 *image2) +{ + s32 *d = (s32 *)x; + u32 i; + s16 r; + srandom((u32)d[1]); + + + for(i=0; i<width*height; i++){ + // get a random val between 0 and 0x7fff + r = (s16)(random() & 0x7fff); + if (r < d[0]) image[i] = image2[i]; + } +} + + +// 3x1 or 1x3 in place convolution +// orientation +void *pdp_imageproc_conv_new(void){return(pdp_alloc(6*sizeof(s32)));} +void pdp_imageproc_conv_delete(void *x){pdp_dealloc(x);} +void pdp_imageproc_conv_setmin1(void *x, float val) +{ + s32 *d = (s32 *)x; + d[0] = float2fixed(val); +} +void pdp_imageproc_conv_setzero(void *x, float val) +{ + s32 *d = (s32 *)x; + d[1] = float2fixed(val); +} +void pdp_imageproc_conv_setplus1(void *x, float val) +{ + s32 *d = (s32 *)x; + d[2] = float2fixed(val); +} +void pdp_imageproc_conv_setbordercolor(void *x, float val) +{ + s32 *d = (s32 *)x; + d[3] = float2fixed(val); +} +void pdp_imageproc_conv_setorientation(void *x, u32 val){((u32 *)x)[4] = val;} +void pdp_imageproc_conv_setnbpasses(void *x, u32 val){((u32 *)x)[5] = val;} + +static inline void pdp_imageproc_conv_scanline(void *x, s16 *data, u32 count, s32 stride) +{ + s32 *d = (s32 *)x; + s32 a,b,c,r; + u32 i; + + a = d[3]; //border + b = data[0]; + c = data[stride]; + + for(i = 0; i < count-2; i++){ + r = a*d[0] + b*d[1] + c*d[2]; + a = data[0]; + b = data[stride]; + c = data[stride<<1]; + data[0] = (s16)CLAMP16(r>>15); + data += stride; + } + r = a*d[0] + b*d[1] + c*d[2]; + a = data[0]; + b = data[stride]; + c = d[3]; //border + data[0] = (s16)CLAMP16(r>>15); + r = a*d[0] + b*d[1] + c*d[2]; + data[stride] = (s16)CLAMP16(r>>15); + +} + +void pdp_imageproc_conv_process(void *x, u32 width, u32 height, s16 *image) +{ + s32 *d = (s32 *)x; + u32 i, j; + u32 orientation = d[4]; + u32 nbp = d[5]; + if (orientation == PDP_IMAGEPROC_CONV_HORIZONTAL){ + for(i=0; i<width*height; i+=width) + for(j=0; j<nbp; j++) + pdp_imageproc_conv_scanline(x, image+i, width, 1); + + } + + if (orientation == PDP_IMAGEPROC_CONV_VERTICAL){ + for(i=0; i<width; i++) + for(j=0; j<nbp; j++) + pdp_imageproc_conv_scanline(x, image+i, height, width); + + } + + + + +} + +// apply a gain to an image +void *pdp_imageproc_gain_new(void){return(pdp_alloc(2*sizeof(s32)));} +void pdp_imageproc_gain_delete(void *x){pdp_dealloc(x);} +void pdp_imageproc_gain_setgain(void *x, float gain) +{ + /* convert float to s16 + shift */ + s32 *d = (s32 *)x; + s32 g; + int i; + float sign; + s32 shift = 0; + + sign = (gain < 0) ? -1 : 1; + gain *= sign; + + /* max shift = 16 */ + for(i=0; i<=16; i++){ + if (gain < 0x4000){ + gain *= 2; + shift++; + } + else break; + } + + gain *= sign; + g = (s32) gain; + + //g = 0x4000; + //shift = 14; + + d[0]=g; + d[1]=shift; +} +void pdp_imageproc_gain_process(void *x, u32 width, u32 height, s16 *image) +{ + s32 *d = (s32 *)x; + s32 a; + u32 i; + for (i=0; i<width*height; i++){ + a = (s32)image[i]; + image[i] = (s16)(CLAMP16((a * d[0]) >> d[1])); + } +} + +// colour rotation for 2 colour planes +void *pdp_imageproc_crot2d_new(void){return pdp_alloc(4*sizeof(s32));} +void pdp_imageproc_crot2d_delete(void *x){pdp_dealloc(x);} +void pdp_imageproc_crot2d_setmatrix(void *x, float *matrix) +{ + s32 *d = (s32 *)x; + d[0] = float2fixed(matrix[0]); + d[1] = float2fixed(matrix[1]); + d[2] = float2fixed(matrix[2]); + d[3] = float2fixed(matrix[3]); + +} +void pdp_imageproc_crot2d_process(void *x, s16 *image, u32 width, u32 height) +{ + s32 *d = (s32 *)x; + u32 i,j; + s32 a1,a2,c1,c2; + + for(i=0, j=width*height; i<width*height; i++, j++){ + c1 = (s32)image[i]; + c2 = (s32)image[j]; + + a1 = d[0] * c1; + a2 = d[1] * c1; + a1+= d[2] * c2; + a2+= d[3] * c2; + + a1 >>= 15; + a2 >>= 15; + + image[i] = (s16)CLAMP16(a1); + image[j] = (s16)CLAMP16(a2); + } +} + +// biquad and biquad time +typedef struct +{ + s32 ma1; + s32 ma2; + s32 b0; + s32 b1; + s32 b2; + + s32 u0; + s32 u1; + + s32 u0_save; + s32 u1_save; + + u32 nbpasses; + u32 direction; +} t_bq; +void *pdp_imageproc_bq_new(void){return pdp_alloc(sizeof(t_bq));} +void pdp_imageproc_bq_delete(void *x){pdp_dealloc(x);} +void pdp_imageproc_bq_setnbpasses(void *x, u32 i){((t_bq *)x)->nbpasses = i;} +void pdp_imageproc_bq_setdirection(void *x, u32 i){((t_bq *)x)->direction = i;} +void pdp_imageproc_bq_setcoef(void *x, float *coef) // a0,-a1,-a2,b0,b1,b2,u0,u1 +{ + s32 *d = (s32 *)x; + float ia0 = 1.0f / coef[0]; + + /* all coefs are s1.14 fixed point */ + /* representing values -2 < x < 2 */ + /* so scale down before using the ordinary s0.15 float->fixed routine */ + + ia0 *= 0.5f; + + // coef + d[0] = float2fixed(ia0*coef[1]); // -a1 + d[1] = float2fixed(ia0*coef[2]); // -a2 + d[2] = float2fixed(ia0*coef[3]); // b0 + d[3] = float2fixed(ia0*coef[4]); // b1 + d[4] = float2fixed(ia0*coef[5]); // b2 + + + // state to reset too + d[5] = float2fixed(coef[6]); + d[6] = float2fixed(coef[7]); + +} + +#define A1 d[0] +#define A2 d[1] +#define B0 d[2] +#define B1 d[3] +#define B2 d[4] +/* + # DIRECT FORM II BIQUAD (from pixel_biquad_s16.s) + # + # y[k] = b0 * x[k] + u1[k-1] + # u1[k] = b1 * x[k] + u2[k-1] - a1 * y[k] + # u2[k] = b2 * x[k] - a2 * y[k] +*/ + +/* remark A1 and A2 are already negated) */ + + +static inline void pdp_imageproc_bq_scanline(void *x, s16 *data, u32 count, s32 stride) +{ + + s32 *d = (s32 *)x; + s32 u1,u2, xx, yy; + + u32 i; + + u1 = d[7]; + u2 = d[8]; + + for(i = 0; i < count; i++){ + + xx = (s32)data[0]; + + yy = ((B0 * xx)>>14) + u1; + u1 = ((B1 * xx)>>14) + u2 + ((A1 * yy)>>14); + u2 = ((B2 * xx)>>14) + ((A2 * yy)>>14); + + data[0] = (s16)CLAMP16(yy); + + data += stride; + + } + + d[7] = u1; + d[8] = u2; + +} + +void pdp_imageproc_bqt_process(void *x, u32 width, u32 height, s16 *image, s16 *state1, s16 *state2) +{ + s32 *d = (s32 *)x; + u32 i; + s32 u1, u2, xx, yy; + + for (i=0; i<width*height; i++){ + + xx = (s32)image[i]; + u1 = (s32)state1[i]; + u2 = (s32)state2[i]; + + yy = ((B0 * xx)>>14) + u1; + u1 = ((B1 * xx)>>14) + u2 + ((A1 * yy)>>14); + u2 = ((B2 * xx)>>14) + ((A2 * yy)>>14); + + image[i] = (s16)CLAMP16(yy); + state1[i] = (s16)CLAMP16(u1); + state2[i] = (s16)CLAMP16(u2); + } + + +} + +void pdp_imageproc_bq_process(void *x, u32 width, u32 height, s16 *data) +{ + s32 *d = (s32 *)x; + + u32 nbp = d[9]; + u32 direction = d[10]; + unsigned int i,j, offset; + + + /* VERTICAL */ + offset = (height-1)*width; + + if ((direction & PDP_IMAGEPROC_BIQUAD_TOP2BOTTOM) + && (direction & PDP_IMAGEPROC_BIQUAD_BOTTOM2TOP)){ + + for(i=0; i<width; i++){ + for (j=0; j<nbp; j++){ + pdp_imageproc_bq_scanline(x, data+i, height, width); //T->B + pdp_imageproc_bq_scanline(x, data+offset+i, height, -width); //B->T + } + } + } + + else if (direction & PDP_IMAGEPROC_BIQUAD_TOP2BOTTOM){ + for(i=0; i<width; i++){ + for (j=0; j<nbp; j++){ + pdp_imageproc_bq_scanline(x, data+i, height, width); //T->B + } + } + } + + else if (direction & PDP_IMAGEPROC_BIQUAD_BOTTOM2TOP){ + for(i=0; i<width; i++){ + for (j=0; j<nbp; j++){ + pdp_imageproc_bq_scanline(x, data+offset+i, height, -width); //B->T + } + } + } + + /* HORIZONTAL */ + + offset = width-1; + if ((direction & PDP_IMAGEPROC_BIQUAD_LEFT2RIGHT) + && (direction & PDP_IMAGEPROC_BIQUAD_RIGHT2LEFT)){ + + for(i=0; i<(width*height); i += width){ + for (j=0; j<nbp; j++){ + pdp_imageproc_bq_scanline(x, data+i, width, 1); //L->R + pdp_imageproc_bq_scanline(x, data+offset+i, width, -1); //R->L + } + } + } + + else if (direction & PDP_IMAGEPROC_BIQUAD_LEFT2RIGHT){ + for(i=0; i<(width*height); i += width){ + for (j=0; j<nbp; j++){ + pdp_imageproc_bq_scanline(x, data+i, width, 1); //L->R + } + } + } + + else if (direction & PDP_IMAGEPROC_BIQUAD_RIGHT2LEFT){ + for(i=0; i<(width*height); i += width){ + for (j=0; j<nbp; j++){ + pdp_imageproc_bq_scanline(x, data+offset+i, width, -1); //R->L + + } + } + } + +} + +// produce a random image +// note: random number generator can be platform specific +// however, it should be seeded. (same seed produces the same result) +void *pdp_imageproc_random_new(void){return pdp_alloc(sizeof(s32));} +void pdp_imageproc_random_delete(void *x){pdp_dealloc(x);} +void pdp_imageproc_random_setseed(void *x, float seed) +{ + float *f = (float *)x; + u32 *d = (u32 *)x; + f[0] = seed; + srandom(d[0]); +} + +void pdp_imageproc_random_process(void *x, u32 width, u32 height, short int *image) +{ + s32 *d = (u32 *)x; + u32 i; + s32 r; + srandom(d[0]); + for (i=0; i<(width*height); i++) { + r = random(); + image[i] = r; + } + d[0] = random(); +} + + + +/* resampling code */ +// zoom + rotate + +/* bilinear resampling core routine */ +/* virtual coordinates are the lowest 16 bits in virt_x and virt_y*/ +static inline s32 pdp_resample_bilin(s16 *image, s32 width, s32 height, s32 virt_x, s32 virt_y) +{ + + s32 fp_x, fp_y, frac_x, frac_y, f, offset, r_1, r_2; + + //virt_x &= 0xffff; + //virt_y &= 0xffff; + + fp_x = virt_x * (width - 1); + fp_y = virt_y * (height - 1); + + frac_x = fp_x & (0xffff); + frac_y = fp_y & (0xffff); + + offset = (fp_x >> 16) + (fp_y >> 16) * width; + image += offset; + + f = 0x10000 - frac_x; + + r_1 = ((f * (s32)(image[0]) + frac_x * (s32)(image[1])))>>16; + + image += width; + + r_2 = ((f * (s32)(image[0]) + frac_x * (s32)(image[1])))>>16; + + f = 0x10000 - frac_y; + + return ((f * r_1 + frac_y * r_2)>>16); + +} + +typedef struct +{ + float centerx; + float centery; + float zoomx; + float zoomy; + float angle; +} t_affine_map; + + +void *pdp_imageproc_resample_affinemap_new(void) +{ + + t_affine_map *a = (t_affine_map *)pdp_alloc(sizeof(t_affine_map)); + a->centerx = 0.5; + a->centery = 0.5; + a->zoomx = 1.0; + a->zoomy = 1.0; + a->angle = 0.0f; + return (void *)a; +} + +void pdp_imageproc_resample_affinemap_delete(void *x){pdp_dealloc(x);} +void pdp_imageproc_resample_affinemap_setcenterx(void *x, float f){((t_affine_map *)x)->centerx = f;} +void pdp_imageproc_resample_affinemap_setcentery(void *x, float f){((t_affine_map *)x)->centery = f;} +void pdp_imageproc_resample_affinemap_setzoomx(void *x, float f){((t_affine_map *)x)->zoomx = f;} +void pdp_imageproc_resample_affinemap_setzoomy(void *x, float f){((t_affine_map *)x)->zoomy = f;} +void pdp_imageproc_resample_affinemap_setangle(void *x, float f){((t_affine_map *)x)->angle = f;} +void pdp_imageproc_resample_affinemap_process(void *x, u32 width, u32 height, s16 *srcimage, s16 *dstimage) +{ + t_affine_map *a = (t_affine_map *)x; + double izx = 1.0f / (a->zoomx); + double izy = 1.0f / (a->zoomy); + double scale = (double)0xffffffff; + double scalew = scale / ((double)(width - 1)); + double scaleh = scale / ((double)(height - 1)); + double cx = ((double)a->centerx) * ((double)(width - 1)); + double cy = ((double)a->centery) * ((double)(height - 1)); + double angle = a->angle * (-M_PI / 180.0); + double c = cos(angle); + double s = sin(angle); + + /* affine x, y mappings in screen coordinates */ + double mapx(double x, double y){return cx + izx * ( c * (x-cx) + s * (y-cy));} + double mapy(double x, double y){return cy + izy * (-s * (x-cx) + c * (y-cy));} + + u32 colstate_x = (u32)(scalew * mapx(0,0)); + u32 colstate_y = (u32)(scaleh * mapy(0,0)); + u32 rowstate_x = colstate_x; + u32 rowstate_y = colstate_y; + + u32 row_inc_x = (u32)(scalew * (mapx(1,0)-mapx(0,0))); + u32 row_inc_y = (u32)(scaleh * (mapy(1,0)-mapy(0,0))); + u32 col_inc_x = (u32)(scalew * (mapx(0,1)-mapx(0,0))); + u32 col_inc_y = (u32)(scaleh * (mapy(0,1)-mapy(0,0))); + + u32 i,j; + + for (j=0; j<height; j++){ + for (i=0; i<width; i++){ + *dstimage++ = pdp_resample_bilin(srcimage, width, height, rowstate_x>>16, rowstate_y>>16); + rowstate_x += row_inc_x; + rowstate_y += row_inc_y; + } + colstate_x += col_inc_x; + colstate_y += col_inc_y; + rowstate_x = colstate_x; + rowstate_y = colstate_y; + } + +} + + + + + +// polynomials + + + + +typedef struct +{ + u32 order; + u32 nbpasses; + s32 coefs[0]; +} t_cheby; + +void *pdp_imageproc_cheby_new(int order) +{ + t_cheby *z; + int i; + if (order < 2) order = 2; + z = (t_cheby *)pdp_alloc(sizeof(t_cheby) + (order + 1) * sizeof(s32)); + z->order = order; + z->coefs[0] = 0; + z->coefs[1] = 0x7fff; + for (i=2; i<=order; i++) z->coefs[i] = 0; + return z; +} +void pdp_imageproc_cheby_delete(void *x){pdp_dealloc(x);} +void pdp_imageproc_cheby_setnbpasses(void *x, u32 n){((t_cheby *)x)->nbpasses = n;} +void pdp_imageproc_cheby_setcoef(void *x, u32 n, float f) +{ + + t_cheby *z = (t_cheby *)x; + if (n <= z->order){ + z->coefs[n] = (s32)(f * 32767.0f); // coefs are in s16.15 format + } + +} +void pdp_imageproc_cheby_process(void *x, u32 width, u32 height, s16 *image) +{ + + t_cheby *z = (t_cheby *)x; + u32 iterations = z->nbpasses; + u32 i,j,k; + s32 *c = z->coefs; + for (j=0; j < (height*width); j++){ + s32 acc = (s32)image[j]; + for (i=0; i<iterations; i++){ + s32 T2 = 0x7fff; /* 1 */ + s32 T1 = acc; + s32 t; + s32 in = acc; + acc = c[0] + ((in*c[1])>>15); + for (k=2; k<=z->order; k++){ + t = ((T1*in)>>14) - T2; /* T_n = 2 x T_n-1 - T_n-2 */ + T2 = T1; + T1 = t; + acc += ((c[k] * t)>>15); + } + } + image[j] = (s16)(CLAMP16(acc)); + } +} diff --git a/system/image/pdp_llconv.c b/system/image/pdp_llconv.c new file mode 100644 index 0000000..f10c61d --- /dev/null +++ b/system/image/pdp_llconv.c @@ -0,0 +1,574 @@ +/* + * Pure Data Packet system implementation. : low level format conversion code + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 file contains low level image conversion code + nominated as "the ugliest part of pdp" + some code is mmx, most is not. */ + +/* seem's there's some confusion between rgb and bgr formats. + not that it matters much which is supposed to be the "real" + rgb or bgr, but opengl and v4l seem to disagree on endianness + grounds.. */ + +#include "pdp_llconv.h" +#include "pdp_mmx.h" +#include "pdp_post.h" + + +/* all symbols are C style */ +#ifdef __cplusplus +extern "C" +{ +#endif + + +#define CLAMP8(x) (((x)<0) ? 0 : ((x>255)? 255 : (x))) +#define CLAMP16(x) (((x)<-0x7fff) ? -0x7fff : ((x>0x7fff) ? 0x7fff : (x))) +#define FP(x) ((int)(((float)(x)) * 256.0f)) + +#define CLAMP CLAMP8 + +/* some prototypes for functions defined elsewhere */ +void llconv_yvu_planar_s16u8(short int *src, unsigned char *dst, unsigned int nbpixels); +void llconv_yuv_planar_u8s16(unsigned char* source, short int *dest, int nbpixels); +void llconv_grey_s16u8(short int *src, unsigned char *dst, unsigned int nbpixels); +void llconv_yvu_planar_u8s16(unsigned char* source, short int *dest, int nbpixels); + + +static inline int rgb2y(int r, int g, int b) +{ + return (FP(0.257) * r) + (FP(0.504) * g) + (FP(0.098) * b) + FP(16); +} +static inline int rgb2v(int r, int g, int b) +{ + return (FP(0.439) * r) - (FP(0.368) * g) - (FP(0.071) * b) + FP(128); +} +static inline int rgb2u(int r, int g, int b) +{ + return -(FP(0.148) * r) - (FP(0.291) * g) + (FP(0.439) * b) + FP(128); +} + + +/* swap top to bottom */ +static inline void _exchange_row(char *row1, char *row2, int size) +{ + int mask = ~(sizeof(int)-1); + int *irow1 = (int *)row1; + int *irow2 = (int *)row2; + + /* transfer words */ + while (size & mask){ + int tmp = *irow1; + *irow1++ = *irow2; + *irow2++ = tmp; + size -= sizeof(int); + } + + row1 = (char *)irow1; + row2 = (char *)irow2; + + /* transfer rest bytes */ + while (size){ + int tmp = *row1; + *row1++ = *row2; + *row2++ = tmp; + size--; + } +} + +void pdp_llconv_flip_top_bottom(char *data, int width, int height, int pixelsize) +{ + int linesize = width * pixelsize; + int i; + char *row1 = data; + char *row2 = data + linesize * (height-1); + + if (height <= 1) return; + if (width <= 0) return; + + while (row1 < row2){ + _exchange_row(row1, row2, linesize); + row1 += linesize; + row2 -= linesize; + } +} + +/* "standard" 8 bit conversion routine */ +static void llconv_rgb2yvu(unsigned char* src, unsigned char* dst, int nbpixels) +{ + int r,g,b,y,v,u,i; + for (i=0; i<nbpixels; i++){ + r = src[0]; + g = src[1]; + b = src[2]; + + y = rgb2y(r,g,b); + v = rgb2v(r,g,b); + u = rgb2u(r,g,b); + + dst[0] = CLAMP(y>>8); + dst[1] = CLAMP(v>>8); + dst[2] = CLAMP(u>>8); + + src += 3; + dst += 3; + } +} + +static void llconv_yvu16planar2rgbpacked(short int *src, unsigned char *dst, int w, int h) +{ + +/* +B = 1.164(Y - 16) + 2.018(U - 128) +G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128) +R = 1.164(Y - 16) + 1.596(V - 128)} +*/ + + int r,g,b,y,u,v,b1,g1,r1,y1,xoff,yoff; + int size = w*h; + int voffset = size; + int uoffset = size + (size>>2); + int rgboff; + int rgbw = w*3; + int lumoff = 0; + int chromoff = 0; + + for(yoff=0; yoff<w*h; yoff+=2*w){ + for(xoff=0; xoff<w; xoff+=2){ + + /* calculate offsets */ + rgboff = 3 * (xoff + yoff); + lumoff = xoff + yoff; + chromoff = (xoff >> 1) + (yoff >> 2); + + /* get uv values */ + v = src[voffset + chromoff]; + u = src[uoffset + chromoff]; + + /* calculate chroma contrib for 2x2 pixblock */ + b1 = FP(2.018) * u; + g1 = FP(-0.813) * v + FP(-0.391) * u; + r1 = FP(1.596) * v; + + /* TOP LEFT */ + + /* top left luma contrib */ + y = src[lumoff] << 1; + y1 = FP(1.164) * y; + y1 -= FP(16*256); + + b = (b1 + y1)>>16; + g = (g1 + y1)>>16; + r = (r1 + y1)>>16; + + /* store top left rgb pixel */ + dst[rgboff+0] = CLAMP8(r); + dst[rgboff+1] = CLAMP8(g); + dst[rgboff+2] = CLAMP8(b); + + /* TOP RIGHT */ + + /* top right luma contrib */ + y = src[lumoff + 1] << 1; + y1 = FP(1.164) * y; + y1 -= FP(16*256); + + b = (b1 + y1)>>16; + g = (g1 + y1)>>16; + r = (r1 + y1)>>16; + + /* store top right rgb pixel */ + dst[rgboff+3] = CLAMP8(r); + dst[rgboff+4] = CLAMP8(g); + dst[rgboff+5] = CLAMP8(b); + + + /* BOTTOM LEFT */ + + /* bottom left luma contrib */ + y = src[lumoff+w] << 1; + y1 = FP(1.164) * y; + y1 -= FP(16*256); + + b = (b1 + y1)>>16; + g = (g1 + y1)>>16; + r = (r1 + y1)>>16; + + /* store bottom left rgb pixel */ + dst[rgboff+rgbw+0] = CLAMP8(r); + dst[rgboff+rgbw+1] = CLAMP8(g); + dst[rgboff+rgbw+2] = CLAMP8(b); + + /* BOTTOM RIGHT */ + + /* bottom right luma contrib */ + y = src[lumoff + w + 1] << 1; + y1 = FP(1.164) * y; + y1 -= FP(16*256); + + b = (b1 + y1)>>16; + g = (g1 + y1)>>16; + r = (r1 + y1)>>16; + + /* store bottom right rgb pixel */ + dst[rgboff+rgbw+3] = CLAMP8(r); + dst[rgboff+rgbw+4] = CLAMP8(g); + dst[rgboff+rgbw+5] = CLAMP8(b); + + } + + } + +} + + + +/* common 8 bit rgb -> 16 bit yvu */ +inline static void llconv_rgb2yvu_planar16sub_indexed(unsigned char* src, short int* dst, int w, int h, int ir, int ig, int ib, int stride) +{ + int r,g,b,y,v,u,i,j,k; + int size = w*h; + + int voffset = size; + int uoffset = size + (size>>2); + + + int loffset = w * stride; + + k=0; + for (j=0; j<w*h; j+=(w<<1)){ + k = stride * j; + for (i=0; i<w; i+=2){ + + + // well, this seems to work... strange though + r = src[k+ir]; + g = src[k+ig]; + b = src[k+ib]; + + y = (FP(0.257) * r) + (FP(0.504) * g) + (FP(0.098) * b) + FP(16); + v = (FP(0.439) * r) - (FP(0.368) * g) - (FP(0.071) * b); + u = -(FP(0.148) * r) - (FP(0.291) * g) + (FP(0.439) * b); + + dst[i+j] = CLAMP16(y >> 1); + + r = src[k+stride+ir]; + g = src[k+stride+ig]; + b = src[k+stride+ib]; + + y = (FP(0.257) * r) + (FP(0.504) * g) + (FP(0.098) * b) + FP(16); + v += (FP(0.439) * r) - (FP(0.368) * g) - (FP(0.071) * b); + u += -(FP(0.148) * r) - (FP(0.291) * g) + (FP(0.439) * b); + + dst[i+j+1] = CLAMP16(y >> 1); + + + + r = src[loffset + k+ir]; + g = src[loffset + k+ig]; + b = src[loffset + k+ib]; + + y = (FP(0.257) * r) + (FP(0.504) * g) + (FP(0.098) * b) + FP(16); + v = (FP(0.439) * r) - (FP(0.368) * g) - (FP(0.071) * b); + u = -(FP(0.148) * r) - (FP(0.291) * g) + (FP(0.439) * b); + + dst[w+i+j] = CLAMP16(y >> 1); + + r = src[loffset + k+stride+ir]; + g = src[loffset + k+stride+ig]; + b = src[loffset + k+stride+ib]; + + k += 2 * stride; + + y = (FP(0.257) * r) + (FP(0.504) * g) + (FP(0.098) * b) + FP(16); + v += (FP(0.439) * r) - (FP(0.368) * g) - (FP(0.071) * b); + u += -(FP(0.148) * r) - (FP(0.291) * g) + (FP(0.439) * b); + + dst[w+i+j+1] = CLAMP16(y >> 1); + + dst[uoffset+ (i>>1) + (j>>2)] = (CLAMP16(u >> 1)); + dst[voffset+ (i>>1) + (j>>2)] = (CLAMP16(v >> 1)); + } + } +} + +/* 8 bit rgb to 16 bit planar subsampled yvu */ +static void llconv_rgb2yvu_planar16sub(unsigned char* src, short int* dst, int w, int h) +{ + llconv_rgb2yvu_planar16sub_indexed(src,dst,w,h,0,1,2,3); +} + +/* 8 bit rgba to 16 bit planar subsampled yvu */ +static void llconv_rgba2yvu_planar16sub(unsigned char* src, short int* dst, int w, int h) +{ + llconv_rgb2yvu_planar16sub_indexed(src,dst,w,h,0,1,2,4); +} + +/* 8 bit bgr to 16 bit planar subsampled yvu */ +static void llconv_bgr2yvu_planar16sub(unsigned char* src, short int* dst, int w, int h) +{ + llconv_rgb2yvu_planar16sub_indexed(src,dst,w,h,2,1,0,3); +} + +/* 8 bit bgra to 16 bit planar subsampled yvu */ +static void llconv_bgra2yvu_planar16sub(unsigned char* src, short int* dst, int w, int h) +{ + llconv_rgb2yvu_planar16sub_indexed(src,dst,w,h,2,1,0,4); +} + + +/* 8 bit rgb to 8 bit planar subsampled yvu */ +static void llconv_rgb2yvu_planar8sub(unsigned char* src, unsigned char *dst, int w, int h) +{ + int r,g,b,y,v,u,i,j,k; + int size = w*h; + + int voffset = size; + int uoffset = size + (size>>2); + + + int loffset = w * 3; + + k=0; + for (j=0; j<w*h; j+=(w<<1)){ + k = 3 * j; + for (i=0; i<w; i+=2){ + + + // well, this seems to work... strange though + r = src[k]; + g = src[k+1]; + b = src[k+2]; + + y = (FP(0.257) * r) + (FP(0.504) * g) + (FP(0.098) * b) + FP(16); + v = (FP(0.439) * r) - (FP(0.368) * g) - (FP(0.071) * b); + u = -(FP(0.148) * r) - (FP(0.291) * g) + (FP(0.439) * b); + + dst[i+j] = CLAMP8(y >> 8); + + r = src[k+3]; + g = src[k+4]; + b = src[k+5]; + + y = (FP(0.257) * r) + (FP(0.504) * g) + (FP(0.098) * b) + FP(16); + v += (FP(0.439) * r) - (FP(0.368) * g) - (FP(0.071) * b); + u += -(FP(0.148) * r) - (FP(0.291) * g) + (FP(0.439) * b); + + dst[i+j+1] = CLAMP8(y >> 8); + + + + r = src[loffset + k]; + g = src[loffset + k+1]; + b = src[loffset + k+2]; + + y = (FP(0.257) * r) + (FP(0.504) * g) + (FP(0.098) * b) + FP(16); + v = (FP(0.439) * r) - (FP(0.368) * g) - (FP(0.071) * b); + u = -(FP(0.148) * r) - (FP(0.291) * g) + (FP(0.439) * b); + + dst[w+i+j] = CLAMP8(y >> 8); + + r = src[loffset + k+3]; + g = src[loffset + k+4]; + b = src[loffset + k+5]; + + k += 6; + + y = (FP(0.257) * r) + (FP(0.504) * g) + (FP(0.098) * b) + FP(16); + v += (FP(0.439) * r) - (FP(0.368) * g) - (FP(0.071) * b); + u += -(FP(0.148) * r) - (FP(0.291) * g) + (FP(0.439) * b); + + dst[w+i+j+1] = CLAMP8(y >> 8); + + dst[uoffset+ (i>>1) + (j>>2)] = (CLAMP8((u >> 9)+128)); + dst[voffset+ (i>>1) + (j>>2)] = (CLAMP8((v >> 9)+128)); + } + } +} + + +/* these seem to be pretty slow */ + +static void llconv_yvu2rgb(unsigned char* src, unsigned char* dst, int nbpixels) +{ + int r,g,b,y,v,u,i; + for (i=0; i<nbpixels; i++){ + y = src[0]; + v = src[1]; + u = src[2]; + + + b = FP(1.164) * (y - 16) + FP(2.018) * (u - 128); + g = FP(1.164) * (y - 16) - FP(0.813) * (v - 128) - FP(0.391) * (u - 128); + r = FP(1.164) * (y - 16) + FP(1.596) * (v - 128); + + dst[0] = CLAMP(r>>8); + dst[1] = CLAMP(g>>8); + dst[2] = CLAMP(b>>8); + + src += 3; + dst += 3; + } +} + + + +/* convert yvu to yuyv */ +static void llconv_yvu2yuyv(unsigned char *src, unsigned char *dst, unsigned int nbpixels) +{ + unsigned int y1, y2, u, v, i; + + for (i = 0; i < nbpixels/2; i++){ + + y1 = src[0]; + y2 = src[3]; + v = (src[1] + src[4]) >> 1; + u = (src[2] + src[5]) >> 1; + dst[0] = y1; + dst[1] = u; + dst[2] = y2; + dst[3] = v; + + src += 6; + dst += 4; + + } + +} + + + +/* convert yuvu packed 8 bit unsigned to yv12 planar 16bit signed */ +static void llconv_yuyv_packed_u8s16(unsigned char* ucsource, short int *sidest, unsigned int w, unsigned int h) +{ + unsigned int i, j; + unsigned int *source = (unsigned int *)ucsource; + + unsigned int *dest = (unsigned int *)sidest; + unsigned int uoffset = (w*h)>>1; + unsigned int voffset = (w*h + ((w*h) >> 2)) >> 1; + + for(j=0; j < (h*w)>>1; j +=(w)){ + for(i=0; i< (w>>1); i+=2){ + unsigned int y,u,v; + unsigned int v00, v01, v10, v11; + v00 = source[i+j]; + v01 = source[i+j+1]; + v10 = source[i+j+(w>>1)]; + v11 = source[i+j+(w>>1)+1]; + + // save luma + dest[i+j] = ((v00 & 0x00ff00ff) << 7); + dest[i+j+1] = ((v01 & 0x00ff00ff) << 7); + dest[i+j+(w>>1)] = ((v10 & 0x00ff00ff) << 7); + dest[i+j+(w>>1)+1] = ((v11 & 0x00ff00ff) << 7); + + // compute chroma + + // mask out luma & shift right + v00 = (v00 & 0xff00ff00)>>1; + v01 = (v01 & 0xff00ff00)>>1; + v10 = (v10 & 0xff00ff00)>>1; + v11 = (v11 & 0xff00ff00)>>1; + + // average 2 scan lines + v00 += v10; + v01 += v11; + + // combine + v = (v01 << 16) | (v00 & 0x0000ffff); + u = (v01 & 0xffff0000) | (v00 >> 16); + + // flip sign bits for u,v + u ^= 0x80008000; + v ^= 0x80008000; + + // save chroma + dest[uoffset + (i>>1) + (j>>2)] = u; + dest[voffset + (i>>1) + (j>>2)] = v; + } + } + + +} + +#define CONVERT(x,y) ((x) + ((y)<<16)) + +void pdp_llconv(void *src, int stype, void *dst, int dtype, int w, int h) +{ + int conversion = CONVERT(stype, dtype); + void *tmpbuf; + + switch(CONVERT(stype, dtype)){ + + case CONVERT( RIF_YVU__P411_U8, RIF_YVU__P411_S16 ): + llconv_yvu_planar_u8s16((unsigned char*)src, (short int *)dst, w*h); + break; + + case CONVERT( RIF_YUV__P411_U8, RIF_YVU__P411_S16 ): + llconv_yuv_planar_u8s16((unsigned char*)src, (short int *)dst, w*h); + break; + + case CONVERT( RIF_YUYV_P____U8, RIF_YVU__P411_S16 ): + llconv_yuyv_packed_u8s16((unsigned char*)src, (short int *)dst, w, h); + break; + + case CONVERT( RIF_RGB__P____U8, RIF_YVU__P411_U8 ): + llconv_rgb2yvu_planar8sub((unsigned char*) src, (unsigned char*) dst, w, h); + break; + + case CONVERT( RIF_RGB__P____U8, RIF_YVU__P411_S16 ): + llconv_rgb2yvu_planar16sub((unsigned char*) src, (short int*) dst, w, h); + break; + + case CONVERT( RIF_RGBA_P____U8, RIF_YVU__P411_S16 ): + llconv_rgba2yvu_planar16sub((unsigned char*) src, (short int*) dst, w, h); + break; + + case CONVERT( RIF_BGR__P____U8, RIF_YVU__P411_S16 ): + llconv_bgr2yvu_planar16sub((unsigned char*) src, (short int*) dst, w, h); + break; + + case CONVERT( RIF_BGRA_P____U8, RIF_YVU__P411_S16 ): + llconv_bgra2yvu_planar16sub((unsigned char*) src, (short int*) dst, w, h); + break; + + case CONVERT( RIF_YVU__P411_S16, RIF_RGB__P____U8 ): + llconv_yvu16planar2rgbpacked((short int*) src, (unsigned char*) dst, w, h); + break; + + case CONVERT( RIF_YVU__P411_S16, RIF_YVU__P411_U8 ): + llconv_yvu_planar_s16u8((short int*)src, (unsigned char*)dst, w*h); + break; + + case CONVERT( RIF_GREY______S16, RIF_GREY______U8 ): + llconv_grey_s16u8((short int*)src, (unsigned char*)dst, w*h); + break; + default: + pdp_post("pdp_llconv: WARNING: no conversion routine defined for (%d)->(%d)", stype, dtype); + + } + +} + + +#ifdef __cplusplus +} +#endif diff --git a/system/image/pdp_llconv_mmx.c b/system/image/pdp_llconv_mmx.c new file mode 100644 index 0000000..8070bac --- /dev/null +++ b/system/image/pdp_llconv_mmx.c @@ -0,0 +1,55 @@ + +/* + * Pure Data Packet system implementation. : wrapper for mmx low level format conversion code + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +#include "pdp_mmx.h" + + + +/* convert greyscale 8 bit unsigned to 16bit signed */ +void llconv_grey_s16u8(short int *src, unsigned char *dst, unsigned int nbpixels) +{ + pixel_pack_s16u8_y(src, dst, nbpixels>>3); +} + +/* convert yvu planar 411 16 bit signed to 8 bit unsigned */ +void llconv_yvu_planar_s16u8(short int *src, unsigned char *dst, unsigned int nbpixels) +{ + pixel_pack_s16u8_y(src, dst, nbpixels>>3); + pixel_pack_s16u8_uv(src + nbpixels, dst + nbpixels, nbpixels>>4); +} + + +/* convert yvu planar 411 8 bit unsigned to yv12 planar 16bit signed */ +void llconv_yvu_planar_u8s16(unsigned char* source, short int *dest, int nbpixels) +{ + pixel_unpack_u8s16_y(source, dest, nbpixels>>3); + pixel_unpack_u8s16_uv(&source[nbpixels], &dest[nbpixels], nbpixels>>4); +} + +/* convert yuv planar 411 8 bit unsigned to yv12 planar 16bit signed */ +void llconv_yuv_planar_u8s16(unsigned char* source, short int *dest, int nbpixels) +{ + pixel_unpack_u8s16_y(source, dest, nbpixels>>3); + pixel_unpack_u8s16_uv(&source[nbpixels], &dest[nbpixels + (nbpixels>>2)], nbpixels>>5); + pixel_unpack_u8s16_uv(&source[nbpixels + (nbpixels>>2)], &dest[nbpixels], nbpixels>>5); +} + diff --git a/system/image/pdp_llconv_portable.c b/system/image/pdp_llconv_portable.c new file mode 100644 index 0000000..f6d5a44 --- /dev/null +++ b/system/image/pdp_llconv_portable.c @@ -0,0 +1,82 @@ + +/* + * Pure Data Packet system implementation. : portable low level format conversion code + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +#define CLAMP(x) (((x)<0) ? 0 : ((x>255)? 255 : (x))) +#define FP(x) ((int)(((float)(x)) * 256.0f)) + +void pixel_unpack_portable_u8s16_y(unsigned char *src ,short int *dst, unsigned int nbpixels) +{ + unsigned int i; + for (i=0; i<nbpixels; i++) dst[i] = ((short int)(src[i])) << 7; +} + +void pixel_unpack_portable_u8s16_uv(unsigned char *src ,short int *dst, unsigned int nbpixels) +{ + unsigned int i; + for (i=0; i<nbpixels; i++) dst[i] = (((short int)(src[i])) << 8) ^ 0x8000; +} + + +void pixel_pack_portable_s16u8_y(short int *src, unsigned char *dst, unsigned int nbpixels) +{ + unsigned int i; + for (i=0; i<nbpixels; i++) dst[i] = (unsigned char)(CLAMP(src[i]>>7)); +} + +void pixel_pack_portable_s16u8_uv(short int *src, unsigned char *dst, unsigned int nbpixels) +{ + unsigned int i; + unsigned short *usrc = (unsigned short *)src; + for (i=0; i<nbpixels; i++) dst[i] = ((usrc[i]^0x8000)>>8); +} + + +/* convert greyscale 8 bit unsigned to 16bit signed */ +void llconv_grey_s16u8(short int *src, unsigned char *dst, unsigned int nbpixels) +{ + pixel_pack_portable_s16u8_y(src, dst, nbpixels); +} + +/* convert yvu planar 411 16 bit signed to 8 bit unsigned */ +void llconv_yvu_planar_s16u8(short int *src, unsigned char *dst, unsigned int nbpixels) +{ + pixel_pack_portable_s16u8_y(src, dst, nbpixels); + pixel_pack_portable_s16u8_uv(src + nbpixels, dst + nbpixels, nbpixels>>1); + +} + + +/* convert yvu planar 411 8 bit unsigned to yv12 planar 16bit signed */ +void llconv_yvu_planar_u8s16(unsigned char* source, short int *dest, int nbpixels) +{ + pixel_unpack_portable_u8s16_y(source, dest, nbpixels); + pixel_unpack_portable_u8s16_uv(&source[nbpixels], &dest[nbpixels], nbpixels>>1); +} + +/* convert yuv planar 411 8 bit unsigned to yv12 planar 16bit signed */ +void llconv_yuv_planar_u8s16(unsigned char* source, short int *dest, int nbpixels) +{ + pixel_unpack_portable_u8s16_y(source, dest, nbpixels); + pixel_unpack_portable_u8s16_uv(&source[nbpixels], &dest[nbpixels + (nbpixels>>2)], nbpixels>>2); + pixel_unpack_portable_u8s16_uv(&source[nbpixels + (nbpixels>>2)], &dest[nbpixels], nbpixels>>2); +} + + diff --git a/system/image/pdp_resample.c b/system/image/pdp_resample.c new file mode 100644 index 0000000..6fbd274 --- /dev/null +++ b/system/image/pdp_resample.c @@ -0,0 +1,204 @@ +/* + * Pure Data Packet system file. - image resampling routines + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +#include <string.h> +#include "pdp_resample.h" + + +/* + +efficient bilinear resampling ?? +performance: how to eliminate divides? -> virtual coordinates 2^k x 2^k (conf. opengl) + +i.e. 16 bit virtual coordinates: easy modular addressing + +*/ + + +/* code in this file should go out to be replaced by code in pdp_imageproc */ + +static s32 pdp_resample_bilin(s16 *image, s32 width, s32 height, s32 virt_x, s32 virt_y) +{ + + s32 fp_x, fp_y, frac_x, frac_y, f, offset, r_1, r_2; + + virt_x &= 0xffff; + virt_y &= 0xffff; + + fp_x = virt_x * (width - 1); + fp_y = virt_y * (height - 1); + + frac_x = fp_x & (0xffff); + frac_y = fp_y & (0xffff); + + offset = (fp_x >> 16) + (fp_y >> 16) * width; + image += offset; + + f = 0x10000 - frac_x; + + r_1 = ((f * (s32)(image[0]) + frac_x * (s32)(image[1])))>>16; + + image += width; + + r_2 = ((f * (s32)(image[0]) + frac_x * (s32)(image[1])))>>16; + + f = 0x10000 - frac_y; + + return ((f * r_1 + frac_y * r_2)>>16); + +} + + +void pdp_resample_scale_bilin(s16 *src_image, s16 *dst_image, s32 src_w, s32 src_h, s32 dst_w, s32 dst_h) +{ + s32 i,j; + s32 virt_x=0; + s32 virt_y=0; /* virtual coordinates in 30 bit */ + s32 scale_x = 0x40000000 / dst_w; + s32 scale_y = 0x40000000 / dst_h; + + for (j=0; j<dst_h; j++){ + for (i=0; i<dst_w; i++){ + *dst_image++ = pdp_resample_bilin(src_image, src_w, src_h, virt_x>>14, virt_y>>14); + virt_x += scale_x; + } + virt_x = 0; + virt_y += scale_y; + } + +} + +void pdp_resample_scale_nn(s16 *src_image, s16 *dst_image, s32 src_w, s32 src_h, s32 dst_w, s32 dst_h) +{ + s32 i,j; + s32 x=0; + s32 y=0; + s32 frac_x=0; + s32 frac_y=0; + s32 scale_x = (src_w << 20 ) / dst_w; + s32 scale_y = (src_h << 20 ) / dst_h; + + for (j=0; j<dst_h; j++){ + for (i=0; i<dst_w; i++){ + *dst_image++ = src_image[x+y]; + frac_x += scale_x; + x = frac_x >> 20; + } + x = 0; + frac_x = 0; + frac_y += scale_y; + y = (frac_y >> 20) * src_w; + } + +} + +/* USE pdp_resample_affinemap +void pdp_resample_zoom_tiled_bilin(s16 *src_image, s16 *dst_image, s32 w, s32 h, + float zoom_x, float zoom_y, float center_x_relative, float center_y_relative) +{ + float izx = 1.0f / zoom_x; + float izy = 1.0f / zoom_y; + s32 scale_x = (s32)((float)0x100000 * izx / (float)w); + s32 scale_y = (s32)((float)0x100000 * izy / (float)h); + + s32 top_virt_x = (s32)((1.0f - izx) * (float)0x100000 * center_x_relative); + s32 top_virt_y = (s32)((1.0f - izy) * (float)0x100000 * center_y_relative); + + s32 virt_x = top_virt_x; + s32 virt_y = top_virt_y; + + s32 i,j; + + for (j=0; j<h; j++){ + for (i=0; i<w; i++){ + *dst_image++ = pdp_resample_bilin(src_image, w, h, virt_x>>4, virt_y>>4); + virt_x += scale_x; + } + virt_x = top_virt_x; + virt_y += scale_y; + } + +} +*/ + +void pdp_resample_halve(s16 *src_image, s16 *dst_image, s32 src_w, s32 src_h) +{ + + int dst_x,dst_y; + int src_x = 0; + int src_y = 0; + int dst_w = src_w >> 1; + int dst_h = src_h >> 1; + s32 tmp1,tmp2,tmp3,tmp4; + + //post("%x %x %d %d\n", src_image, dst_image, src_w, src_h); + + for(dst_y = 0; dst_y < dst_h * dst_w; dst_y += dst_w){ + for (dst_x = 0; dst_x < dst_w; dst_x++){ + + tmp1 = (s32)src_image[src_y + src_x]; + tmp2 = (s32)src_image[src_y + src_x + 1]; + tmp3 = (s32)src_image[src_y + src_x + src_w]; + tmp4 = (s32)src_image[src_y + src_x + src_w + 1]; + + tmp1 += tmp2; + tmp3 += tmp4; + + src_x += 2; + + dst_image[dst_x+dst_y] = (s16)((tmp1 + tmp3)>>2); + } + src_y += src_w << 1; + src_x = 0; + } +} + +void pdp_resample_double(s16 *src_image, s16 *dst_image, s32 src_w, s32 src_h) +{ + int src_x = 0; + int src_y = 0; + int dst = 0; + int dst_w = src_w << 1; + + s16 tmp; + + for(src_y = 0; src_y < src_h * src_w; src_y += src_w){ + for (src_x = 0; src_x < src_w; src_x++){ + + tmp = *src_image++; + dst = (src_y << 2) + (src_x << 1); + dst_image[dst] = tmp; + dst_image[dst+1] = tmp; + dst+=dst_w; + dst_image[dst] = tmp; + dst_image[dst+1] = tmp; + } + } +} + +/* $$$TODO: finish this */ +void pdp_resample_padcrop(s16 *src_image, s16 *dst_image, s32 src_w, s32 src_h, s32 dst_w, s32 dst_h) +{ + + int shift_x = (dst_w - src_w) / 2; + int shift_y = (dst_h - src_h) / 2; +} + diff --git a/system/kernel/CONTENTS b/system/kernel/CONTENTS new file mode 100644 index 0000000..c2f7c8c --- /dev/null +++ b/system/kernel/CONTENTS @@ -0,0 +1,7 @@ +debug debug stuff +forth the forth system +list the list implementation +mem memory allocation stuf +packet the packet memory manager +type the type handling and conversion system +symbol symbol implementation, with namespaces for forth, types, classes, ... diff --git a/system/kernel/Makefile b/system/kernel/Makefile new file mode 100644 index 0000000..08b21cd --- /dev/null +++ b/system/kernel/Makefile @@ -0,0 +1,16 @@ + +OBJECTS = pdp_packet.o pdp_type.o pdp_dpd_command.o \ + pdp_list.o pdp_debug.o pdp_symbol.o \ + pdp_mem.o pdp_post.o + + +include ../../Makefile.config + +all: pdp_main_clean $(OBJECTS) + +pdp_main_clean: + rm -f pdp.o + +clean: + rm -f *~ + rm -f *.o diff --git a/system/kernel/pdp_debug.c b/system/kernel/pdp_debug.c new file mode 100644 index 0000000..07f6541 --- /dev/null +++ b/system/kernel/pdp_debug.c @@ -0,0 +1,21 @@ +#include <sys/types.h> +#include <signal.h> +#include <unistd.h> +#include "pdp_post.h" + +int pdp_debug_sigtrap_on_assert; + + +void pdp_assert_hook (char *condition, char *file, int line) +{ + pdp_post("PDP_ASSERT (%s) failed in file %s, line %u. ", condition, file, line); + pdp_post("%s.\n", pdp_debug_sigtrap_on_assert ? "sending SIGTRAP" : "continuing"); + + if (pdp_debug_sigtrap_on_assert) kill(getpid(), SIGTRAP); +} + + +void pdp_debug_setup(void) +{ + pdp_debug_sigtrap_on_assert = 1; +} diff --git a/system/kernel/pdp_dpd_command.c b/system/kernel/pdp_dpd_command.c new file mode 100644 index 0000000..d812cf2 --- /dev/null +++ b/system/kernel/pdp_dpd_command.c @@ -0,0 +1,87 @@ + +/* + * Pure Data Packet header file. DPD command class + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 implements a dpd command queue and command object */ + +#include "pdp_dpd_command.h" +#include "pdp_mem.h" + +void pdp_dpd_commandfactory_init(t_pdp_dpd_commandfactory *x, u32 size) +{ + x->nb_commands = 0; + x->command_size = size; + x->command = 0; +} + +void _pdp_dpd_commandfactory_free(t_pdp_dpd_command *x) +{ + if (x) _pdp_dpd_commandfactory_free(x->next); + pdp_dealloc(x); +} + +void pdp_dpd_commandfactory_free(t_pdp_dpd_commandfactory *x) +{ + _pdp_dpd_commandfactory_free(x->command); + x->command = 0; + x->nb_commands = 0; +} + + +/* factory method */ +t_pdp_dpd_command *pdp_dpd_commandfactory_get_new_command(t_pdp_dpd_commandfactory *x) +{ + + t_pdp_dpd_command *c = x->command; + t_pdp_dpd_command *oldhead = c; + + /* check if we can reuse */ + while (c){ + if (!c->used){ + c->used = 1; + //post("reusing command %x", c, c->used); + return c; + } + //post("command %x is used %d", c, c->used); + c = c->next; + } + + /* create a new command */ + x->command = (t_pdp_dpd_command *)pdp_alloc(x->command_size); + x->command->next = oldhead; + x->command->used = 1; + x->nb_commands++; + //post("created command %x, nbcommands: %d", x->command, x->nb_commands); + return x->command; + +} + + +/* (self)destructor */ +void pdp_dpd_command_suicide(void *x) +{ + t_pdp_dpd_command *c = (t_pdp_dpd_command *)x; + c->used = 0; + //post("command %x committed suicide %d", c, c->used); +} + + + + diff --git a/system/kernel/pdp_list.c b/system/kernel/pdp_list.c new file mode 100644 index 0000000..deeb7f1 --- /dev/null +++ b/system/kernel/pdp_list.c @@ -0,0 +1,931 @@ + +/* + * Pure Data Packet header file. List class + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +/* who can live without a list, hmm? + + this is sorth of a compromise between lists, queues, + stacks, lisp and forth. list contain pdp atoms + (floats, ints, symbols, pointers, packets or lists) */ + + +#include <pthread.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "pdp_list.h" +#include "pdp_symbol.h" +#include "pdp_packet.h" +#include "pdp_type.h" +#include "pdp_types.h" +#include "pdp_mem.h" +#include "pdp_post.h" +#include "pdp_debug.h" + +#define D if (0) + + +t_pdp_fastalloc *_fast_atom_allocator; +t_pdp_fastalloc *_fast_list_allocator; + + + + +static void _pdp_list_dealloc(t_pdp_list *l) +{ + pdp_fastalloc_save_atom(_fast_list_allocator, l); +} + +// allocator macros +#define PDP_ATOM_ALLOC() pdp_fastalloc_new_atom(_fast_atom_allocator) +#define PDP_ATOM_DEALLOC(x) pdp_fastalloc_save_atom(_fast_atom_allocator, x) +#define PDP_LIST_ALLOC() pdp_fastalloc_new_atom(_fast_list_allocator) +#define PDP_LIST_DEALLOC(x) _pdp_list_dealloc(x) +//#define PDP_LIST_DEALLOC(x) pdp_fastalloc_save_atom(_fast_list_allocator, x) + + + + +/* some private helper methods */ + +/* list pool setup */ +void pdp_list_setup(void) +{ + + + + /* create fast allocators */ + _fast_atom_allocator = pdp_fastalloc_new(sizeof(t_pdp_atom)); + _fast_list_allocator = pdp_fastalloc_new(sizeof(t_pdp_list)); + + /* testing code */ + if (0){ + char *next; + t_pdp_list *l = pdp_tree_from_cstring("( een twee (3 vier ()) vijf (6.0)", &next); + if (!l){ + pdp_post("parse error:"); + pdp_post(next); + } + else{ + pdp_list_print(l); + } + exit(1); + } + + +} + + + +/* create a list */ +t_pdp_list* pdp_list_new(int elements) +{ + t_pdp_atom *a = 0; + t_pdp_list *l = PDP_LIST_ALLOC(); + l->elements = 0; + + + if (elements){ + a = PDP_ATOM_ALLOC(); + l->elements++; + a->t = a_undef; + a->w.w_int = 0; + a->next = 0; + elements--; + } + l->first = a; + l->last = a; + + while (elements--){ + a = PDP_ATOM_ALLOC(); + l->elements++; + a->t = a_undef; + a->w.w_int = 0; + a->next = l->first; + l->first = a; + } + + return l; +} + +/* clear a list */ +void pdp_list_clear(t_pdp_list *l) +{ + t_pdp_atom *a = l->first; + t_pdp_atom *next_a; + + while(a){ + next_a = a->next; + PDP_ATOM_DEALLOC(a); + a = next_a; + } + + l->first = 0; + l->last = 0; + l->elements = 0; + +} + +/* destroy a list */ +void pdp_list_free(t_pdp_list *l) +{ + if (l){ + pdp_list_clear(l); + PDP_LIST_DEALLOC(l); + } +} + + +/* destroy a (sub)tree */ +void pdp_tree_free(t_pdp_list *l) +{ + if (l) { + pdp_tree_clear(l); + PDP_LIST_DEALLOC(l); + } +} + +/* clear a tree */ +void pdp_tree_clear(t_pdp_list *l) +{ + t_pdp_atom *a = l->first; + t_pdp_atom *next_a; + + + while(a){ + if (a->t == a_list){ + pdp_tree_free(a->w.w_list); + } + next_a = a->next; + PDP_ATOM_DEALLOC(a); + a = next_a; + } + + l->first = 0; + l->last = 0; + l->elements = 0; + +} + +/* BEGIN PARSER CODE */ + +/* real whitespace handling */ +static inline int _is_whitespace(char c){return (c == ' ' || c == '\n' || c == '\t');} +static inline void _skip_real_whitespace(char **c){while (_is_whitespace(**c)) (*c)++;} + +/* comment handling */ +static inline int _is_left_comment(char c) {return (c == '#');} +static inline int _is_right_comment(char c) {return (c == '\n');} +static inline void _skip_comment(char **c) +{ + if (!_is_left_comment(**c)) return; + (*c)++; + while (!_is_right_comment(**c)){ + if (!**c) return; // no terminating newline + (*c)++; + } + (*c)++; +} + +/* comment + whitespace handling */ +static inline void _skip_whitespace(char **c) +{ + char *prev_c; + /* skip comments and whitespace until the + pointer stops moving */ + do { + prev_c = *c; + _skip_real_whitespace(c); + _skip_comment(c); + } while (prev_c != *c); +} + +static inline int _is_left_separator(char c) {return (c == '(');} +static inline int _is_right_separator(char c) {return (c == ')');} +static inline int _is_terminator(char c) {return (c == 0);} + +/* the end of an atom is marked by a separator */ +static inline int _is_separator(char c) {return (_is_terminator(c) + || _is_left_separator(c) + || _is_right_separator(c) + || _is_whitespace(c));} + + +/* parse a single pure atom from a zero terminated string + a pure atom is either a number (int or float) xor a symbol +*/ + +static inline void _parse_pure_atom(t_pdp_atom *a, char *c) +{ + char *next; + + /* check if the string has a decimal point */ + int has_decimal = 0; + char *c2; + for(c2 = c; *c2; c2++){ + if (*c2 == '.') { has_decimal = 1; break; } + } + + /* try parsing as a number (int or float) first */ + if (has_decimal){ // try float + float f = strtod(c, &next); + if (next[0] == 0){ // got everything? + D pdp_post("parsing float %f", f); + a->t = a_float; + a->w = (t_pdp_word)f; + return; + } + } + else { // try int + int i = strtol(c, &next, 0); + if (next[0] == 0){ // got everything? + D pdp_post("parsing int %d", i); + a->t = a_int; + a->w = (t_pdp_word)i; + return; + } + } + + + /* number parsing failed: it's a symbol */ + D pdp_post("parsing symbol %s", c); + a->t = a_symbol; + a->w = (t_pdp_word)pdp_gensym(c); + +} + +t_pdp_atom *pdp_atom_new(void){t_pdp_atom *a = PDP_ATOM_ALLOC(); a->next = 0; return a;} +void pdp_atom_free(t_pdp_atom *a){PDP_ATOM_DEALLOC(a);} + +/* there are two parser methods: parse an atom and parse a list + both can call each other recursively. + the atoms and list are allocated with pdp_list_new and + pdp_atom_new respectively */ + +t_pdp_atom *pdp_atom_from_cstring(char *chardef, char **next) +{ + t_pdp_atom *a = 0; + + /* skip whitespace and check if there's anything left */ + _skip_whitespace(&chardef); + if (!chardef[0] || _is_right_separator(*chardef)) goto done; + + + /* check if it's a list atom */ + if(_is_left_separator(*chardef)){ + t_pdp_list *l = pdp_tree_from_cstring(chardef, &chardef); + if (l){ + a = pdp_atom_new(); + a->t = a_list; + a->w.w_list = l; + } + + } + + /* we have a pure atom, copy it to a temp buffer */ + else{ + int n = 0; + while (!_is_separator(chardef[n])) n++; + if (!n) goto done; + else { + char tmp[n+1]; + strncpy(tmp, chardef, n); + tmp[n] = 0; + a = pdp_atom_new(); + _parse_pure_atom(a, tmp); + chardef += n; + } + + } + + done: + if (next) *next = chardef; + return a; + +} + +/* check if a tree (list of lists) matches a certain type syntax + types: + + symbol -> a_sym; + int -> a_int; + float -> a_float; + packet -> a_packet; + list -> a_list; + ... -> zero or more times the preceeding elements in the list +*/ + + + +/* create a list from a character string */ +t_pdp_list *pdp_tree_from_cstring(char *chardef, char **next) +{ + t_pdp_list *l = pdp_list_new(0); + t_pdp_atom *a = 0; + + D pdp_post ("creating list from char: %s", chardef); + + /* find opening parenthesis and skip it*/ + _skip_whitespace(&chardef); + if (!_is_left_separator(*chardef)) goto error; else chardef++; + + /* chardef now points at the first atom, start adding atoms */ + while(1){ + a = pdp_atom_from_cstring(chardef, &chardef); + if (a)pdp_list_add_back_atom(l, a); + else break; + } + + /* skip whitespace and find closing parenthesis */ + _skip_whitespace(&chardef); + if (!_is_right_separator(*chardef)) goto error; else chardef++; + if (next) *next = chardef; + return l; + + error: + /* end of string encountered: parse error */ + D pdp_post("parse error: %s", chardef); + if (next) *next = chardef; + pdp_tree_free(l); //this will free all sublists too + return 0; // parse error + + + +} + +/* END PARSER CODE */ + +// this assumes syntax's syntax is correct +int pdp_tree_check_syntax(t_pdp_list *list, t_pdp_list *syntax) +{ + + t_pdp_atom *la = 0; + t_pdp_atom *sa = 0; + + t_pdp_symbol *ellipsis = pdp_gensym("..."); + t_pdp_symbol *wildcard = pdp_gensym("*"); + + /* handle empty lists */ + if (list->elements == 0){ + + /* check if syntax list is empty */ + if (syntax->elements == 0) goto match; + + /* check if syntax list has ellipsis */ + if (syntax->last->t == a_symbol && + syntax->last->w.w_symbol == ellipsis) goto match; + + /* default: no match */ + goto nomatch; + } + + + /* loop over list and syntax list */ + for (la = list->first, sa = syntax->first; + la && sa; + la = la->next, sa = sa->next){ + + D pdp_post("pdp_tree_check_syntax: starting check"); + + checkatom: + /* what do we expect for this atom ? */ + switch(sa->t){ + case a_list: + D pdp_post("expecting list"); + /* we need to recurse down the tree */ + /* exit if the current list to check + does not have a sublist */ + if (la->t != a_list) { + D pdp_post("not a list"); + goto nomatch; + } + + /* recurse and exit if no match */ + D pdp_post("checking sublist"); + if (!pdp_tree_check_syntax(la->w.w_list, sa->w.w_list)){ + D pdp_post("sublist does not match"); + goto nomatch; + } + + break; + + case a_symbol: + + /* if ellipsis, rewind */ + if (ellipsis == sa->w.w_symbol){ + D pdp_post("got ellipsis"); + /* check if we're not looping */ + if (sa == syntax->first){ + D pdp_post("ellipsis at start of list"); + goto nomatch; + } + /* try again */ + sa = syntax->first; + D pdp_post("ellipsis rewind"); + goto checkatom; + } + + else if (wildcard == sa->w.w_symbol){ + D pdp_post("got wildcard"); + } + + /* ordinary atom: check type */ + else{ + D pdp_post("expecting %s", sa->w.w_symbol->s_name); + switch(la->t){ + + case a_int: + if (sa->w.w_symbol != pdp_gensym("int")) goto nomatch; break; + case a_float: + if (sa->w.w_symbol != pdp_gensym("float")) goto nomatch; break; + case a_symbol: + if (sa->w.w_symbol != pdp_gensym("symbol")) goto nomatch; break; + case a_packet: + if (sa->w.w_symbol != pdp_gensym("packet")) goto nomatch; break; + case a_list: + if (sa->w.w_symbol != pdp_gensym("list")) goto nomatch; break; + + default: + goto nomatch; + } + D pdp_post("OK"); + } + + break; + + default: + D pdp_post("syntax syntax error"); + pdp_list_print(syntax); + goto nomatch; // incorrect syntax description + } + + } + + /* loop ended because one of the lists was finished */ + /* only two cases can be valid: la == 0 and (sa == 0 or ellipsis) */ + + if (la != 0){ + D pdp_post("not end of list -> no match"); + goto nomatch; + } + + if (sa == 0) goto match; + + if (!(sa->t == a_symbol && sa->w.w_symbol == ellipsis)){ + D pdp_post("syntax list not in ellipsis position -> no match"); + goto nomatch; + } + + + /* exits */ + match: + D pdp_post("pdp_tree_check_syntax: match"); + return 1; + nomatch: + D pdp_post("pdp_tree_check_syntax: no match"); + return 0; + +} + + + +/* traversal */ +void pdp_list_apply(t_pdp_list *l, t_pdp_atom_method m) +{ + t_pdp_atom *a; + if (!l) return; + for (a=l->first; a; a=a->next) m(a); +} + +void pdp_tree_apply(t_pdp_list *l, t_pdp_atom_method m) +{ + t_pdp_atom *a; + if (!l) return; + for (a=l->first; a; a=a->next){ + if (a->t == a_list) pdp_tree_apply(a->w.w_list, m); + else m(a); + } +} + +void pdp_list_apply_word_method(t_pdp_list *l, + t_pdp_word_type type, t_pdp_word_method wm) +{ + t_pdp_atom *a; + if (!l) return; + for (a=l->first; a; a=a->next){ + if (a->t == type) wm(a->w); + } +} +void pdp_list_apply_pword_method(t_pdp_list *l, + t_pdp_word_type type, t_pdp_pword_method pwm) +{ + t_pdp_atom *a; + if (!l) return; + for (a=l->first; a; a=a->next){ + if (a->t == type) pwm(&a->w); + } +} + +void pdp_tree_apply_word_method(t_pdp_list *l, + t_pdp_word_type type, t_pdp_word_method wm) +{ + t_pdp_atom *a; + if (!l) return; + for (a=l->first; a; a=a->next){ + if (a->t == a_list) pdp_tree_apply_word_method(a->w.w_list, type, wm); + else if (a->t == type) wm(a->w); + } +} +void pdp_tree_apply_pword_method(t_pdp_list *l, + t_pdp_word_type type, t_pdp_pword_method pwm) +{ + t_pdp_atom *a; + if (!l) return; + for (a=l->first; a; a=a->next){ + if (a->t == a_list) pdp_tree_apply_pword_method(a->w.w_list, type ,pwm); + else if (a->t == type) pwm(&a->w); + } +} + +static void _atom_packet_mark_unused(t_pdp_atom *a) +{ + if (a->t == a_packet){ + pdp_packet_mark_unused(a->w.w_packet); + a->w.w_packet = -1; + } +} + +static void _atom_packet_copy_ro(t_pdp_atom *a) +{ + int p; + if (a->t == a_packet){ + a->w.w_packet = pdp_packet_copy_ro(a->w.w_packet); + } +} + +void pdp_tree_strip_packets (t_pdp_list *l) +{ + pdp_tree_apply(l, _atom_packet_mark_unused); +} + +static void _pdp_tree_copy_ro_packets (t_pdp_list *l) +{ + pdp_tree_apply(l, _atom_packet_copy_ro); +} + +t_pdp_list *pdp_tree_copy_ro(t_pdp_list *l) +{ + t_pdp_list *l2 = pdp_tree_copy(l); + _pdp_tree_copy_ro_packets(l2); + return l2; +} + +static void _pdp_atomlist_fprint(FILE* f, t_pdp_atom *a); + +static void _pdp_atom_fprint(FILE* f, t_pdp_atom *a) +{ + if (!a){ + fprintf(f, "<NULL ATOM>"); + return; + } + + switch(a->t){ + /* generic atoms */ + case a_symbol: fprintf(f, "%s",a->w.w_symbol->s_name); break; + case a_float: fprintf(f, "%f",a->w.w_float); break; + case a_int: fprintf(f, "%d",a->w.w_int); break; + case a_packet: fprintf(f, "#<pdp %d %s>",a->w.w_packet, + pdp_packet_get_description(a->w.w_packet)->s_name); break; + case a_pointer: fprintf(f, "#<0x%08x>", a->w.w_int); break; + case a_list: _pdp_atomlist_fprint(f, a->w.w_list->first); break; + case a_atom_pointer: + fprintf(f, "->"); + _pdp_atom_fprint(f, a->w.w_atom_pointer); + break; + case a_undef: fprintf(f, "<undef>"); break; + + /* forth atoms */ + case a_forthword: fprintf(f, "#<forth word 0x%08x>", a->w.w_int); break; + case a_vmword: fprintf(f, "#<vm word 0x%08x>", a->w.w_int); break; + case a_vmmacro: fprintf(f, "#<vm macro 0x%08x>", a->w.w_int); break; + + + default: fprintf(f, "<unknown type>"); break; + } +} + +/* debug */ +static void _pdp_atomlist_fprint(FILE* f, t_pdp_atom *a) +{ + fprintf(f, "("); + while (a){ + _pdp_atom_fprint(f,a); + a = a->next; + if (a) fprintf(f, " "); + } + fprintf(f, ")"); +} + +void _pdp_list_fprint(FILE* f, t_pdp_list *l) +{ + _pdp_atomlist_fprint(f, l->first); + fprintf(f, "\n"); +} + +void pdp_list_print(t_pdp_list *l) +{ + _pdp_list_fprint(stderr, l); +} + +void pdp_atom_print(t_pdp_atom *a) +{ + _pdp_atom_fprint(stderr, a); +} + +/* public list operations */ + + + + +/* add a atom/word to the start of the list */ +void pdp_list_add_atom(t_pdp_list *l, t_pdp_atom *a) +{ + a->next = l->first; + l->first = a; + l->elements++; + if (!l->last) l->last = a; +} + +void pdp_list_add(t_pdp_list *l, t_pdp_word_type t, t_pdp_word w) +{ + t_pdp_atom *a = PDP_ATOM_ALLOC(); + a->t = t; + a->w = w; + pdp_list_add_atom(l, a); +} + + +/* add a word to the end of the list */ +void pdp_list_add_back_atom(t_pdp_list *l, t_pdp_atom *a) +{ + + l->elements++; + a->next = 0; + if (l->last){ + l->last->next = a; + } + else{ + l->first = a; + } + l->last = a; +} + +void pdp_list_add_back(t_pdp_list *l, t_pdp_word_type t, t_pdp_word w) +{ + t_pdp_atom *a = PDP_ATOM_ALLOC(); + a->w = w; + a->t = t; + pdp_list_add_back_atom(l, a); +} + +/* get list size */ +int pdp_list_size(t_pdp_list *l) +{ + return l->elements; +} + + + + +/* pop: return first item and remove */ +t_pdp_atom *pdp_list_pop_atom(t_pdp_list *l) +{ + t_pdp_atom *a = l->first; + if (!a) return a; + + l->first = a->next; + l->elements--; + if (!l->first) l->last = 0; + a->next = 0; // detach + return a; +} + + +/* pop: return first item and remove */ +t_pdp_word pdp_list_pop(t_pdp_list *l) +{ + t_pdp_atom *a = pdp_list_pop_atom(l); + t_pdp_word w=a->w; + PDP_ATOM_DEALLOC(a); + return w; +} + + + + +/* pop from one list and push to other */ +void pdp_list_pop_push(t_pdp_list *source, t_pdp_list *dest) +{ + t_pdp_atom *a = source->first; + + /* pop atom */ + if (--(source->elements)){source->last = 0;} + source->first = a->next; + + /* push atom */ + a->next = dest->first; + if (dest->elements++) {dest->last = a;} + dest->first = a; + + return; + +} + + +/* return element at index */ +t_pdp_word pdp_list_index(t_pdp_list *l, int index) +{ + t_pdp_atom *a; + for (a = l->first; index--; a = a->next); + return a->w; +} + + + + + +/* remove an element from a list */ +void pdp_list_remove(t_pdp_list *l, t_pdp_word_type t, t_pdp_word w) +{ + t_pdp_atom head; + t_pdp_atom *a; + t_pdp_atom *kill_a; + head.next = l->first; + + for(a = &head; a->next; a = a->next){ + if (a->next->w.w_int == w.w_int && a->next->t == t){ + kill_a = a->next; // element to be killed + a->next = a->next->next; // remove link + PDP_ATOM_DEALLOC(kill_a); + l->elements--; + l->first = head.next; // restore the start pointer + if (l->last == kill_a) { // restore the end pointer + l->last = (a != &head) ? a : 0; + } + + break; + } + } + +} + + + + + +/* copy a list */ +t_pdp_list* pdp_tree_copy_reverse(t_pdp_list *list) +{ + t_pdp_list *newlist = pdp_list_new(0); + t_pdp_atom *a; + for (a = list->first; a; a = a->next) + if (a->t == a_list){ + pdp_list_add(newlist, a->t, + (t_pdp_word)pdp_tree_copy_reverse(a->w.w_list)); + } + else{ + pdp_list_add(newlist, a->t, a->w); + } + return newlist; +} +t_pdp_list* pdp_list_copy_reverse(t_pdp_list *list) +{ + t_pdp_list *newlist = pdp_list_new(0); + t_pdp_atom *a; + for (a = list->first; a; a = a->next) + pdp_list_add(newlist, a->t, a->w); + return newlist; +} + +t_pdp_list* pdp_tree_copy(t_pdp_list *list) +{ + t_pdp_list *newlist = pdp_list_new(list->elements); + t_pdp_atom *a_src = list->first; + t_pdp_atom *a_dst = newlist->first; + + while(a_src){ + a_dst->t = a_src->t; + if (a_dst->t == a_list){ //recursively copy sublists (tree copy) + a_dst->w.w_list = pdp_tree_copy(a_src->w.w_list); + } + else{ + a_dst->w = a_src->w; + } + a_src = a_src->next; + a_dst = a_dst->next; + } + + return newlist; +} +t_pdp_list* pdp_list_copy(t_pdp_list *list) +{ + t_pdp_list *newlist = pdp_list_new(list->elements); + t_pdp_atom *a_src = list->first; + t_pdp_atom *a_dst = newlist->first; + + while(a_src){ + a_dst->t = a_src->t; + a_dst->w = a_src->w; + a_src = a_src->next; + a_dst = a_dst->next; + } + return newlist; +} + +void pdp_list_join (t_pdp_list *l, t_pdp_list *tail) +{ + if (tail->elements){ + l->elements += tail->elements; + if (l->last){ + l->last->next = tail->first; + l->last = tail->last; + } + else { + l->first = tail->first; + l->last = tail->last; + } + } + PDP_LIST_DEALLOC(tail); //delete the tail header +} + +void pdp_list_cat (t_pdp_list *l, t_pdp_list *tail) +{ + t_pdp_list *tmp = pdp_list_copy(tail); + pdp_list_join(l, tmp); +} + + +/* in place reverse: atoms stay the same + they are just relinked. so pointers will stay accurate */ +void pdp_list_reverse(t_pdp_list *l) +{ + t_pdp_list tmp; + t_pdp_atom *a; + tmp.first = l->first; + tmp.last = l->last; + tmp.elements = l->elements; + l->first = 0; + l->last = 0; + l->elements = 0; + while (a = pdp_list_pop_atom(&tmp)){ + pdp_list_add_atom(l, a); + } +} + +void pdp_list_reverse_old(t_pdp_list *l) +{ + t_pdp_list *l2 = pdp_list_copy_reverse(l); + pdp_list_clear(l); + l->first = l2->first; + l->last = l2->last; + l->elements = l2->elements; + _pdp_list_dealloc(l2); +} + +/* check if a list contains an element */ +int pdp_list_contains(t_pdp_list *list, t_pdp_word_type t, t_pdp_word w) +{ + t_pdp_atom *a; + for(a = list->first; a; a=a->next){ + if (a->w.w_int == w.w_int && a->t == t) return 1; + } + return 0; +} + +/* add a thing to the start of the list if it's not in there already */ +void pdp_list_add_to_set(t_pdp_list *list, t_pdp_word_type t, t_pdp_word w) +{ + if (!pdp_list_contains(list, t, w)) + pdp_list_add(list, t, w); +} + + + + diff --git a/system/kernel/pdp_mem.c b/system/kernel/pdp_mem.c new file mode 100644 index 0000000..33822ef --- /dev/null +++ b/system/kernel/pdp_mem.c @@ -0,0 +1,129 @@ +/* + * Pure Data Packet system file: memory allocation + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +#include <stdlib.h> +#include "pdp_mem.h" +#include "pdp_debug.h" + + +/* malloc wrapper that calls garbage collector */ +void *pdp_alloc(int size) +{ + void *ptr = malloc(size); + + PDP_ASSERT(ptr); + + return ptr; + + //TODO: REPAIR THIS + //post ("malloc failed in a pdp module: running garbage collector."); + //pdp_pool_collect_garbage(); + //return malloc(size); +} + + +void pdp_dealloc(void *stuff) +{ + free (stuff); +} + + +/* fast atom allocation object + well, this is not too fast yet, but will be later + when it suports linux futexes or atomic operations */ + +//#include <pthread.h> + +/* private linked list struct */ +typedef struct _fastalloc +{ + struct _fastalloc * next; +} t_fastalloc; + + + + +static void _pdp_fastalloc_lock(t_pdp_fastalloc *x){pthread_mutex_lock(&x->mut);} +static void _pdp_fastalloc_unlock(t_pdp_fastalloc *x){pthread_mutex_unlock(&x->mut);} + +static void _pdp_fastalloc_refill_freelist(t_pdp_fastalloc *x) +{ + t_fastalloc *atom; + unsigned int i; + + PDP_ASSERT(x->freelist == 0); + + /* get a new block + there is no means of freeing the data afterwards, + this is a fast implementation with the tradeoff of data + fragmentation "memory leaks".. */ + + x->freelist = pdp_alloc(x->block_elements * x->atom_size); + + /* link all atoms together */ + atom = x->freelist; + for (i=0; i<x->block_elements-1; i++){ + atom->next = (t_fastalloc *)(((char *)atom) + x->atom_size); + atom = atom->next; + } + atom->next = 0; + +} + +void *pdp_fastalloc_new_atom(t_pdp_fastalloc *x) +{ + t_fastalloc *atom; + + _pdp_fastalloc_lock(x); + + /* get an atom from the freelist + or refill it and try again */ + while (!(atom = x->freelist)){ + _pdp_fastalloc_refill_freelist(x); + } + + /* delete the element from the freelist */ + x->freelist = x->freelist->next; + atom->next = 0; + + _pdp_fastalloc_unlock(x); + + return (void *)atom; + +} +void pdp_fastalloc_save_atom(t_pdp_fastalloc *x, void *atom) +{ + _pdp_fastalloc_lock(x); + ((t_fastalloc *)atom)->next = x->freelist; + x->freelist = (t_fastalloc *)atom; + _pdp_fastalloc_unlock(x); +} + +t_pdp_fastalloc *pdp_fastalloc_new(unsigned int size) +{ + t_pdp_fastalloc *x = pdp_alloc(sizeof(*x)); + if (size < sizeof(t_fastalloc)) size = sizeof(t_fastalloc); + x->freelist = 0; + x->atom_size = size; + x->block_elements = PDP_FASTALLOC_BLOCK_ELEMENTS; + pthread_mutex_init(&x->mut, NULL); + return x; +} + diff --git a/system/kernel/pdp_packet.c b/system/kernel/pdp_packet.c new file mode 100644 index 0000000..0eb569a --- /dev/null +++ b/system/kernel/pdp_packet.c @@ -0,0 +1,634 @@ +/* + * Pure Data Packet system implementation: Packet Manager + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include <stdio.h> +#include <pthread.h> +#include <unistd.h> +#include <string.h> +#include "pdp_post.h" +#include "pdp_packet.h" +#include "pdp_mem.h" +#include "pdp_list.h" +#include "pdp_type.h" +#include "pdp_debug.h" + + +/* packet implementation. contains class and packet (instance) handling + + some notes on packet operations. + copy ro/rw and unregister are relatively straightforward + packet creation can be done in 2 ways in this interface: + create + reuse + however, these methods should only be called by specific factory + methods, so the user should only create packets using pdp_factory_newpacket + + reuse or create is thus the responsability of the factory methods for + each packet type (class) implementation + + +*/ + + +/* NOTE: + the packet pool methods are called within the pool locks. this probably + needs to change, because it will cause deadlocks for container packets (fobs) */ + + +/* new implementation: probably just a minor adjustment: add the reuse fifo attached + to type desc symbol name + need to check and possibly eliminate hacks for non-pure packets + + pdp_packet_new: + LOCK + 1. check reuse fifo + 2. empty -> create packet+return (search array) + 3. element -> check if type is correct, yes->pop+return, no->goto 1. + UNLOCK + 4. wakeup + + pdp_packet_mark_unused + + 1. check refcount. if > 1 dec + exit + 2. if 1 put packet to sleep + 3. dec refcount + 4. add to reuse fifo (no fifo -> create) + + pdp_packet_delete: analogous to mark_unused + pdp_packet_copy_ro/rw: analogous to new + +*/ + + +/* the pool */ +#define PDP_INITIAL_POOL_SIZE 64 +static int pdp_pool_size; +static t_pdp** pdp_pool; + +/* mutex: protects the pool and reuse lists attached to symbols */ +static pthread_mutex_t pdp_pool_mutex; +#define LOCK pthread_mutex_lock (&pdp_pool_mutex) +#define UNLOCK pthread_mutex_unlock (&pdp_pool_mutex) + +/* the list of classes */ +static t_pdp_list *class_list; + +/* debug */ +void +pdp_packet_print_debug(int packet) +{ + t_pdp *h = pdp_packet_header(packet); + pdp_post("debug info for packet %d", packet); + if (!h){ + pdp_post("invalid packet"); + } + else{ + pdp_post ("\ttype: %d", h->type); + pdp_post ("\tdesc: %s", h->desc ? h->desc->s_name : "unknown"); + pdp_post ("\tsize: %d", h->size); + pdp_post ("\tflags: %x", h->flags); + pdp_post ("\tusers: %d", h->users); + pdp_post ("\tclass: %x", h->theclass); + } +} + + + +/* setup methods */ + +void +pdp_packet_setup(void) +{ + + pdp_pool_size = PDP_INITIAL_POOL_SIZE; + pdp_pool = (t_pdp **)pdp_alloc(PDP_INITIAL_POOL_SIZE * sizeof(t_pdp *)); + bzero(pdp_pool, pdp_pool_size * sizeof(t_pdp *)); + class_list = pdp_list_new(0); + pthread_mutex_init(&pdp_pool_mutex, NULL); +} + +/* class methods */ +t_pdp_class *pdp_class_new(t_pdp_symbol *type, t_pdp_factory_method create){ + t_pdp_class *c = (t_pdp_class *)pdp_alloc(sizeof(t_pdp_class)); + memset(c, 0, sizeof(t_pdp_class)); + c->create = create; + c->type = type; // set type + pdp_list_add(class_list, a_pointer, (t_pdp_word)((void *)c)); + return c; +} + +/* the packet factory */ +int pdp_factory_newpacket(t_pdp_symbol *type) +{ + int p; + t_pdp_class *c; + t_pdp_atom *a = class_list->first; + + /* try to reuse first + THINK: should this be the responsability of the type specific constructors, + or should a packet allways be reusable (solution: depends on what the cleanup method returns??) + */ + p = pdp_packet_reuse(type); + if (-1 != p) return p; + + + /* call class constructor */ + while(a){ + c = (t_pdp_class *)(a->w.w_pointer); + if (c->type && pdp_type_description_match(type, c->type)){ + //pdp_post("method %x, type %s", c->create, type->s_name); + return (c->create) ? (*c->create)(type) : -1; + } + a = a->next; + } + return -1; +} + +static void +_pdp_pool_expand_nolock(void){ + int i; + + /* double the size */ + int new_pool_size = pdp_pool_size << 1; + t_pdp **new_pool = (t_pdp **)pdp_alloc(new_pool_size * sizeof(t_pdp *)); + bzero(new_pool, new_pool_size * sizeof(t_pdp *)); + memcpy(new_pool, pdp_pool, pdp_pool_size * sizeof(t_pdp *)); + pdp_dealloc(pdp_pool); + pdp_pool = new_pool; + pdp_pool_size = new_pool_size; +} + + + + +/* private _pdp_packet methods */ + +/* packets can only be created and destroyed using these 2 methods */ +/* it updates the mem usage and total packet count */ + +static void +_pdp_packet_dealloc_nolock(t_pdp *p) +{ + /* free memory */ + pdp_dealloc (p); +} + +static t_pdp* +_pdp_packet_alloc_nolock(unsigned int datatype, unsigned int datasize) +{ + unsigned int totalsize = datasize + PDP_HEADER_SIZE; + t_pdp *p = (t_pdp *)pdp_alloc(totalsize); + if (p){ + memset(p, 0, PDP_HEADER_SIZE); //initialize header to 0 + p->type = datatype; + p->size = totalsize; + p->users = 1; + } + return p; +} + + +/* create a new packet and expand pool if necessary */ +static int +_pdp_packet_create_nolock(unsigned int datatype, unsigned int datasize) +{ + int p = 0; + while(1){ + for (; p < pdp_pool_size; p++){ + if (!pdp_pool[p]){ + /* found slot to store packet*/ + t_pdp *header = _pdp_packet_alloc_nolock(datatype, datasize); + if (!header) return -1; // error allocating packet + pdp_pool[p] = header; + return p; + } + } + /* no slot found, expand pool */ + _pdp_pool_expand_nolock(); + } +} + + +void +pdp_packet_destroy(void) +{ + int i = 0; + /* dealloc all the data in object stack */ + pdp_post("DEBUG: pdp_packet_destroy: clearing object pool."); + while ((i < pdp_pool_size) && (pdp_pool[i])) _pdp_packet_dealloc_nolock(pdp_pool[i++]); +} + + + + + + + + +/* public pool operations: have to be thread safe so each entry point + locks the mutex */ + + +/* create a new packet. + this should only be used by type specific factory methods, and only if the + reuse method fails, since it will always create a new packet */ +int +pdp_packet_create(unsigned int datatype, unsigned int datasize /*without header*/) +{ + int packet; + LOCK; + packet = _pdp_packet_create_nolock(datatype, datasize); + UNLOCK; + return packet; +} + + +/* return a new packet. + it tries to reuse a packet based on + 1. matching data size + 2. abscence of destructor (which SHOULD mean there are no enclosed references) + + it obviously can't use the reuse fifo tagged to a symbolic type description + + ALWAYS USE pdp_packet_reuse BEFORE calling pdp_packet_new if possible + use both ONLY IN CONSTRUCTORS !!! + + use pdp_packet_factory to create packets as a "user" + + this is a summary of all internal packet creation mechanisms: + + -> pdp_packet_reuse, which uses symbolic type descriptions, and should work for all packet types + it returns an initialized container (meta = correct, data = garbage) + + -> pdp_packet_new, which only works for non-pure packets, and reuses packets based on data type + it returns a pure packet (meta + data = garbage) + + -> pdp_packet_create, like pdp_packet_new, only it always creates a new packet + + + +*/ + +int +pdp_packet_new(unsigned int datatype, unsigned int datasize) +{ + t_pdp *header; + int packet; + LOCK; + for (packet = 0; packet < pdp_pool_size; packet++){ + header = pdp_pool[packet]; + /* check data size */ + if (header + && header->users == 0 // must be unused + && header->size == datasize + PDP_HEADER_SIZE // must be same size + && !(header->theclass && header->theclass->cleanup)){ // must be pure packet (no destructor) + + /* ok, got one. initialize */ + memset(header, 0, PDP_HEADER_SIZE); + header->users = 1; + header->type = datatype; + header->size = datasize + PDP_HEADER_SIZE; + + UNLOCK; //EXIT1 + return packet; + } + } + + /* no usable non-pure packet found, create a new one */ + + UNLOCK; //EXIT2 + return pdp_packet_create(datatype, datasize); + + + +} + + +/* internal method to add a packet to a packet type + description symbol's unused packet fifo */ +void +_pdp_packet_save_nolock(int packet) +{ + t_pdp *header = pdp_packet_header(packet); + t_pdp_symbol *s; + PDP_ASSERT(header); + PDP_ASSERT(header->users == 0); + PDP_ASSERT(header->desc); + s = header->desc; + if (!s->s_reusefifo) s->s_reusefifo = pdp_list_new(0); + pdp_list_add(s->s_reusefifo, a_packet, (t_pdp_word)packet); +} + +/* this will revive a packet matching a certain type description + no wildcards are allowed */ +int +pdp_packet_reuse(t_pdp_symbol *type_description) +{ + int packet = -1; + t_pdp *header = 0; + t_pdp_list *l = 0; + LOCK; + if (!type_description || !(l = type_description->s_reusefifo)) goto exit; + while(l->elements){ + packet = pdp_list_pop(l).w_packet; + header = pdp_packet_header(packet); + + /* check if reuse fifo is consistent (packet unused + correct type) + packet could be deleted and replaced with another one, or + revived without the index updated (it's a "hint cache") */ + + if (header->users == 0){ + /* check if type matches */ + if (pdp_type_description_match(header->desc, type_description)){ + header->users++; // revive + goto exit; + } + /* if not, add the packet to the correct reuse fifo */ + else{ + _pdp_packet_save_nolock(packet); + } + } + + /* remove dangling refs */ + header = 0; + packet = -1; + } + + exit: + UNLOCK; + if (header && header->theclass && header->theclass->wakeup){ + header->theclass->wakeup(header); // revive if necessary + } + return packet; +} + +/* find all unused packets in pool, marked as used (to protect from other reapers) + and return them as a list. non-pure packets are not revived */ + + + + + +/* this returns a copy of a packet for read only access. + (increases refcount of the packet -> packet will become readonly if it was + writable, i.e. had rc=1 */ + +int +pdp_packet_copy_ro(int handle) +{ + t_pdp* header; + + if (header = pdp_packet_header(handle)){ + PDP_ASSERT(header->users); // consistency check + LOCK; + header->users++; // increment reference count + UNLOCK; + } + else handle = -1; + return handle; +} + +/* clone a packet: create a new packet with the same + type as the source packet */ + +int +pdp_packet_clone_rw(int handle) +{ + t_pdp* header; + int new_handle = -1; + + + if (header = pdp_packet_header(handle)){ + /* consistency checks */ + PDP_ASSERT(header->users); + PDP_ASSERT(header->desc); + + /* first try to reuse old packet */ + new_handle = pdp_packet_reuse(header->desc); + + /* if this failed, create a new one using the central packet factory method */ + if (-1 == new_handle) new_handle = pdp_factory_newpacket(header->desc); + + /* if the factory method failed cline it manually */ + if (-1 == new_handle) { + t_pdp *new_header; + //pdp_post("WARNING: pdp_clone_rw: working around non-implemented factory method."); + new_handle = pdp_packet_new(header->type, header->size - PDP_HEADER_SIZE); + new_header = pdp_packet_header(new_handle); + if (new_header){ + memcpy(new_header, header, PDP_HEADER_SIZE); + } + } + } + + return new_handle; +} + +/* return a copy of a packet (clone + copy data) */ +int +pdp_packet_copy_rw(int handle) +{ + t_pdp *header, *new_header; + int new_handle = -1; + + if (!(header = pdp_packet_header(handle))) return -1; + + /* check if we are allowed to copy */ + if (header->flags & PDP_FLAG_DONOTCOPY) return -1; + + /* get target packet */ + new_handle = pdp_packet_clone_rw(handle); + if (-1 == new_handle) return -1; + new_header = pdp_packet_header(new_handle); + + /* if there is a copy method, use that one */ + if (header->theclass && header->theclass->copy){ + header->theclass->copy(header, new_header); + } + + /* otherwize copy the data verbatim */ + else { + memcpy(pdp_packet_data(new_handle), + pdp_packet_data(handle), + pdp_packet_data_size(handle)); + } + + return new_handle; + +} + + +/* decrement refcount */ +void pdp_packet_mark_unused(int handle) +{ + t_pdp *header; + if (!(header = pdp_packet_header(handle))) return; + + PDP_ASSERT(header->users); // consistency check + + LOCK; + + /* just decrement refcount */ + if (header->users > 1){ + header->users--; + } + + /* put packet to sleep if refcount 1->0 */ + else { + if (header->theclass && header->theclass->sleep){ + /* call sleep method (if any) outside of lock + while the packet is still alive, so it won't be + acclaimed by another thread */ + UNLOCK; + header->theclass->sleep(header); + LOCK; + } + /* clear refcount & save in fifo for later use */ + header->users = 0; + if (header->desc) // sleep could have destructed packet.. + _pdp_packet_save_nolock(handle); + } + + UNLOCK; +} + + + +/* delete a packet. rc needs to be == 1 */ +void pdp_packet_delete(int handle) +{ + t_pdp *header; + header = pdp_packet_header(handle); + PDP_ASSERT(header); + PDP_ASSERT(header->users == 1); // consistency check + + LOCK; + + if (header->theclass && header->theclass->cleanup){ + /* call cleanup method (if any) outside of lock + while the packet is still alive, so it won't be + acclaimed by another thread */ + UNLOCK; + header->theclass->cleanup(header); + LOCK; + } + + /* delete the packet */ + pdp_pool[handle] = 0; + _pdp_packet_dealloc_nolock(header); + + + UNLOCK; +} + + + + + + + +/* public data access methods */ + +t_pdp* +pdp_packet_header(int handle) +{ + if ((handle >= 0) && (handle < pdp_pool_size)) return pdp_pool[handle]; + else return 0; +} + +void* +pdp_packet_subheader(int handle) +{ + t_pdp* header = pdp_packet_header(handle); + if (!header) return 0; + return (void *)(&header->info.raw); +} + +void* +pdp_packet_data(int handle) +{ + t_pdp *h; + if ((handle >= 0) && (handle < pdp_pool_size)) + { + h = pdp_pool[handle]; + if (!h) return 0; + return (char *)(h) + PDP_HEADER_SIZE; + } + else return 0; +} + +int +pdp_packet_data_size(int handle) +{ + t_pdp *h; + if ((handle >= 0) && (handle < pdp_pool_size)) + { + h = pdp_pool[handle]; + if (!h) return 0; + return h->size - PDP_HEADER_SIZE; + } + else return 0; +} + + + + +int pdp_packet_writable(int packet) /* returns true if packet is writable */ +{ + t_pdp *h = pdp_packet_header(packet); + if (!h) return 0; + return (h->users == 1); +} + +void pdp_packet_replace_with_writable(int *packet) /* replaces a packet with a writable copy */ +{ + int new_p; + if (!pdp_packet_writable(*packet)){ + new_p = pdp_packet_copy_rw(*packet); + pdp_packet_mark_unused(*packet); + *packet = new_p; + } + +} + +/* pool stuff */ + +int +pdp_pool_collect_garbage(void) +{ + pdp_post("ERROR: garbage collector not implemented"); + return 0; +} + +void +pdp_pool_set_max_mem_usage(int max) +{ + pdp_post("ERROR: mem limit not implemented"); +} + + + + + + +#ifdef __cplusplus +} +#endif diff --git a/system/kernel/pdp_packet2.c b/system/kernel/pdp_packet2.c new file mode 100644 index 0000000..3717a77 --- /dev/null +++ b/system/kernel/pdp_packet2.c @@ -0,0 +1,623 @@ +/* + * Pure Data Packet system implementation: Packet Manager + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + + +#include <stdio.h> +#include <pthread.h> +#include <unistd.h> +#include <string.h> +#include "pdp_post.h" +#include "pdp_packet.h" +#include "pdp_mem.h" +#include "pdp_list.h" +#include "pdp_type.h" +#include "pdp_debug.h" + + +/* packet implementation. contains class and packet (instance) handling + + some notes on packet operations. + copy ro/rw and unregister are relatively straightforward + packet creation can be done in 2 ways in this interface: + create + reuse + however, these methods should only be called by specific factory + methods, so the user should only create packets using pdp_factory_newpacket + + reuse or create is thus the responsability of the factory methods for + each packet type (class) implementation + + +*/ + + +/* NOTE: + the packet pool methods are called within the pool locks. this probably + needs to change, because it will cause deadlocks for container packets (fobs) */ + + +/* new implementation: probably just a minor adjustment: add the reuse fifo attached + to type desc symbol name + need to check and possibly eliminate hacks for non-pure packets + + pdp_packet_new: + LOCK + 1. check reuse fifo + 2. empty -> create packet+return (search array) + 3. element -> check if type is correct, yes->pop+return, no->goto 1. + UNLOCK + 4. wakeup + + pdp_packet_mark_unused + + 1. check refcount. if > 1 dec + exit + 2. if 1 put packet to sleep + 3. dec refcount + 4. add to reuse fifo (no fifo -> create) + + pdp_packet_delete: analogous to mark_unused + pdp_packet_copy_ro/rw: analogous to new + +*/ + + +/* the pool */ +#define PDP_INITIAL_POOL_SIZE 64 +static int pdp_pool_size; +static t_pdp** pdp_pool; + +/* mutex: protects the pool and reuse lists attached to symbols */ +static pthread_mutex_t pdp_pool_mutex; +#define LOCK pthread_mutex_lock (&pdp_pool_mutex) +#define UNLOCK pthread_mutex_unlock (&pdp_pool_mutex) + +/* the list of classes */ +static t_pdp_list *class_list; + +/* debug */ +void +pdp_packet_print_debug(int packet) +{ + t_pdp *h = pdp_packet_header(packet); + pdp_post("debug info for packet %d", packet); + if (!h){ + pdp_post("invalid packet"); + } + else{ + pdp_post ("\ttype: %d", h->type); + pdp_post ("\tdesc: %s", h->desc ? h->desc->s_name : "unknown"); + pdp_post ("\tsize: %d", h->size); + pdp_post ("\tflags: %x", h->flags); + pdp_post ("\tusers: %d", h->users); + pdp_post ("\tclass: %x", h->theclass); + } +} + + + +/* setup methods */ + +void +pdp_packet_setup(void) +{ + + pdp_pool_size = PDP_INITIAL_POOL_SIZE; + pdp_pool = (t_pdp **)pdp_alloc(PDP_INITIAL_POOL_SIZE * sizeof(t_pdp *)); + bzero(pdp_pool, pdp_pool_size * sizeof(t_pdp *)); + class_list = pdp_list_new(0); + pthread_mutex_init(&pdp_pool_mutex, NULL); +} + +/* class methods */ +t_pdp_class *pdp_class_new(t_pdp_symbol *type, t_pdp_factory_method create){ + t_pdp_class *c = (t_pdp_class *)pdp_alloc(sizeof(t_pdp_class)); + memset(c, 0, sizeof(t_pdp_class)); + c->create = create; + c->type = type; // set type + pdp_list_add(class_list, a_pointer, (t_pdp_word)((void *)c)); + return c; +} + +/* the packet factory */ +int pdp_factory_newpacket(t_pdp_symbol *type) +{ + int p; + t_pdp_class *c; + t_pdp_atom *a = class_list->first; + + /* try to reuse first + THINK: should this be the responsability of the type specific constructors, + or should a packet allways be reusable (solution: depends on what the cleanup method returns??) + */ + p = pdp_packet_reuse(type); + if (-1 != p) return p; + + + /* call class constructor */ + while(a){ + c = (t_pdp_class *)(a->w.w_pointer); + if (c->type && pdp_type_description_match(type, c->type)){ + //pdp_post("method %x, type %s", c->create, type->s_name); + return (c->create) ? (*c->create)(type) : -1; + } + a = a->next; + } + return -1; +} + +static void +_pdp_pool_expand_nolock(void){ + int i; + + /* double the size */ + int new_pool_size = pdp_pool_size << 1; + t_pdp **new_pool = (t_pdp **)pdp_alloc(new_pool_size * sizeof(t_pdp *)); + bzero(new_pool, new_pool_size * sizeof(t_pdp *)); + memcpy(new_pool, pdp_pool, pdp_pool_size * sizeof(t_pdp *)); + pdp_dealloc(pdp_pool); + pdp_pool = new_pool; + pdp_pool_size = new_pool_size; +} + + + + +/* private _pdp_packet methods */ + +/* packets can only be created and destroyed using these 2 methods */ +/* it updates the mem usage and total packet count */ + +static void +_pdp_packet_dealloc_nolock(t_pdp *p) +{ + /* free memory */ + pdp_dealloc (p); +} + +static t_pdp* +_pdp_packet_alloc_nolock(unsigned int datatype, unsigned int datasize) +{ + unsigned int totalsize = datasize + PDP_HEADER_SIZE; + t_pdp *p = (t_pdp *)pdp_alloc(totalsize); + if (p){ + memset(p, 0, PDP_HEADER_SIZE); //initialize header to 0 + p->type = datatype; + p->size = totalsize; + p->users = 1; + } + return p; +} + + +/* create a new packet and expand pool if necessary */ +static int +_pdp_packet_create_nolock(unsigned int datatype, unsigned int datasize) +{ + int p = 0; + while(1){ + for (; p < pdp_pool_size; p++){ + if (!pdp_pool[p]){ + /* found slot to store packet*/ + t_pdp *header = _pdp_packet_alloc_nolock(datatype, datasize); + if (!header) return -1; // error allocating packet + pdp_pool[p] = header; + return p; + } + } + /* no slot found, expand pool */ + _pdp_pool_expand_nolock(); + } +} + + +void +pdp_packet_destroy(void) +{ + int i = 0; + /* dealloc all the data in object stack */ + pdp_post("DEBUG: pdp_packet_destroy: clearing object pool."); + while ((i < pdp_pool_size) && (pdp_pool[i])) _pdp_packet_dealloc_nolock(pdp_pool[i++]); +} + + + + + + + + +/* public pool operations: have to be thread safe so each entry point + locks the mutex */ + + +/* create a new packet. + this should only be used by type specific factory methods, and only if the + reuse method fails, since it will always create a new packet */ +int +pdp_packet_create(unsigned int datatype, unsigned int datasize /*without header*/) +{ + int packet; + LOCK; + packet = _pdp_packet_create_nolock(datatype, datasize); + UNLOCK; + return packet; +} + + +/* return a new packet. + it tries to reuse a packet based on + 1. matching data size + 2. abscence of destructor (which SHOULD mean there are no enclosed references) + + it obviously can't use the reuse fifo tagged to a symbolic type description + + ALWAYS USE pdp_packet_reuse BEFORE calling pdp_packet_new if possible + use both ONLY IN CONSTRUCTORS !!! + + use pdp_packet_factory to create packets as a "user" + + this is a summary of all internal packet creation mechanisms: + + -> pdp_packet_reuse, which uses symbolic type descriptions, and should work for all packet types + it returns an initialized container (meta = correct, data = garbage) + + -> pdp_packet_new, which only works for non-pure packets, and reuses packets based on data type + it returns a pure packet (meta + data = garbage) + + -> pdp_packet_create, like pdp_packet_new, only it always creates a new packet + + + +*/ + +int +pdp_packet_new(unsigned int datatype, unsigned int datasize) +{ + t_pdp *header; + int packet; + LOCK; + for (packet = 0; packet < pdp_pool_size; packet++){ + header = pdp_pool[packet]; + /* check data size */ + if (header + && header->users == 0 + && header->size == datasize + PDP_HEADER_SIZE + && !(header->theclass && header->theclass->cleanup)){ + + /* ok, got one. initialize */ + memset(header, 0, PDP_HEADER_SIZE); + header->users = 1; + header->type = datatype; + header->size = datasize + PDP_HEADER_SIZE; + + UNLOCK; //EXIT1 + return packet; + } + } + + /* no usable non-pure packet found, create a new one */ + + UNLOCK; //EXIT2 + return pdp_packet_create(datatype, datasize); + + + +} + + +/* internal method to add a packet to a packet type + description symbol's unused packet fifo */ +void +_pdp_packet_save_nolock(int packet) +{ + t_pdp *header = pdp_packet_header(packet); + t_pdp_symbol *s; + PDP_ASSERT(header); + PDP_ASSERT(header->users == 0); + PDP_ASSERT(header->desc); + s = header->desc; + if (!s->s_reusefifo) s->s_reusefifo = pdp_list_new(0); + pdp_list_add(s->s_reusefifo, a_packet, (t_pdp_word)packet); +} + +/* this will revive a packet matching a certain type description + no wildcards are allowed */ +int +pdp_packet_reuse(t_pdp_symbol *type_description) +{ + int packet = -1; + t_pdp *header = 0; + t_pdp_list *l = 0; + LOCK; + if (!type_description || !(l = type_description->s_reusefifo)) goto exit; + while(l->elements){ + packet = pdp_list_pop(l).w_packet; + header = pdp_packet_header(packet); + + /* check if reuse fifo is consistent (packet unused + correct type) + packet could be deleted and replaced with another one, or + revived without the index updated (it's a "hint cache") */ + + if (header->users == 0){ + /* check if type matches */ + if (pdp_type_description_match(header->desc, type_description)){ + header->users++; // revive + goto exit; + } + /* if not, add the packet to the correct reuse fifo */ + else{ + _pdp_packet_save_nolock(packet); + } + } + + /* remove dangling refs */ + header = 0; + packet = -1; + } + + exit: + UNLOCK; + if (header && header->theclass && header->theclass->wakeup){ + header->theclass->wakeup(header); // revive if necessary + } + return packet; +} + +/* find all unused packets in pool, marked as used (to protect from other reapers) + and return them as a list. non-pure packets are not revived */ + + + + + +/* this returns a copy of a packet for read only access. + (increases refcount of the packet -> packet will become readonly if it was + writable, i.e. had rc=1 */ + +int +pdp_packet_copy_ro(int handle) +{ + t_pdp* header; + + if (header = pdp_packet_header(handle)){ + PDP_ASSERT(header->users); // consistency check + LOCK; + header->users++; // increment reference count + UNLOCK; + } + else handle = -1; + return handle; +} + +/* clone a packet: create a new packet with the same + type as the source packet */ + +int +pdp_packet_clone_rw(int handle) +{ + t_pdp* header; + int new_handle = -1; + + + if (header = pdp_packet_header(handle)){ + /* consistency checks */ + PDP_ASSERT(header->users); + PDP_ASSERT(header->desc); + + /* first try to reuse old packet */ + new_handle = pdp_packet_reuse(header->desc); + + /* if this failed, create a new one using the central packet factory method */ + if (-1 == new_handle) new_handle = pdp_factory_newpacket(header->desc); + } + + return new_handle; +} + +/* return a copy of a packet (clone + copy data) */ +int +pdp_packet_copy_rw(int handle) +{ + t_pdp *header, *new_header; + int new_handle = -1; + + if (!(header = pdp_packet_header(handle))) return -1; + + /* check if we are allowed to copy */ + if (header->flags & PDP_FLAG_DONOTCOPY) return -1; + + /* get target packet */ + new_handle = pdp_packet_clone_rw(handle); + if (-1 == new_handle) return -1; + new_header = pdp_packet_header(new_handle); + + /* if there is a copy method, use that one */ + if (header->theclass && header->theclass->copy){ + header->theclass->copy(header, new_header); + } + + /* otherwize copy the data verbatim */ + else { + memcpy(pdp_packet_data(new_handle), + pdp_packet_data(handle), + pdp_packet_data_size(handle)); + } + + return new_handle; + +} + + +/* decrement refcount */ +void pdp_packet_mark_unused(int handle) +{ + t_pdp *header; + if (!(header = pdp_packet_header(handle))) return; + + PDP_ASSERT(header->users); // consistency check + + LOCK; + + /* just decrement refcount */ + if (header->users > 1){ + header->users--; + } + + /* put packet to sleep if refcount 1->0 */ + else { + if (header->theclass && header->theclass->sleep){ + /* call sleep method (if any) outside of lock + while the packet is still alive, so it won't be + acclaimed by another thread */ + UNLOCK; + header->theclass->sleep(header); + LOCK; + } + /* clear refcount & save in fifo for later use */ + header->users = 0; + if (header->desc) // sleep could have destructed packet.. + _pdp_packet_save_nolock(handle); + } + + UNLOCK; +} + + + +/* delete a packet. rc needs to be == 1 */ +void pdp_packet_delete(int handle) +{ + t_pdp *header; + header = pdp_packet_header(handle); + PDP_ASSERT(header); + PDP_ASSERT(header->users == 1); // consistency check + + LOCK; + + if (header->theclass && header->theclass->cleanup){ + /* call cleanup method (if any) outside of lock + while the packet is still alive, so it won't be + acclaimed by another thread */ + UNLOCK; + header->theclass->cleanup(header); + LOCK; + } + + /* delete the packet */ + pdp_pool[handle] = 0; + _pdp_packet_dealloc_nolock(header); + + + UNLOCK; +} + + + + + + + +/* public data access methods */ + +t_pdp* +pdp_packet_header(int handle) +{ + if ((handle >= 0) && (handle < pdp_pool_size)) return pdp_pool[handle]; + else return 0; +} + +void* +pdp_packet_subheader(int handle) +{ + t_pdp* header = pdp_packet_header(handle); + if (!header) return 0; + return (void *)(&header->info.raw); +} + +void* +pdp_packet_data(int handle) +{ + t_pdp *h; + if ((handle >= 0) && (handle < pdp_pool_size)) + { + h = pdp_pool[handle]; + if (!h) return 0; + return (char *)(h) + PDP_HEADER_SIZE; + } + else return 0; +} + +int +pdp_packet_data_size(int handle) +{ + t_pdp *h; + if ((handle >= 0) && (handle < pdp_pool_size)) + { + h = pdp_pool[handle]; + if (!h) return 0; + return h->size - PDP_HEADER_SIZE; + } + else return 0; +} + + + + +int pdp_packet_writable(int packet) /* returns true if packet is writable */ +{ + t_pdp *h = pdp_packet_header(packet); + if (!h) return 0; + return (h->users == 1); +} + +void pdp_packet_replace_with_writable(int *packet) /* replaces a packet with a writable copy */ +{ + int new_p; + if (!pdp_packet_writable(*packet)){ + new_p = pdp_packet_copy_rw(*packet); + pdp_packet_mark_unused(*packet); + *packet = new_p; + } + +} + +/* pool stuff */ + +int +pdp_pool_collect_garbage(void) +{ + pdp_post("ERROR: garbage collector not implemented"); + return 0; +} + +void +pdp_pool_set_max_mem_usage(int max) +{ + pdp_post("ERROR: mem limit not implemented"); +} + + + + + + +#ifdef __cplusplus +} +#endif diff --git a/system/kernel/pdp_post.c b/system/kernel/pdp_post.c new file mode 100644 index 0000000..fb761d0 --- /dev/null +++ b/system/kernel/pdp_post.c @@ -0,0 +1,48 @@ + +/* + * Pure Data Packet system file. pdp logging. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#include "pdp_post.h" + +/* list printing should be moved here too */ + +/* write a message to log (console) */ +void pdp_post_n(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} +void pdp_post(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + putc('\n', stderr); +} + + diff --git a/system/kernel/pdp_symbol.c b/system/kernel/pdp_symbol.c new file mode 100644 index 0000000..32e9e33 --- /dev/null +++ b/system/kernel/pdp_symbol.c @@ -0,0 +1,196 @@ +/* + * Pure Data Packet system implementation. : code implementing pdp's namespace (symbols) + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +#include <string.h> +#include <pthread.h> +#include "pdp_symbol.h" +#include "pdp_list.h" +#include "pdp_debug.h" + +// some extra prototypes +void *pdp_alloc(int size); +void pdp_dealloc(void *data); + +// the symbol hash mutex +static pthread_mutex_t pdp_hash_mutex; + +#define HASHSIZE 1024 +static t_pdp_symbol *pdp_symhash[HASHSIZE]; + + +#define LOCK pthread_mutex_lock(&pdp_hash_mutex) +#define UNLOCK pthread_mutex_unlock(&pdp_hash_mutex) + + +static void _pdp_symbol_init(t_pdp_symbol *s) +{ + memset(s, 0, sizeof(*s)); + s->s_forth.t = a_undef; +} + + +/* shamelessly copied from pd src and made thread safe */ +t_pdp_symbol *_pdp_dogensym(char *s, t_pdp_symbol *oldsym) +{ + t_pdp_symbol **sym1, *sym2; + unsigned int hash1 = 0, hash2 = 0; + int length = 0; + char *s2 = s; + while (*s2) + { + hash1 += *s2; + hash2 += hash1; + length++; + s2++; + } + sym1 = pdp_symhash + (hash2 & (HASHSIZE-1)); + + /* lock hash */ + LOCK; + + while (sym2 = *sym1) + { + if (!strcmp(sym2->s_name, s)) goto gotit; + sym1 = &sym2->s_next; + } + if (oldsym){ + sym2 = oldsym; + } + else + { + sym2 = (t_pdp_symbol *)pdp_alloc(sizeof(*sym2)); + _pdp_symbol_init(sym2); + sym2->s_name = pdp_alloc(length+1); + sym2->s_next = 0; + strcpy(sym2->s_name, s); + } + *sym1 = sym2; + + gotit: + + /* unlock hash */ + UNLOCK; + return (sym2); +} + +t_pdp_symbol *pdp_gensym(char *s) +{ + return(_pdp_dogensym(s, 0)); +} + + +/* connect a parsed typelist to a symbol type name + 1 = succes, 0 = error (symbol already connected) */ +int pdp_symbol_set_typelist(t_pdp_symbol *s, t_pdp_list *typelist) +{ + int status = 0; + LOCK; + if (!s->s_type){ + s->s_type = typelist; + status = 1; + } + UNLOCK; + return status; +} + + +void pdp_symbol_apply_all(t_pdp_symbol_iterator it) +{ + int i; + for (i=0; i<HASHSIZE; i++){ + t_pdp_symbol *s; + for (s = pdp_symhash[i]; s; s=s->s_next){ + it(s); + } + + } +} + +t_pdp_symbol _pdp_sym_wildcard; +t_pdp_symbol _pdp_sym_float; +t_pdp_symbol _pdp_sym_int; +t_pdp_symbol _pdp_sym_symbol; +t_pdp_symbol _pdp_sym_packet; +t_pdp_symbol _pdp_sym_pointer; +t_pdp_symbol _pdp_sym_invalid; +t_pdp_symbol _pdp_sym_list; +t_pdp_symbol _pdp_sym_question_mark; +t_pdp_symbol _pdp_sym_atom; +t_pdp_symbol _pdp_sym_null; +t_pdp_symbol _pdp_sym_quote_start; +t_pdp_symbol _pdp_sym_quote_end; +t_pdp_symbol _pdp_sym_return; +t_pdp_symbol _pdp_sym_nreturn; +t_pdp_symbol _pdp_sym_defstart; +t_pdp_symbol _pdp_sym_defend; +t_pdp_symbol _pdp_sym_if; +t_pdp_symbol _pdp_sym_then; +t_pdp_symbol _pdp_sym_local; +t_pdp_symbol _pdp_sym_forth; +t_pdp_symbol _pdp_sym_call; +t_pdp_symbol _pdp_sym_push; +t_pdp_symbol _pdp_sym_pop; + +static void _sym(char *name, t_pdp_symbol *s) +{ + t_pdp_symbol *realsym; + _pdp_symbol_init(s); + s->s_name = name; + realsym = _pdp_dogensym(name, s); + PDP_ASSERT(realsym == s); // if this fails, the symbol was already defined +} + +void pdp_symbol_setup(void) +{ + // create mutexes + pthread_mutex_init(&pdp_hash_mutex, NULL); + + // init symbol hash + memset(pdp_symhash, 0, HASHSIZE * sizeof(t_pdp_symbol *)); + + // setup predefined symbols (those that have direct pointer access for speedup) + _sym("*", &_pdp_sym_wildcard); + _sym("float", &_pdp_sym_float); + _sym("int", &_pdp_sym_int); + _sym("symbol", &_pdp_sym_symbol); + _sym("packet", &_pdp_sym_packet); + _sym("pointer", &_pdp_sym_pointer); + _sym("invalid", &_pdp_sym_invalid); + _sym("list", &_pdp_sym_list); + _sym("?", &_pdp_sym_question_mark); + _sym("atom", &_pdp_sym_atom); + _sym("null", &_pdp_sym_null); + _sym("[", &_pdp_sym_quote_start); + _sym("]", &_pdp_sym_quote_end); + _sym("ret", &_pdp_sym_return); + _sym("nret", &_pdp_sym_nreturn); + _sym(":", &_pdp_sym_defstart); + _sym(";", &_pdp_sym_defend); + _sym("if", &_pdp_sym_if); + _sym("then", &_pdp_sym_then); + _sym("local", &_pdp_sym_local); + _sym("forth", &_pdp_sym_forth); + _sym("call", &_pdp_sym_call); + _sym("push", &_pdp_sym_push); + _sym("pop", &_pdp_sym_pop); + +} + + diff --git a/system/kernel/pdp_type.c b/system/kernel/pdp_type.c new file mode 100644 index 0000000..0216d07 --- /dev/null +++ b/system/kernel/pdp_type.c @@ -0,0 +1,473 @@ +/* + * Pure Data Packet system implementation. : code for handling different packet types + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 file contains type handling routines */ + +#include <stdarg.h> +#include <string.h> +#include <pthread.h> +#include "pdp_list.h" +#include "pdp_symbol.h" +#include "pdp_packet.h" +#include "pdp_post.h" +#include "pdp_type.h" +#include "pdp_mem.h" +#include "pdp_debug.h" + + +// debug +#define D if (0) + + +static t_pdp_list *conversion_list; + +#define INIT_MAX_CACHE_SIZE 32 + +static t_pdp_list *cached_conversion_list; +static int max_cache_size; + +/* mutex */ +static pthread_mutex_t pdp_conversion_mutex; +static pthread_mutex_t pdp_cache_mutex; + + + +/* convert a type to a list */ +t_pdp_list *pdp_type_to_list(t_pdp_symbol *type) +{ +#define TMPSIZE 1024 + + char *c = type->s_name; + char *lastname = c; + int n = 0; + char tmp[strlen(type->s_name)+1]; + t_pdp_list *l = pdp_list_new(0); + + while(*c){ + if (*c == '/'){ + strncpy(tmp, lastname, n); + tmp[n] = 0; + pdp_list_add_back(l, a_symbol, (t_pdp_word)pdp_gensym(tmp)); + c++; + lastname = c; + n = 0; + } + else{ + c++; + n++; + PDP_ASSERT(n < TMPSIZE); + } + } + pdp_list_add_back(l, a_symbol, (t_pdp_word)pdp_gensym(lastname)); + + return l; +} + + +/* get the description symbol. */ +t_pdp_symbol *pdp_packet_get_description(int packet) +{ + t_pdp *header = pdp_packet_header(packet); + + if (!header) return pdp_gensym("invalid"); + else if (!header->desc){ + + /* since every packet is obliged to have a description, this is an error */ + pdp_post("ERROR: pdp_packet_get_description: packet %d has no description.", packet); + pdp_packet_print_debug(packet); + return pdp_gensym("unknown"); + } + else return header->desc; +} + + + +/* this runs a conversion program */ +int _pdp_type_run_conversion_program(t_pdp_conversion_program *program, + int packet, t_pdp_symbol *dest_template) +{ + /* run a conversion program: + treat the source packet as readonly, and cleanup intermediates, such + that the net result is the production of a new packet, with the + source packet intact. */ + + int p, tmp; + t_pdp_atom *a; + t_pdp_conversion_method m; + + // run the first line of the program + a = program->first; + m = a->w.w_pointer; + D pdp_post("DEBUG: _pdp_type_run_conversion_program: method = %x", m); + p = m(packet, dest_template); + D pdp_post("DEBUG: _pdp_type_run_conversion_program:"); + D pdp_post(" packet returned = %d, type = %s", + p, pdp_packet_get_description(p)->s_name); + + // run the remaining lines + cleanup intermediates + for (a=a->next; a; a=a->next){ + m = a->w.w_pointer; + D pdp_post("DEBUG: _pdp_type_run_conversion_program: next method ptr = %x", m); + tmp = m(p, dest_template); + pdp_packet_mark_unused(p); + p = tmp; + } + return p; +} + + +/* find a conversion program */ +t_pdp_conversion_program * +_pdp_type_find_conversion_program(t_pdp_symbol *src_pattern, t_pdp_symbol *dst_pattern) +{ + t_pdp_conversion *c; + t_pdp_atom *a; + t_pdp_conversion_program *retval = 0; + + /* lock conversion list */ + pthread_mutex_lock(&pdp_conversion_mutex); + + for (a = conversion_list->first; a; a=a->next){ + c = a->w.w_pointer; + /* can be a wildcard match */ + if (pdp_type_description_match(src_pattern, c->src_pattern) && + pdp_type_description_match(dst_pattern, c->dst_pattern)) { + /* found a program */ + D pdp_post("DEBUG: _pdp_type_find_conversion_program: found: %s -> %s", + c->src_pattern->s_name, c->dst_pattern->s_name); + retval = c->program; + goto gotit; + } + } + + /* no conversion program was found */ + retval = 0; + gotit: + + /* lock conversion list */ + pthread_mutex_unlock(&pdp_conversion_mutex); + return retval; +} + +/* find a cached conversion program + if one is found it will be moved to the back of the queue (MRU) */ +t_pdp_conversion_program * +_pdp_type_find_cached_conversion_program(t_pdp_symbol *src_pattern, t_pdp_symbol *dst_pattern) +{ + t_pdp_conversion *c, *c_tmp; + t_pdp_atom *a; + t_pdp_conversion_program *retval = 0; + + /* lock cached list */ + pthread_mutex_lock(&pdp_cache_mutex); + + for (a = cached_conversion_list->first; a; a=a->next){ + c = a->w.w_pointer; + /* must be exact match */ + if ((src_pattern == c->src_pattern) && + (dst_pattern == c->dst_pattern)) { + + /* found a program */ + D pdp_post("DEBUG: _pdp_type_find_cached_conversion_program: found: %s -> %s", + c->src_pattern->s_name, c->dst_pattern->s_name); + retval = c->program; + + /* make MRU (move to back) */ + c_tmp = cached_conversion_list->last->w.w_pointer; + cached_conversion_list->last->w.w_pointer = c; + a->w.w_pointer = c_tmp; + goto gotit; + } + } + + retval = 0; + + gotit: + + + /* un lock cached list */ + pthread_mutex_unlock(&pdp_cache_mutex); + + /* no conversion program was found */ + return retval; +} + + +/* conversion program manipulations */ +void pdp_conversion_program_free(t_pdp_conversion_program *program) +{ + pdp_list_free(program); +} + +/* debug print */ +void _pdp_conversion_program_print(t_pdp_conversion_program *program) +{ + D pdp_post("_pdp_conversion_program_print %x", program); + pdp_list_print(program); +} + +t_pdp_conversion_program *pdp_conversion_program_new(t_pdp_conversion_method method, ...) +{ + t_pdp_conversion_program *p = pdp_list_new(0); + t_pdp_conversion_method m = method; + va_list ap; + + D pdp_post("DEBUG: pdp_conversion_program_new:BEGIN"); + + pdp_list_add_back_pointer(p, m); + va_start(ap, method); + while (m = va_arg(ap, t_pdp_conversion_method)) pdp_list_add_back_pointer(p, m); + va_end(ap); + + D pdp_post("DEBUG: pdp_conversion_program_new:END"); + + return p; +} + +t_pdp_conversion_program *pdp_conversion_program_copy(t_pdp_conversion_program *program) +{ + if (program) return pdp_list_copy(program); + else return 0; +} + +void pdp_conversion_program_add(t_pdp_conversion_program *program, + t_pdp_conversion_program *tail) +{ + return pdp_list_cat(program, tail); +} + +/* conversion registration */ +void pdp_type_register_conversion (t_pdp_symbol *src_pattern, t_pdp_symbol *dst_pattern, + t_pdp_conversion_program *program) +{ + t_pdp_conversion *c = (t_pdp_conversion *)pdp_alloc(sizeof(*c)); + c->src_pattern = src_pattern; + c->dst_pattern = dst_pattern; + c->program = program; + + /* lock conversion list */ + pthread_mutex_lock(&pdp_conversion_mutex); + + pdp_list_add_back_pointer(conversion_list, c); + + /* unlock conversion list */ + pthread_mutex_unlock(&pdp_conversion_mutex); + +} + +/* register a cached conversion */ +void pdp_type_register_cached_conversion (t_pdp_symbol *src_pattern, t_pdp_symbol *dst_pattern, t_pdp_conversion_program *program) +{ + + /* create the new conversion */ + t_pdp_conversion *c = (t_pdp_conversion *)pdp_alloc(sizeof(*c)); + c->src_pattern = src_pattern; + c->dst_pattern = dst_pattern; + c->program = program; + + /* lock cached conversion list */ + pthread_mutex_lock(&pdp_cache_mutex); + + /* check size, and remove LRU (top) if the cache is full */ + while (cached_conversion_list->elements >= max_cache_size){ + t_pdp_conversion *c_old = pdp_list_pop(cached_conversion_list).w_pointer; + if (c_old->program) pdp_conversion_program_free(c_old->program); + pdp_dealloc(c_old); + } + + /* add and make MRU (back) */ + pdp_list_add_back_pointer(cached_conversion_list, c); + + /* unlock cached conversion list */ + pthread_mutex_unlock(&pdp_cache_mutex); +} + +/* convert a given packet to a certain type (template) */ +int _pdp_packet_convert(int packet, t_pdp_symbol *dest_template) +{ + t_pdp_symbol *type = pdp_packet_get_description(packet); + t_pdp_symbol *tmp_type = 0; + int tmp_packet = -1; + + t_pdp_conversion_program *program = 0; + t_pdp_conversion_program *program_last = 0; + t_pdp_conversion_program *program_tail = 0; + + /* check if there is a program in the cached list, if so run it */ + if (program = _pdp_type_find_cached_conversion_program(type, dest_template)) + return _pdp_type_run_conversion_program(program, packet, dest_template); + + /* if it is not cached, iteratively convert + and save program on top of cache list if a conversion path (program) was found */ + + // run first conversion that matches + program = pdp_conversion_program_copy + (_pdp_type_find_conversion_program(type, dest_template)); + program_last = program; + if (!program){ + D pdp_post("DEBUG: pdp_type_convert: (1) can't convert %s to %s", + type->s_name, dest_template->s_name); + return -1; + } + tmp_packet = _pdp_type_run_conversion_program(program, packet, dest_template); + tmp_type = pdp_packet_get_description(tmp_packet); + + // run more conversions if necessary, deleting intermediate packets + while (!pdp_type_description_match(tmp_type, dest_template)){ + int new_packet; + program_tail = _pdp_type_find_conversion_program(tmp_type, dest_template); + if (!program_tail){ + D pdp_post("DEBUG: pdp_type_convert: (2) can't convert %s to %s", + tmp_type->s_name, dest_template->s_name); + pdp_packet_mark_unused(tmp_packet); + pdp_conversion_program_free(program); + return -1; + } + if (program_last == program_tail){ + pdp_post("ERROR: pdp_packet_convert: conversion loop detected"); + } + program_last = program_tail; + + pdp_conversion_program_add(program, program_tail); + new_packet = _pdp_type_run_conversion_program(program_tail, tmp_packet, dest_template); + pdp_packet_mark_unused(tmp_packet); + tmp_packet = new_packet; + tmp_type = pdp_packet_get_description(tmp_packet); + } + + // save the conversion program in the cache + pdp_type_register_cached_conversion(type, dest_template, program); + + // return resulting packet + return tmp_packet; + +} + +/* convert or copy ro */ +int pdp_packet_convert_ro(int packet, t_pdp_symbol *dest_template) +{ + t_pdp_symbol *type = pdp_packet_get_description(packet); + + /* if it is compatible, return a ro copy */ + if (pdp_type_description_match(type, dest_template)) return pdp_packet_copy_ro(packet); + + /* if not, convert to a new type */ + else return _pdp_packet_convert(packet, dest_template); +} + +/* convert or copy rw */ +int pdp_packet_convert_rw(int packet, t_pdp_symbol *dest_template) +{ + t_pdp_symbol *type = pdp_packet_get_description(packet); + + /* if it is compatible, just return a rw copy */ + if (pdp_type_description_match(type, dest_template)) return pdp_packet_copy_rw(packet); + + /* if not, convert to a new type */ + else return _pdp_packet_convert(packet, dest_template); +} + + +/* this is a hack. type cache data: (a type description parsed into + a pdp_list for fast comparison) should be setup when + a packet symbol is created, but since that can be everywhere, + we set it up on first use. type cache is permanent. */ + + +static void _setup_type_cache(t_pdp_symbol *s) +{ + t_pdp_list *l = pdp_type_to_list(s); + if (!pdp_symbol_set_typelist(s, l)) + pdp_list_free(l); // list was already present -> free cached list + +} + +/* check if a type description fits a template + this function is symmetric */ +int pdp_type_description_match(t_pdp_symbol *description, t_pdp_symbol *pattern) +{ + int match = 0; // no match until all tests are passed + + t_pdp_atom *ad, *ap; + t_pdp_symbol *wildcard = PDP_SYM_WILDCARD; + + PDP_ASSERT(pattern); + PDP_ASSERT(description); + + /* same type symbol -> match */ + if (description == pattern) {match = 1; goto done;} + + /* check the description list */ + if (!(description->s_type)) _setup_type_cache(description); + if (!(pattern->s_type)) _setup_type_cache(pattern); + + /* compare symbols of description list */ + for(ad=description->s_type->first, ap=pattern->s_type->first; + ad && ap; + ad=ad->next, ap=ap->next) + { + + if (ad->w.w_symbol == wildcard) continue; + if (ap->w.w_symbol == wildcard) continue; + if (ad->w.w_symbol != ap->w.w_symbol) {goto done;} /* difference and not a wildcard */ + } + + /* ok if sizes are equal */ + if (! (ad || ap)) {match = 1; goto done;} + + /* one of the two is shorter, so the shortest list needs + to end with a wildcard to have a match */ + + if (ap && description->s_type->last->w.w_symbol != wildcard) goto done; + if (ad && pattern->s_type->last->w.w_symbol != wildcard) goto done; + + /* all tests passed: type templates match */ + match = 1; + + done: + D pdp_post("DEBUG: testing match between %s and %s: %s", + description->s_name, pattern->s_name, match ? "match" : "no match"); + return match; + +} + + + + + +/* setup method */ +void pdp_type_setup(void) +{ + int i; + + // create mutexes + pthread_mutex_init(&pdp_conversion_mutex, NULL); + pthread_mutex_init(&pdp_cache_mutex, NULL); + + // create conversion lists + cached_conversion_list = pdp_list_new(0); + conversion_list = pdp_list_new(0); + max_cache_size = INIT_MAX_CACHE_SIZE; + + + + +} diff --git a/system/mmx/Makefile b/system/mmx/Makefile new file mode 100644 index 0000000..9b1f690 --- /dev/null +++ b/system/mmx/Makefile @@ -0,0 +1,31 @@ +include ../../Makefile.config + +OBJ = \ +pixel_pack_s16u8.o \ +pixel_unpack_u8s16.o \ +pixel_add_s16.o \ +pixel_mul_s16.o \ +pixel_mix_s16.o \ +pixel_randmix_s16.o \ +pixel_conv_hor_s16.o \ +pixel_conv_ver_s16.o \ +pixel_biquad_s16.o \ +pixel_ca_s1.o \ +pixel_rand_s16.o \ +pixel_crot_s16.o \ +pixel_gain_s16.o \ +pixel_resample_s16.o \ +pixel_cheby_s16.o + +all: $(OBJ) + +test: pdp_mmx_test.o $(OBJ) + gcc -o pdp_mmx_test pdp_mmx_test.o $(OBJ) -g + +clean: + rm -f *.o + rm -f *~ + rm -f pdp_mmx.a + rm -f pdp_mmx_test + + diff --git a/system/mmx/pdp_mmx_test.c b/system/mmx/pdp_mmx_test.c new file mode 100644 index 0000000..e93539f --- /dev/null +++ b/system/mmx/pdp_mmx_test.c @@ -0,0 +1,62 @@ +#include "pdp_mmx.h" + +#define FP(x) ((short int)(((float)(x) * 2 * 256.0f))) + +#define nbp 256 + + short int a1[4] = {0x0100,0x0100,0x0100,0x0100}; + short int a2[4] = {0x0100,0x0100,0x0100,0x0100}; + short int b0[4] = {0x0100,0x0100,0x0100,0x0100}; + short int b1[4] = {0x0100,0x0100,0x0100,0x0100}; + short int b2[4] = {0x0100,0x0100,0x0100,0x0100}; + + short int u1[4] = {0x0100,0x0100,0x0100,0x0100}; + short int u2[4] = {0x0100,0x0100,0x0100,0x0100}; + + short int x0[4] = {0x0100,0x0100,0x0100,0x0100}; + short int x1[4] = {0x0100,0x0100,0x0100,0x0100}; + short int x2[4] = {0x0100,0x0100,0x0100,0x0100}; + short int x3[4] = {0x0100,0x0100,0x0100,0x0100}; + +void print_pixel(unsigned int i) +{ + if (i) printf("x "); + else printf(". "); +} + +void print_line(void) +{ + printf("\n"); +} + +void print_square(unsigned char *c) +{ + int i,j; + + for(j=7; j>=0; j--){ + for(i=0; i<8; i++) print_pixel(c[j] & (1<<(7-i))); + printf("\n"); + } + +} + +main() +{ + + unsigned char src[16]={1,2,3,4,5,6,7,8,-1,-2,-3,-4,-5,-6,-7,-8}; + unsigned char dst[8]; + + + print_square(src); + print_line(); + print_square(src+8); + print_line(); + + pixel_test_s1(dst,src,1,1); + + print_square(dst); + print_line(); + + + +} diff --git a/system/mmx/pixel_add_s16.s b/system/mmx/pixel_add_s16.s new file mode 100644 index 0000000..8d4c7df --- /dev/null +++ b/system/mmx/pixel_add_s16.s @@ -0,0 +1,55 @@ +# Pure Data Packet mmx routine. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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. +# +.globl pixel_add_s16 +.type pixel_add_s16,@function + +# simple add +# void pixel_add_s16(int *left, int *right, int nb_4pixel_vectors) + +pixel_add_s16: + pushl %ebp + movl %esp, %ebp + push %esi + push %edi + + movl 8(%ebp), %edi # left array + movl 12(%ebp), %esi # right array + movl 16(%ebp), %ecx # pixel count + + + .align 16 + .loop_mix: + +# prefetch 128(%esi) + movq (%esi), %mm1 # load right 4 pixels from memory + movq (%edi), %mm0 # load 4 left pixels from memory + paddsw %mm1, %mm0 # mix + movq %mm0, (%edi) + addl $8, %esi + addl $8, %edi + decl %ecx + jnz .loop_mix # loop + + emms + + + pop %edi + pop %esi + leave + ret + diff --git a/system/mmx/pixel_biquad_dirI_s16.s b/system/mmx/pixel_biquad_dirI_s16.s new file mode 100644 index 0000000..1729502 --- /dev/null +++ b/system/mmx/pixel_biquad_dirI_s16.s @@ -0,0 +1,361 @@ +# Pure Data Packet mmx routine. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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. +# + + + # TODO MOVE TO DIRECT FORM II + # y[k] = b0 * x[k] + u1[k-1] + # u1[k] = b1 * x[k] + u2[k-1] - a1 * y[k] + # u2[k] = b2 * x[k] - a2 * y[k] + + # input in register: + # %mm0-mm3: input 4x4 pixels {x0 x1 x2 x3} + # %esi: coef memory (a1, a2, b0, b1, b2) + # %edi: state memory (u1, u2) + + + # return in register: + # %mm0-mm4: 4x4 pixels result + + + .biquad_4x4_pixels: + .align 16 + # prescale + movq -8(%esi), %mm4 + pmulhw %mm4, %mm0 + pmulhw %mm4, %mm1 + pmulhw %mm4, %mm2 + pmulhw %mm4, %mm3 + psllw $1, %mm0 + psllw $1, %mm1 + psllw $1, %mm2 + psllw $1, %mm3 + + + # first vector + movq 0(%edi), %mm4 # mm4 <- u[-1] + movq 8(%edi), %mm5 # mm5 <- u[-2] + movq %mm4, %mm6 + movq %mm5, %mm7 + + pmulhw 0(%esi), %mm6 # multiply by a1 + pmulhw 8(%esi), %mm7 # multiply by a2 + + paddsw %mm6, %mm0 # accumulate + paddsw %mm7, %mm0 # accumulate + paddsw %mm0, %mm0 # scale by 2 (since all fixed point muls are x*y/2) + + movq %mm0, %mm6 # mm6 <- u[0] + movq %mm4, %mm7 # mm7 <- u[-1] + pmulhw 16(%esi), %mm0 # multiply by b0 + pmulhw 24(%esi), %mm4 # multiply by b1 + pmulhw 32(%esi), %mm5 # multiply by b2 + + paddsw %mm4, %mm0 # accumulate + paddsw %mm5, %mm0 # accumulate + + # mm0 is result 0 + + # second vector + movq %mm6, %mm4 # mm4 <- u[0] + movq %mm7, %mm5 # mm5 <- u[-1] + + pmulhw 0(%esi), %mm6 # multiply by a1 + pmulhw 8(%esi), %mm7 # multiply by a2 + + paddsw %mm6, %mm1 # accumulate + paddsw %mm7, %mm1 # accumulate + paddsw %mm1, %mm1 # scale by 2 + + + movq %mm1, %mm6 # mm6 <- u[1] + movq %mm4, %mm7 # mm7 <- u[0] + pmulhw 16(%esi), %mm1 # multiply by b0 + pmulhw 24(%esi), %mm4 # multiply by b1 + pmulhw 32(%esi), %mm5 # multiply by b2 + + paddsw %mm4, %mm1 # accumulate + paddsw %mm5, %mm1 # accumulate + + # mm1 is result 1 + + # third vector + movq %mm6, %mm4 # mm4 <- u[1] + movq %mm7, %mm5 # mm5 <- u[0] + + pmulhw 0(%esi), %mm6 # multiply by a1 + pmulhw 8(%esi), %mm7 # multiply by a2 + + paddsw %mm6, %mm2 # accumulate + paddsw %mm7, %mm2 # accumulate + paddsw %mm2, %mm2 # scale by 2 + + + movq %mm2, %mm6 # mm6 <- u[2] + movq %mm4, %mm7 # mm7 <- u[1] + pmulhw 16(%esi), %mm2 # multiply by b0 + pmulhw 24(%esi), %mm4 # multiply by b1 + pmulhw 32(%esi), %mm5 # multiply by b2 + + paddsw %mm4, %mm2 # accumulate + paddsw %mm5, %mm2 # accumulate + + # mm2 is result 2 + + # fourth vector + movq %mm6, %mm4 # mm4 <- u[2] + movq %mm7, %mm5 # mm5 <- u[1] + + pmulhw 0(%esi), %mm6 # multiply by a1 + pmulhw 8(%esi), %mm7 # multiply by a2 + + paddsw %mm6, %mm3 # accumulate + paddsw %mm7, %mm3 # accumulate + paddsw %mm3, %mm3 # scale by 2 + + + movq %mm3, 0(%edi) # store u[3] + movq %mm4, 8(%edi) # store u[2] + pmulhw 16(%esi), %mm3 # multiply by b0 + pmulhw 24(%esi), %mm4 # multiply by b1 + pmulhw 32(%esi), %mm5 # multiply by b2 + + paddsw %mm4, %mm3 # accumulate + paddsw %mm5, %mm3 # accumulate + + # mm3 is result 3 + + ret + + + # in order to use the 4 line parallel biquad routine on horizontal + # lines, we need to reorder (rotate or transpose) the matrix, since + # images are scanline encoded, and we want to work in parallell + # on 4 lines. + # + # since the 4 lines are independent, it doesnt matter in which order + # the the vector elements are present. + # + # this allows us to use the same routine for left->right and right->left + # processing. + # + # some comments on the non-abelean group of square isometries consisting of + # (I) identity + # (H) horizontal axis mirror + # (V) vertical axis mirror + # (T) transpose (diagonal axis mirror) + # (A) antitranspose (antidiagonal axis mirror) + # (R1) 90deg anticlockwize rotation + # (R2) 180deg rotation + # (R3) 90deg clockwize rotation + # + # + # we basicly have two options: (R1,R3) or (T,A) + # we opt for T and A because they are self inverting, which improves locality + # + # use antitranspose for right to left an transpose + # for left to right (little endian) + + + # antitranspose 4x4 + + # input + # %mm3 == {d0 d1 d2 d3} + # %mm2 == {c0 c1 c2 c3} + # %mm1 == {b0 b1 b2 b3} + # %mm0 == {a0 a1 a2 a3} + + # output + # %mm3 == {a3 b3 c3 d3} + # %mm2 == {a2 b2 c2 d2} + # %mm1 == {a1 b1 c1 d1} + # %mm0 == {a0 b0 c0 d0} + + + .antitranspose_4x4: + .align 16 + movq %mm3, %mm4 + punpcklwd %mm1, %mm4 # mm4 <- {b2 d2 b3 d3} + movq %mm3, %mm5 + punpckhwd %mm1, %mm5 # mm5 <- {b0 d0 b1 d1} + + movq %mm2, %mm6 + punpcklwd %mm0, %mm6 # mm6 <- {a2 c2 a3 c3} + movq %mm2, %mm7 + punpckhwd %mm0, %mm7 # mm7 <- {a0 c0 a1 c1} + + movq %mm4, %mm3 + punpcklwd %mm6, %mm3 # mm3 <- {a3 b3 c3 d3} + movq %mm4, %mm2 + punpckhwd %mm6, %mm2 # mm2 <- {a2 b2 c2 d2} + + movq %mm5, %mm1 + punpcklwd %mm7, %mm1 # mm1 <- {a1 b1 c1 d1} + movq %mm5, %mm0 + punpckhwd %mm7, %mm0 # mm0 <- {a0 b0 c0 d0} + + ret + + + + # transpose 4x4 + + # input + # %mm3 == {d3 d2 d1 d0} + # %mm2 == {c3 c2 c1 c0} + # %mm1 == {b3 b2 b1 b0} + # %mm0 == {a3 a2 a1 a0} + + # output + # %mm3 == {d3 c3 b3 a3} + # %mm2 == {d2 c2 b2 a2} + # %mm1 == {d1 c1 b1 a1} + # %mm0 == {d0 c0 b0 a0} + + + .transpose_4x4: + .align 16 + movq %mm0, %mm4 + punpcklwd %mm2, %mm4 # mm4 <- {c1 a1 c0 a0} + movq %mm0, %mm5 + punpckhwd %mm2, %mm5 # mm5 <- {c3 a3 c2 a2} + + movq %mm1, %mm6 + punpcklwd %mm3, %mm6 # mm6 <- {d1 b1 d0 b0} + movq %mm1, %mm7 + punpckhwd %mm3, %mm7 # mm7 <- {d3 b3 d2 b2} + + movq %mm4, %mm0 + punpcklwd %mm6, %mm0 # mm0 <- {d0 c0 b0 a0} + movq %mm4, %mm1 + punpckhwd %mm6, %mm1 # mm1 <- {d1 c1 b1 a1} + + movq %mm5, %mm2 + punpcklwd %mm7, %mm2 # mm2 <- {d2 c2 b2 a2} + movq %mm5, %mm3 + punpckhwd %mm7, %mm3 # mm3 <- {d3 c3 b3 a3} + + ret + + +.globl pixel_biquad_vertb_s16 +.type pixel_biquad_vertb_s16,@function + + +# pixel_biquad_vertbr_s16(char *pixel_array, int nb_rows, int linewidth, short int coef[20], short int state[8]) + + +pixel_biquad_vertb_s16: + + + pushl %ebp + movl %esp, %ebp + push %ebx + push %esi + push %edi + + movl 8(%ebp), %ebx # pixel array offset + movl 12(%ebp), %ecx # nb of 4x4 pixblocks + movl 16(%ebp), %edx # line with + + movl 20(%ebp), %esi # coefs + movl 24(%ebp), %edi # state + + shll $1, %edx # short int addressing + movl %edx, %eax + shll $1, %eax + addl %edx, %eax # eax = 3 * edx + + .align 16 + .biquad_vertb_line_loop: + movq (%ebx), %mm0 + movq (%ebx,%edx,1), %mm1 + movq (%ebx,%edx,2), %mm2 + movq (%ebx,%eax,1), %mm3 + call .biquad_4x4_pixels + movq %mm0, (%ebx) + movq %mm1, (%ebx,%edx,1) + movq %mm2, (%ebx,%edx,2) + movq %mm3, (%ebx,%eax,1) + addl %edx, %ebx + addl %eax, %ebx + decl %ecx + jnz .biquad_vertb_line_loop + + emms + + pop %edi + pop %esi + pop %ebx + leave + ret + +.globl pixel_biquad_horlr_s16 +.type pixel_biquad_horlr_s16,@function + + +# pixel_biquad_hor_s16(char *pixel_array, int nb_rows, int linewidth, short int coef[20], short int state[8]) + + +pixel_biquad_horlr_s16: + + + pushl %ebp + movl %esp, %ebp + push %ebx + push %esi + push %edi + + movl 8(%ebp), %ebx # pixel array offset + movl 12(%ebp), %ecx # nb of 4x4 pixblocks + movl 16(%ebp), %edx # line with + + movl 20(%ebp), %esi # coefs + movl 24(%ebp), %edi # state + + shll $1, %edx # short int addressing + movl %edx, %eax + shll $1, %eax + addl %edx, %eax # eax = 3 * edx + + .align 16 + .biquad_horlr_line_loop: + movq (%ebx), %mm0 + movq (%ebx,%edx,1), %mm1 + movq (%ebx,%edx,2), %mm2 + movq (%ebx,%eax,1), %mm3 + call .transpose_4x4 + call .biquad_4x4_pixels + call .transpose_4x4 + movq %mm0, (%ebx) + movq %mm1, (%ebx,%edx,1) + movq %mm2, (%ebx,%edx,2) + movq %mm3, (%ebx,%eax,1) + addl $8, %ebx + decl %ecx + jnz .biquad_horlr_line_loop + + emms + + pop %edi + pop %esi + pop %ebx + leave + ret + + + diff --git a/system/mmx/pixel_biquad_s16.s b/system/mmx/pixel_biquad_s16.s new file mode 100644 index 0000000..844b041 --- /dev/null +++ b/system/mmx/pixel_biquad_s16.s @@ -0,0 +1,451 @@ +# Pure Data Packet mmx routine. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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. +# + + + # DIRECT FORM II BIQUAD + # + # y[k] = b0 * x[k] + u1[k-1] + # u1[k] = b1 * x[k] + u2[k-1] - a1 * y[k] + # u2[k] = b2 * x[k] - a2 * y[k] + # MACRO: df2 <reg> + # + # computes a direct form 2 biquad + # does not use {mm0-mm3}\<inreg> + # + # input: <reg> == input + # %mm4 == state 1 + # %mm5 == state 2 + # (%esi) == biquad coefs (-a1 -a2 b0 b1 b2) in s1.14 + # output: <reg> == output + # %mm4 == state 1 + # %mm5 == state 2 + + .macro df2 reg + movq \reg, %mm6 # mm6 == x[k] + movq \reg, %mm7 # mm7 == x[k] + pmulhw 16(%esi), %mm6 # mm6 == x[k] * b0 + pmulhw 24(%esi), %mm7 # mm7 == x[k] * b1 + paddw %mm4, %mm6 # mm6 == x[k] * b0 + u1[k-1] == y[k] + paddw %mm5, %mm7 # mm7 == x[k] * b1 + u2[k-1] + paddsw %mm6, %mm6 # compensate for mul = x*y/4 (coefs are s1.14 fixed point) + paddsw %mm6, %mm6 # paddsw ensures saturation + movq \reg, %mm5 # mm5 == x[k] + movq %mm6, %mm4 # mm4 == y[k] + movq %mm6, \reg # reg == y[k] -------------------- + pmulhw 0(%esi), %mm4 # mm4 == y[k] * (-a1) + pmulhw 8(%esi), %mm6 # mm6 == y[k] * (-a2) + pmulhw 32(%esi), %mm5 # mm5 == x[k] * b2 + paddw %mm7, %mm4 # mm4 == u1[k] -------------------- + paddw %mm6, %mm5 # mm5 == u2[k] -------------------- + .endm + + + # input in register: + # %mm0-mm3: input 4x4 pixels {x0 x1 x2 x3} + # %esi: coef memory (-a1, -a2, b0, b1, b2) in s1.14 + # %edi: state memory (u1, u2) + + # return in register: + # %mm0-mm4: 4x4 pixels result + + + + + .macro biquad_4x4_pixels + .align 16 + movq 0(%edi), %mm4 # get state + movq 8(%edi), %mm5 + df2 %mm0 # compute 4 biquads + df2 %mm1 + df2 %mm2 + df2 %mm3 + movq %mm4, 0(%edi) # store state + movq %mm5, 8(%edi) + .endm + + + + # in order to use the 4 line parallel biquad routine on horizontal + # lines, we need to reorder (rotate or transpose) the matrix, since + # images are scanline encoded, and we want to work in parallell + # on 4 lines. + # + # since the 4 lines are independent, it doesnt matter in which order + # the the vector elements are present. + # + # this allows us to use the same routine for left->right and right->left + # processing. + # + # some comments on the non-abelean group of square isometries consisting of + # (I) identity + # (H) horizontal axis mirror + # (V) vertical axis mirror + # (T) transpose (diagonal axis mirror) + # (A) antitranspose (antidiagonal axis mirror) + # (R1) 90deg anticlockwize rotation + # (R2) 180deg rotation + # (R3) 90deg clockwize rotation + # + # + # we basicly have two options: (R1,R3) or (T,A) + # we opt for T and A because they are self inverting, which improves locality + # + # use antitranspose for right to left an transpose + # for left to right (little endian) + + + # antitranspose 4x4 + + # input + # %mm3 == {d0 d1 d2 d3} + # %mm2 == {c0 c1 c2 c3} + # %mm1 == {b0 b1 b2 b3} + # %mm0 == {a0 a1 a2 a3} + + # output + # %mm3 == {a3 b3 c3 d3} + # %mm2 == {a2 b2 c2 d2} + # %mm1 == {a1 b1 c1 d1} + # %mm0 == {a0 b0 c0 d0} + + + .macro antitranspose_4x4: + movq %mm3, %mm4 + punpcklwd %mm1, %mm4 # mm4 <- {b2 d2 b3 d3} + movq %mm3, %mm5 + punpckhwd %mm1, %mm5 # mm5 <- {b0 d0 b1 d1} + + movq %mm2, %mm6 + punpcklwd %mm0, %mm6 # mm6 <- {a2 c2 a3 c3} + movq %mm2, %mm7 + punpckhwd %mm0, %mm7 # mm7 <- {a0 c0 a1 c1} + + movq %mm4, %mm3 + punpcklwd %mm6, %mm3 # mm3 <- {a3 b3 c3 d3} + movq %mm4, %mm2 + punpckhwd %mm6, %mm2 # mm2 <- {a2 b2 c2 d2} + + movq %mm5, %mm1 + punpcklwd %mm7, %mm1 # mm1 <- {a1 b1 c1 d1} + movq %mm5, %mm0 + punpckhwd %mm7, %mm0 # mm0 <- {a0 b0 c0 d0} + + .endm + + + # transpose 4x4 + + # input + # %mm3 == {d3 d2 d1 d0} + # %mm2 == {c3 c2 c1 c0} + # %mm1 == {b3 b2 b1 b0} + # %mm0 == {a3 a2 a1 a0} + + # output + # %mm3 == {d3 c3 b3 a3} + # %mm2 == {d2 c2 b2 a2} + # %mm1 == {d1 c1 b1 a1} + # %mm0 == {d0 c0 b0 a0} + + + .macro transpose_4x4: + movq %mm0, %mm4 + punpcklwd %mm2, %mm4 # mm4 <- {c1 a1 c0 a0} + movq %mm0, %mm5 + punpckhwd %mm2, %mm5 # mm5 <- {c3 a3 c2 a2} + + movq %mm1, %mm6 + punpcklwd %mm3, %mm6 # mm6 <- {d1 b1 d0 b0} + movq %mm1, %mm7 + punpckhwd %mm3, %mm7 # mm7 <- {d3 b3 d2 b2} + + movq %mm4, %mm0 + punpcklwd %mm6, %mm0 # mm0 <- {d0 c0 b0 a0} + movq %mm4, %mm1 + punpckhwd %mm6, %mm1 # mm1 <- {d1 c1 b1 a1} + + movq %mm5, %mm2 + punpcklwd %mm7, %mm2 # mm2 <- {d2 c2 b2 a2} + movq %mm5, %mm3 + punpckhwd %mm7, %mm3 # mm3 <- {d3 c3 b3 a3} + + .endm + +.globl pixel_biquad_vertb_s16 +.type pixel_biquad_vertb_s16,@function + + +# pixel_biquad_vertbr_s16(char *pixel_array, int nb_rows, int linewidth, short int coef[20], short int state[8]) + + +pixel_biquad_vertb_s16: + + + pushl %ebp + movl %esp, %ebp + push %ebx + push %esi + push %edi + + movl 8(%ebp), %ebx # pixel array offset + movl 12(%ebp), %ecx # nb of 4x4 pixblocks + movl 16(%ebp), %edx # line with + + movl 20(%ebp), %esi # coefs + movl 24(%ebp), %edi # state + + shll $1, %edx # short int addressing + movl %edx, %eax + shll $1, %eax + addl %edx, %eax # eax = 3 * edx + + .align 16 + .biquad_vertb_line_loop: + movq (%ebx), %mm0 + movq (%ebx,%edx,1), %mm1 + movq (%ebx,%edx,2), %mm2 + movq (%ebx,%eax,1), %mm3 + biquad_4x4_pixels + movq %mm0, (%ebx) + movq %mm1, (%ebx,%edx,1) + movq %mm2, (%ebx,%edx,2) + movq %mm3, (%ebx,%eax,1) + addl %edx, %ebx + addl %eax, %ebx + decl %ecx + jnz .biquad_vertb_line_loop + + emms + + pop %edi + pop %esi + pop %ebx + leave + ret +.globl pixel_biquad_verbt_s16 +.type pixel_biquad_verbt_s16,@function + + +# pixel_biquad_vertbt_s16(char *pixel_array, int nb_rows, int linewidth, short int coef[20], short int state[8]) + + +pixel_biquad_verbt_s16: + + + pushl %ebp + movl %esp, %ebp + push %ebx + push %esi + push %edi + + movl 8(%ebp), %ebx # pixel array offset + movl 12(%ebp), %ecx # nb of 4x4 pixblocks + movl 16(%ebp), %eax # line with + + shll $3, %eax # 4 line byte spacing + decl %ecx + mul %ecx + incl %ecx + addl %eax, %ebx # ebx points to last pixblock + + movl 16(%ebp), %edx # line with + + movl 20(%ebp), %esi # coefs + movl 24(%ebp), %edi # state + + shll $1, %edx # short int addressing + movl %edx, %eax + shll $1, %eax + addl %edx, %eax # eax = 3 * edx + + .align 16 + .biquad_verbt_line_loop: + movq (%ebx), %mm3 + movq (%ebx,%edx,1), %mm2 + movq (%ebx,%edx,2), %mm1 + movq (%ebx,%eax,1), %mm0 + biquad_4x4_pixels + movq %mm3, (%ebx) + movq %mm2, (%ebx,%edx,1) + movq %mm1, (%ebx,%edx,2) + movq %mm0, (%ebx,%eax,1) + subl %edx, %ebx + subl %eax, %ebx + decl %ecx + jnz .biquad_verbt_line_loop + + emms + + pop %edi + pop %esi + pop %ebx + leave + ret + +.globl pixel_biquad_horlr_s16 +.type pixel_biquad_horlr_s16,@function +# pixel_biquad_hor_s16(char *pixel_array, int nb_rows, int linewidth, short int coef[20], short int state[8]) + +pixel_biquad_horlr_s16: + + + pushl %ebp + movl %esp, %ebp + push %ebx + push %esi + push %edi + + movl 8(%ebp), %ebx # pixel array offset + movl 12(%ebp), %ecx # nb of 4x4 pixblocks + movl 16(%ebp), %edx # line with + + movl 20(%ebp), %esi # coefs + movl 24(%ebp), %edi # state + + shll $1, %edx # short int addressing + movl %edx, %eax + shll $1, %eax + addl %edx, %eax # eax = 3 * edx + + .align 16 + .biquad_horlr_line_loop: + movq (%ebx), %mm0 + movq (%ebx,%edx,1), %mm1 + movq (%ebx,%edx,2), %mm2 + movq (%ebx,%eax,1), %mm3 + transpose_4x4 + biquad_4x4_pixels + transpose_4x4 + movq %mm0, (%ebx) + movq %mm1, (%ebx,%edx,1) + movq %mm2, (%ebx,%edx,2) + movq %mm3, (%ebx,%eax,1) + addl $8, %ebx + decl %ecx + jnz .biquad_horlr_line_loop + + emms + + pop %edi + pop %esi + pop %ebx + leave + ret + + +.globl pixel_biquad_horrl_s16 +.type pixel_biquad_horrl_s16,@function +# pixel_biquad_horrl_s16(char *pixel_array, int nb_rows, int linewidth, short int coef[20], short int state[8]) + +pixel_biquad_horrl_s16: + + pushl %ebp + movl %esp, %ebp + push %ebx + push %esi + push %edi + + movl 8(%ebp), %ebx # pixel array offset + movl 12(%ebp), %ecx # nb of 4x4 pixblocks + movl 16(%ebp), %edx # line with + + + movl %ecx, %eax + decl %eax + shll $3, %eax + addl %eax, %ebx # ebx points to last pixblock + + + movl 20(%ebp), %esi # coefs + movl 24(%ebp), %edi # state + + shll $1, %edx # short int addressing + movl %edx, %eax + shll $1, %eax + addl %edx, %eax # eax = 3 * edx + + .align 16 + .biquad_horrl_line_loop: + movq (%ebx), %mm0 + movq (%ebx,%edx,1), %mm1 + movq (%ebx,%edx,2), %mm2 + movq (%ebx,%eax,1), %mm3 + antitranspose_4x4 + biquad_4x4_pixels + antitranspose_4x4 + movq %mm0, (%ebx) + movq %mm1, (%ebx,%edx,1) + movq %mm2, (%ebx,%edx,2) + movq %mm3, (%ebx,%eax,1) + subl $8, %ebx + decl %ecx + jnz .biquad_horrl_line_loop + + emms + + pop %edi + pop %esi + pop %ebx + leave + ret + + +.globl pixel_biquad_time_s16 +.type pixel_biquad_time_s16,@function +# pixel_biquad_time_s16(short int *pixel_array, short int *s1, short int *s2, short int *coefs, int nb_4_pix_vectors) + +pixel_biquad_time_s16: + + pushl %ebp + movl %esp, %ebp + push %ebx + push %esi + push %edi + + movl 8(%ebp), %ebx # pixel array offset + movl 12(%ebp), %edx # state 1 array + movl 16(%ebp), %edi # state 2 array + + movl 20(%ebp), %esi # coefs + movl 24(%ebp), %ecx # nb of 4 pixel vectors + + + .align 16 + .biquad_time_loop: + movq (%ebx), %mm0 # get input + movq (%edx), %mm4 # get state 1 + movq (%edi), %mm5 # get state 2 + df2 %mm0 # compute direct form 2 + movq %mm0, (%ebx) # write output + movq %mm5, (%edi) # write state 2 + movq %mm4, (%edx) # write state 1 + addl $8, %ebx + addl $8, %edi + addl $8, %edx + decl %ecx + jnz .biquad_time_loop + + emms + + pop %edi + pop %esi + pop %ebx + leave + ret + + diff --git a/system/mmx/pixel_ca_s1.s b/system/mmx/pixel_ca_s1.s new file mode 100644 index 0000000..d9c730f --- /dev/null +++ b/system/mmx/pixel_ca_s1.s @@ -0,0 +1,189 @@ +# Pure Data Packet mmx routine. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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 file contains assembler routines for 2D 1 bit cellular automata + # processing. it is organized around a feeder kernel and a + # stack based bit processor (virtual forth machine) + # + # the feeder kernel is responsable for loading/storing CA cells + # from/to memory. data in memory is organized as a scanline + # encoded toroidial bitplane (lsb = left). to simplify the kernel, the top + # left corner of the rectangular grid of pixels will shift down + # every processing step. + # + # the stack machine has the following architecture: + # CA stack: %esi, TOS: %mm0 (32x2 pixels. lsw = top row) + # CA horizon: %mm4-%mm7 (64x4 pixels. %mm4 = top row) + # + # the stack size / organization is not known to the stack machine. + # it can be thought of as operating on a 3x3 cell neightbourhood. + # the only purpose of forth program is to determine the CA local update rule. + # + # the machine is supposed to be very minimal. no looping control. + # no adressing modes. no conditional code (hey, this is an experiment!) + # so recursion is not allowed (no way to stop it) + # there are 9 words to load the cell neigbourhood on the stack. + # the rest is just logic and stack manips. + + + # this file contains pure asm macros. it is to be included before assembly + # after scaforth.pl has processed the .scaf file + + + # *************************** CA CELL ACCESS MACROS ***************************** + # fetchTL - fetchBR + + # shift / load rectangle macros: + + # shift rectangle horizontal + # result is in reg1 + .macro shift reg1 reg2 count + psllq $(32+\count), \reg1 + psrlq $(32-\count), \reg2 + psrlq $32, \reg1 + psllq $32, \reg2 + por \reg2, \reg1 + .endm + + .macro ldtop reg1 reg2 + movq %mm4, \reg1 + movq %mm5, \reg2 + .endm + + .macro ldcenter reg1 reg2 + movq %mm5, \reg1 + movq %mm6, \reg2 + .endm + + .macro ldbottom reg1 reg2 + movq %mm6, \reg1 + movq %mm7, \reg2 + .endm + + + # fetch from top row + + # fetch the top left square + .macro fetchTL + ldtop %mm0, %mm1 + shift %mm0, %mm1, -1 + .endm + + # fetch the top mid square + .macro fetchTM + ldtop %mm0, %mm1 + shift %mm0, %mm1, 0 + .endm + + # fetch the top right square + .macro fetchTR + ldtop %mm0, %mm1 + shift %mm0, %mm1, 1 + .endm + + + + # fetch from center row + + # fetch the mid left square + .macro fetchML + ldcenter %mm0, %mm1 + shift %mm0, %mm1, -1 + .endm + + # fetch the mid mid square + .macro fetchMM + ldcenter %mm0, %mm1 + shift %mm0, %mm1, 0 + .endm + + # fetch the mid right square + .macro fetchMR + ldcenter %mm0, %mm1 + shift %mm0, %mm1, 1 + .endm + + + + + + # fetch from bottom row + + # fetch the bottom left square + .macro fetchBL + ldbottom %mm0, %mm1 + shift %mm0, %mm1, -1 + .endm + + # fetch the bottom mid square + .macro fetchBM + ldbottom %mm0, %mm1 + shift %mm0, %mm1, 0 + .endm + + # fetch the bottom right square + .macro fetchBR + ldbottom %mm0, %mm1 + shift %mm0, %mm1, 1 + .endm + + + + # *************************** CA STACK MANIP MACROS ***************************** + # dup drop dropdup swap nip dropover + + .macro dup + lea -8(%esi), %esi + movq %mm0, (%esi) + .endm + + .macro drop + movq (%esi), %mm0 + lea 8(%esi), %esi + .endm + + .macro dropdup + movq (%esi), %mm0 + .endm + + .macro swap + movq (%esi), %mm1 + movq %mm0, (%esi) + movq %mm1, %mm0 + .endm + + .macro nip + lea 8(%esi), %esi + .endm + + .macro dropover + movq 8(%esi), %mm0 + .endm + + + # *************************** CA BOOLEAN LOGIC MACROS ***************************** + # overxor + + .macro overxor + pxor (%esi), %mm0 + .endm + + + + + diff --git a/system/mmx/pixel_cascade_s16.s b/system/mmx/pixel_cascade_s16.s new file mode 100644 index 0000000..bf88d08 --- /dev/null +++ b/system/mmx/pixel_cascade_s16.s @@ -0,0 +1,330 @@ +# Pure Data Packet mmx routine. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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. +# + + + # TODO: COUPLED CASCADE SECOND ORDER SECTION + # + # s1[k] = ar * s1[k-1] + ai * s2[k-1] + x[k] + # s2[k] = ar * s2[k-1] - ai * s1[k-1] + # y[k] = c0 * x[k] + c1 * s1[k-1] + c2 * s2[k-1] + + + # MACRO: df2 + # + # computes a coupled cascade + # + # input: %mm0 == input + # %mm1 == state 1 + # %mm2 == state 2 + # (%esi) == cascade coefs (ar ai c0 c1 c2) in s0.15 + # output: %mm0 == output + # %mm1 == state 1 + # %mm2 == state 2 + + + .macro coupled + pmovq %mm1, %mm3 # mm3 == s1[k-1] + pmovq %mm1, %mm4 # mm4 == s1[k-1] + pmovq %mm2, %mm5 # mm5 == s2[k-1] + pmovq %mm2, %mm6 # mm5 == s2[k-1] + pmulhw (%esi), %mm1 # mm1 == s1[k-1] * ar + pmulhw 8(%esi), %mm3 # mm3 == s1[k-1] * ai + pmulhw 24(%esi), %mm4 # mm4 == s1[k-1] * c1 + pmulhw (%esi), %mm2 # mm2 == s2[k-1] * ar + pmulhw 8(%esi), %mm5 # mm5 == s2[k-1] * ai + pmulhw 32(%esi), %mm6 # mm6 == s2[k-1] * c2 + paddw %mm5, %mm1 # mm1 == s1[k-1] * ar + s2[k-1] * ai + psubw %mm3, %mm2 # mm2 == s2[k-1] * ar - s1[k-1] * ai == s2[k] + paddw %mm0, %mm1 # mm1 == s1[k] + pmulhw 16(%esi), %mm0 # mm0 == x[k] * c0 + paddw %mm6, %mm4 # mm4 == s1[k-1] * c1 + s2[k-1] * c2 + paddw %mm4, %mm0 # mm0 == y[k] + .endm + + + + + # in order to use the 4 line parallel cascade routine on horizontal + # lines, we need to reorder (rotate or transpose) the matrix, since + # images are scanline encoded, and we want to work in parallell + # on 4 lines. + # + # since the 4 lines are independent, it doesnt matter in which order + # the the vector elements are present. + # + # this allows us to use the same routine for left->right and right->left + # processing. + # + # some comments on the non-abelean group of square isometries consisting of + # (I) identity + # (H) horizontal axis mirror + # (V) vertical axis mirror + # (T) transpose (diagonal axis mirror) + # (A) antitranspose (antidiagonal axis mirror) + # (R1) 90deg anticlockwize rotation + # (R2) 180deg rotation + # (R3) 90deg clockwize rotation + # + # + # we basicly have two options: (R1,R3) or (T,A) + # we opt for T and A because they are self inverting, which improves locality + # + # use antitranspose for right to left an transpose + # for left to right (little endian) + + + # antitranspose 4x4 + + # input + # %mm3 == {d0 d1 d2 d3} + # %mm2 == {c0 c1 c2 c3} + # %mm1 == {b0 b1 b2 b3} + # %mm0 == {a0 a1 a2 a3} + + # output + # %mm3 == {a3 b3 c3 d3} + # %mm2 == {a2 b2 c2 d2} + # %mm1 == {a1 b1 c1 d1} + # %mm0 == {a0 b0 c0 d0} + + + .macro antitranspose_4x4: + movq %mm3, %mm4 + punpcklwd %mm1, %mm4 # mm4 <- {b2 d2 b3 d3} + movq %mm3, %mm5 + punpckhwd %mm1, %mm5 # mm5 <- {b0 d0 b1 d1} + + movq %mm2, %mm6 + punpcklwd %mm0, %mm6 # mm6 <- {a2 c2 a3 c3} + movq %mm2, %mm7 + punpckhwd %mm0, %mm7 # mm7 <- {a0 c0 a1 c1} + + movq %mm4, %mm3 + punpcklwd %mm6, %mm3 # mm3 <- {a3 b3 c3 d3} + movq %mm4, %mm2 + punpckhwd %mm6, %mm2 # mm2 <- {a2 b2 c2 d2} + + movq %mm5, %mm1 + punpcklwd %mm7, %mm1 # mm1 <- {a1 b1 c1 d1} + movq %mm5, %mm0 + punpckhwd %mm7, %mm0 # mm0 <- {a0 b0 c0 d0} + + .endm + + + # transpose 4x4 + + # input + # %mm3 == {d3 d2 d1 d0} + # %mm2 == {c3 c2 c1 c0} + # %mm1 == {b3 b2 b1 b0} + # %mm0 == {a3 a2 a1 a0} + + # output + # %mm3 == {d3 c3 b3 a3} + # %mm2 == {d2 c2 b2 a2} + # %mm1 == {d1 c1 b1 a1} + # %mm0 == {d0 c0 b0 a0} + + + .macro transpose_4x4: + movq %mm0, %mm4 + punpcklwd %mm2, %mm4 # mm4 <- {c1 a1 c0 a0} + movq %mm0, %mm5 + punpckhwd %mm2, %mm5 # mm5 <- {c3 a3 c2 a2} + + movq %mm1, %mm6 + punpcklwd %mm3, %mm6 # mm6 <- {d1 b1 d0 b0} + movq %mm1, %mm7 + punpckhwd %mm3, %mm7 # mm7 <- {d3 b3 d2 b2} + + movq %mm4, %mm0 + punpcklwd %mm6, %mm0 # mm0 <- {d0 c0 b0 a0} + movq %mm4, %mm1 + punpckhwd %mm6, %mm1 # mm1 <- {d1 c1 b1 a1} + + movq %mm5, %mm2 + punpcklwd %mm7, %mm2 # mm2 <- {d2 c2 b2 a2} + movq %mm5, %mm3 + punpckhwd %mm7, %mm3 # mm3 <- {d3 c3 b3 a3} + + .endm + +.globl pixel_cascade_vertb_s16 +.type pixel_cascade_vertb_s16,@function + + +# pixel_cascade_vertbr_s16(char *pixel_array, int nb_rows, int linewidth, short int coef[20], short int state[8]) + + +pixel_cascade_vertb_s16: + + + pushl %ebp + movl %esp, %ebp + push %ebx + push %esi + push %edi + + movl 8(%ebp), %ebx # pixel array offset + movl 12(%ebp), %ecx # nb of 4x4 pixblocks + movl 16(%ebp), %edx # line with + + movl 20(%ebp), %esi # coefs + movl 24(%ebp), %edi # state + + shll $1, %edx # short int addressing + subl %edx, %ebx + + movq 0(%edi), %mm1 # s1[k-1] + movq 8(%edi), %mm2 # s2[k-1] + .align 16 + .cascade_vertb_line_loop: + + movq (%ebx,%edx,1), %mm3 + movq %mm3, %mm0 + addl %edx, %ebx + coupled + movq %mm0, (%ebx) + + movq (%ebx,%edx,1), %mm3 + movq %mm3, %mm0 + addl %edx, %ebx + coupled + movq %mm0, (%ebx) + + movq (%ebx,%edx,1), %mm3 + movq %mm3, %mm0 + addl %edx, %ebx + coupled + movq %mm0, (%ebx) + + movq (%ebx,%edx,1), %mm3 + movq %mm3, %mm0 + addl %edx, %ebx + coupled + movq %mm0, (%ebx) + + decl %ecx + jnz .cascade_vertb_line_loop + + movq %mm1, 0(%edi) # s1[k-1] + movq %mm2, 8(%edi) # s2[k-1] + + emms + + pop %edi + pop %esi + pop %ebx + leave + ret + +.globl pixel_cascade_horlr_s16 +.type pixel_cascade_horlr_s16,@function + + +# pixel_cascade_hor_s16(char *pixel_array, int nb_rows, int linewidth, short int coef[20], short int state[8]) + + +pixel_cascade_horlr_s16: + + + pushl %ebp + movl %esp, %ebp + push %ebx + push %esi + push %edi + + movl 8(%ebp), %ebx # pixel array offset + movl 12(%ebp), %ecx # nb of 4x4 pixblocks + movl 16(%ebp), %edx # line with + + movl 20(%ebp), %esi # coefs + movl 24(%ebp), %edi # state + + shll $1, %edx # short int addressing + movl %edx, %eax + shll $1, %eax + addl %edx, %eax # eax = 3 * edx + + + .align 16 + .cascade_horlr_line_loop: + movq (%edi), %mm1 + movq 8(%edi), %mm2 + + movq (%ebx), %mm0 + movq (%ebx,%edx,1), %mm1 + movq (%ebx,%edx,2), %mm2 + movq (%ebx,%eax,1), %mm3 + + transpose_4x4 + + movq %mm1, (%ebx,%edx,1) + movq %mm2, (%ebx,%edx,2) + movq %mm3, (%ebx,%eax,1) + + coupled + + movq %mm0, (%ebx) + movq (%ebx,%edx,1), %mm3 + movq %mm3, %mm0 + + coupled + + movq %mm0, (%ebx, %edx,1) + movq (%ebx,%edx,2), %mm3 + movq %mm3, %mm0 + + coupled + + movq %mm0, (%ebx, %edx,2) + movq (%ebx,%eax,1), %mm3 + movq %mm3, %mm0 + + coupled + + movq %mm1, 0(%edi) # s1[k-1] + movq %mm2, 8(%edi) # s2[k-1] + + movq %mm0, %mm3 + movq (%ebx), %mm0 + movq (%ebx,%edx,1), %mm1 + movq (%ebx,%edx,2), %mm2 + + transpose_4x4 + + movq %mm0, (%ebx) + movq %mm1, (%ebx,%edx,1) + movq %mm2, (%ebx,%edx,2) + movq %mm3, (%ebx,%eax,1) + + addl $8, %ebx + decl %ecx + jnz .cascade_horlr_line_loop + + emms + + pop %edi + pop %esi + pop %ebx + leave + ret + + + diff --git a/system/mmx/pixel_cheby_s16.s b/system/mmx/pixel_cheby_s16.s new file mode 100644 index 0000000..2afe9e2 --- /dev/null +++ b/system/mmx/pixel_cheby_s16.s @@ -0,0 +1,90 @@ +# Pure Data Packet mmx routine. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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. +# +.globl pixel_cheby_s16_3plus +.type pixel_cheby_s16_3plus,@function + +# void pixel_cheby_s16(int *buf, int nb_8pixel_vectors, int order+1, short int *coefs) + + +# coefs are s2.13 fixed point (-4->4) +pixel_cheby_s16_3plus: + pushl %ebp + movl %esp, %ebp + push %esi + push %edi + push %edx + + movl 8(%ebp), %esi # input array + movl 12(%ebp), %ecx # vector count + movl 16(%ebp), %eax # get order+1 + + shll $3, %eax + movl 20(%ebp), %edx + addl %eax, %edx # edx = coef endx address + +# jmp skip + + .align 16 + .loop_cheby: + + movl 20(%ebp), %edi # get coefs + movq (%esi), %mm0 # load 4 pixels from memory (mm0 = x) + pcmpeqw %mm2, %mm2 + movq %mm0, %mm1 # mm1 (T_n-1) <- x + psrlw $1, %mm2 # mm2 (T_n-2) <- 1 + + + movq (%edi), %mm4 # mm4 (acc) == a0 + psraw $1, %mm4 # mm4 == a0/2 + movq %mm0, %mm5 # mm5 (intermediate) + pmulhw 8(%edi), %mm5 # mm5 == (x * a1)/2 + paddsw %mm5, %mm4 # acc = c0 + c1 x + addl $16, %edi + + .loop_cheby_inner: + movq %mm1, %mm3 # mm3 == T_n-1 + psraw $2, %mm2 # mm2 == T_n-2 / 4 + pmulhw %mm0, %mm3 # mm3 == (2 x T_n-1) / 4 + psubsw %mm2, %mm3 # mm3 == (2 x T_n-1 - T_n-2) / 4 + paddsw %mm3, %mm3 + paddsw %mm3, %mm3 # mm3 == T_n + movq %mm1, %mm2 # mm2 == new T_n-1 + movq %mm3, %mm1 # mm3 == new T_n-2 + pmulhw (%edi), %mm3 # mm3 = a_n * T_n / 2 + paddsw %mm3, %mm4 # accumulate + addl $8, %edi + cmpl %edx, %edi + jne .loop_cheby_inner + + paddsw %mm4, %mm4 # compensate for 0.125 factor + paddsw %mm4, %mm4 + paddsw %mm4, %mm4 + movq %mm4, (%esi) # store result in memory + addl $8, %esi # increment source/dest pointer + decl %ecx + jnz .loop_cheby # loop + +skip: + emms + + pop %edx + pop %edi + pop %esi + leave + ret + diff --git a/system/mmx/pixel_conv_hor_s16.s b/system/mmx/pixel_conv_hor_s16.s new file mode 100644 index 0000000..e90a692 --- /dev/null +++ b/system/mmx/pixel_conv_hor_s16.s @@ -0,0 +1,134 @@ +# Pure Data Packet mmx routine. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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. +# + # intermediate function + + # input in register: + # %mm0: left 4 pixels + # %mm1: middle 4 pixels + # %mm2: right 4 pixels + + # %mm5: left 4 pixel masks + # %mm6: middle 4 pixel masks + # %mm7: right 4 pixel masks + + # return in register: + # %mm0: middle 4 pixels result + + + .conv_hor_4_pixels: + .align 16 + + # compute quadruplet + + # get left pixels + psrlq $48, %mm0 # shift word 3 to byte 0 + movq %mm1, %mm4 + psllq $16, %mm4 # shift word 0,1,2 to 1,2,3 + por %mm4, %mm0 # combine + pmulhw %mm5, %mm0 + psllw $1, %mm0 + + + # get middle pixels + movq %mm1, %mm4 + pmulhw %mm6, %mm4 + psllw $1, %mm4 + paddsw %mm4, %mm0 + + + # get right pixels + movq %mm2, %mm3 + psllq $48, %mm3 # shift word 0 to word 3 + movq %mm1, %mm4 + psrlq $16, %mm4 # shift word 1,2,3 to 0,1,2 + por %mm4, %mm3 # combine + pmulhw %mm7, %mm3 + psllw $1, %mm3 + paddsw %mm3, %mm0 # accumulate + + ret + +.globl pixel_conv_hor_s16 +.type pixel_conv_hor_s16,@function + + +# pixel_conv_hor_s16(short int *pixel_array, int nb_4_pixel_vectors, short int border[4], short int mask[12]) +# horizontal unsigned pixel conv (1/4 1/2 1/4) not tested +# NOT TESTED + + +pixel_conv_hor_s16: + + + pushl %ebp + movl %esp, %ebp + push %esi + push %edi + + movl 8(%ebp), %esi # pixel array offset + movl 12(%ebp), %ecx # nb of 8 pixel vectors in a row (at least 2) + + movl 20(%ebp), %edi # mask vector + movq (%edi), %mm5 + movq 8(%edi), %mm6 + movq 16(%edi), %mm7 + + movl 16(%ebp), %edi # boundary pixel vector + + + + movq (%edi), %mm0 # init regs (left edge, so mm0 is zero) + movq (%esi), %mm1 + movq 8(%esi), %mm2 + + decl %ecx # loop has 2 terminator stubs + decl %ecx # todo: handle if ecx < 3 + + jmp .conv_line_loop + + + .align 16 + .conv_line_loop: + call .conv_hor_4_pixels # compute conv + movq %mm0, (%esi) # store result + movq %mm1, %mm0 # mm0 <- prev (%esi) + movq %mm2, %mm1 # mm1 <- 8(%esi) + movq 16(%esi), %mm2 # mm2 <- 16(%esi) + + addl $8, %esi # increase pointer + decl %ecx + jnz .conv_line_loop + + call .conv_hor_4_pixels # compute conv + movq %mm0, (%esi) # store result + movq %mm1, %mm0 # mm0 <- prev (%esi) + movq %mm2, %mm1 # mm1 <- 8(%esi) + movq (%edi), %mm2 # mm2 <- border + + call .conv_hor_4_pixels # compute last vector + movq %mm0, 8(%esi) # store it + + emms + + pop %edi + pop %esi + leave + ret + + + diff --git a/system/mmx/pixel_conv_ver_s16.s b/system/mmx/pixel_conv_ver_s16.s new file mode 100644 index 0000000..ae2456f --- /dev/null +++ b/system/mmx/pixel_conv_ver_s16.s @@ -0,0 +1,128 @@ +# Pure Data Packet mmx routine. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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. +# +#TODO: fix out of bound acces in conv_ver and conv_hor + + # intermediate function + + # input in register: + # %mm0: top 4 pixels + # %mm1: middle 4 pixels + # %mm2: bottom 4 pixels + + # %mm5: top 4 pixel mask + # %mm6: middle 4 pixel mask + # %mm7: bottom 4 pixel mask + + # return in register: + # %mm0: middle 4 pixels result + + + .conv_ver_4_pixels: + .align 16 + + # compute quadruplet + + # get top pixel + pmulhw %mm5, %mm0 + psllw $1, %mm0 + + # get middle pixel + movq %mm1, %mm4 + pmulhw %mm6, %mm4 + psllw $1, %mm4 + paddsw %mm4, %mm0 + + # get bottom pixel + movq %mm2, %mm3 + pmulhw %mm7, %mm3 + psllw $1, %mm3 # mm3 <- mm3/4 + paddsw %mm3, %mm0 + + ret + +.globl pixel_conv_ver_s16 +.type pixel_conv_ver_s16,@function + + +# pixel_conv_ver_s16(short int *pixel_array, int nb_4_pixel_vectors, int row_byte_size, short int border[4]) +# horizontal unsigned pixel conv (1/4 1/2 1/4) not tested +# NOT TESTED + + +pixel_conv_ver_s16: + + + pushl %ebp + movl %esp, %ebp + push %esi + push %edi + + movl 8(%ebp), %esi # pixel array offset + movl 12(%ebp), %ecx # nb of 4 pixel vectors in a row (at least 2) + movl 16(%ebp), %edx # rowsize in bytes + + movl 24(%ebp), %edi # mask vector + movq (%edi), %mm5 + movq 8(%edi), %mm6 + movq 16(%edi), %mm7 + + movl 20(%ebp), %edi # edge vector + + + shll $1, %edx + decl %ecx # loop has a terminator stub + decl %ecx # loop has another terminator stub + + + movq (%edi), %mm0 # init regs (left edge, so mm0 is zero) + movq (%esi), %mm1 + movq (%esi,%edx,1), %mm2 + jmp .conv_line_loop + + + .align 16 + .conv_line_loop: + call .conv_ver_4_pixels # compute conv + movq %mm0, (%esi) # store result + movq %mm1, %mm0 # mm0 <- prev (%esi) + movq %mm2, %mm1 # mm1 <- (%esi,%edx,1) + movq (%esi,%edx,2), %mm2 # mm2 <- (%esi,%edx,2) + + addl %edx, %esi # increase pointer + decl %ecx + jnz .conv_line_loop + + call .conv_ver_4_pixels # compute conv + movq %mm0, (%esi) # store result + movq %mm1, %mm0 # mm0 <- prev (%esi) + movq %mm2, %mm1 # mm1 <- (%esi,%edx,1) + movq (%edi), %mm2 # clear invalid edge vector + + addl %edx, %esi # increase pointer + call .conv_ver_4_pixels # compute last vector + movq %mm0, (%esi) # store it + + emms + + pop %edi + pop %esi + leave + ret + + + diff --git a/system/mmx/pixel_crot_s16.s b/system/mmx/pixel_crot_s16.s new file mode 100644 index 0000000..2427869 --- /dev/null +++ b/system/mmx/pixel_crot_s16.s @@ -0,0 +1,153 @@ +# Pure Data Packet mmx routine. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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. +# +.globl pixel_crot3d_s16 +.type pixel_crot3d_s16,@function + + +# 3 dimensional colour space rotation +# 3x3 matrix is column encoded, each coefficient is a 4x16 bit fixed point vector + +# void pixel_crot3d_s16(int *buf, int nb_4pixel_vectors_per_plane, short int *matrix) + +pixel_crot3d_s16: + pushl %ebp + movl %esp, %ebp + push %esi + push %edi + + + movl 8(%ebp), %esi # input array + movl 12(%ebp), %ecx # pixel count + movl 16(%ebp), %edi # rotation matrix + movl %ecx, %edx + shll $3, %edx # %edx = plane spacing + + + .align 16 + .loop_crot3d: + + movq (%esi), %mm0 # get 1st component + movq (%esi,%edx,1), %mm6 # get 2nd component + movq (%esi,%edx,2), %mm7 # get 3rd component + + movq %mm0, %mm1 # copy 1st component + movq %mm0, %mm2 + + pmulhw (%edi), %mm0 # mul first column + pmulhw 8(%edi), %mm1 + pmulhw 16(%edi), %mm2 + + movq %mm6, %mm5 # copy 2nd component + movq %mm6, %mm3 + + pmulhw 24(%edi), %mm6 # mul second column + pmulhw 32(%edi), %mm5 + pmulhw 40(%edi), %mm3 + + paddsw %mm6, %mm0 # accumulate + paddsw %mm5, %mm1 + paddsw %mm3, %mm2 + + movq %mm7, %mm4 # copy 3rd component + movq %mm7, %mm6 + + pmulhw 48(%edi), %mm4 # mul third column + pmulhw 56(%edi), %mm6 + pmulhw 64(%edi), %mm7 + + paddsw %mm4, %mm0 # accumulate + paddsw %mm6, %mm1 + paddsw %mm7, %mm2 + + paddsw %mm0, %mm0 # double (fixed point normalization) + paddsw %mm1, %mm1 + paddsw %mm2, %mm2 + + movq %mm0, (%esi) # store + movq %mm1, (%esi, %edx, 1) + movq %mm2, (%esi, %edx, 2) + + addl $8, %esi # increment source pointer + decl %ecx + jnz .loop_crot3d # loop + + emms + + pop %edi + pop %esi + leave + ret + + +.globl pixel_crot2d_s16 +.type pixel_crot2d_s16,@function + +# 2 dimensional colour space rotation +# 2x2 matrix is column encoded, each coefficient is a 4x16 bit fixed point vector + +# void pixel_crot2d_s16(int *buf, int nb_4pixel_vectors_per_plane, short int *matrix) + +pixel_crot2d_s16: + pushl %ebp + movl %esp, %ebp + push %esi + push %edi + + + movl 8(%ebp), %esi # input array + movl 12(%ebp), %ecx # pixel count + movl 16(%ebp), %edi # rotation matrix + movl %ecx, %edx + shll $3, %edx # %edx = plane spacing + + + .align 16 + .loop_crot2d: + + movq (%esi), %mm0 # get 1st component + movq (%esi,%edx,1), %mm2 # get 2nd component + + movq %mm0, %mm1 # copy 1st component + movq %mm2, %mm3 # copy 2nd component + + pmulhw (%edi), %mm0 # mul first column + pmulhw 8(%edi), %mm1 + + pmulhw 16(%edi), %mm2 # mul second column + pmulhw 24(%edi), %mm3 + + paddsw %mm2, %mm0 # accumulate + paddsw %mm3, %mm1 + + paddsw %mm0, %mm0 # fixed point gain correction + paddsw %mm1, %mm1 + + movq %mm0, (%esi) # store + movq %mm1, (%esi, %edx, 1) + + addl $8, %esi # increment source pointer + decl %ecx + jnz .loop_crot2d # loop + + emms + + pop %edi + pop %esi + leave + ret + diff --git a/system/mmx/pixel_gain.s b/system/mmx/pixel_gain.s new file mode 100644 index 0000000..5cd5057 --- /dev/null +++ b/system/mmx/pixel_gain.s @@ -0,0 +1,83 @@ +# Pure Data Packet mmx routine. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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. +# +.globl pixel_gain +.type pixel_gain,@function + +# mmx rgba pixel gain +# void asmtest(char *pixelarray, int32 nbpixels, int *rgba_gain) +# gains are 7.9 fixed point for rgba + +pixel_gain: + pushl %ebp + movl %esp, %ebp + push %esi + push %edi + + movl 8(%ebp), %esi # pixel array offset + movl 12(%ebp), %ecx # nb of elements + movl 16(%ebp), %edi # int16[4] array of gains + + prefetch (%esi) + + emms + sarl $2, %ecx # process 4 pixels per loop iteration + jz .exit + movq (%edi), %mm7 # read gain array from memory + jmp .loop_gain + + .align 16 + .loop_gain: + + prefetch 128(%esi) + movq (%esi), %mm5 # load pixel 1-2 from memory + movq 8(%esi), %mm6 # load pixel 3-4 from memory + pxor %mm0, %mm0 # zero mm0 - mm3 + pxor %mm1, %mm1 + pxor %mm2, %mm2 + pxor %mm3, %mm3 + punpcklbw %mm5, %mm0 # unpack 1st pixel into 8.8 bit ints + punpckhbw %mm5, %mm1 # unpack 2nd + punpcklbw %mm6, %mm2 # unpack 3rd + punpckhbw %mm6, %mm3 # unpack 4th + psrlw $0x1, %mm0 # shift right to clear sign bit 9.7 + psrlw $0x1, %mm1 + psrlw $0x1, %mm2 + psrlw $0x1, %mm3 + + pmulhw %mm7, %mm0 # multiply 1st pixel 9.7 * 7.9 -> 16.0 + pmulhw %mm7, %mm1 # multiply 2nd + pmulhw %mm7, %mm2 # multiply 3rd + pmulhw %mm7, %mm3 # multiply 4th + + packuswb %mm1, %mm0 # pack & saturate to 8bit vector + movq %mm0, (%esi) # store result in memory + packuswb %mm3, %mm2 # pack & saturate to 8bit vector + movq %mm2, 8(%esi) # store result in memory + + addl $16, %esi # increment source pointer + decl %ecx + jnz .loop_gain # loop + + .exit: + emms + + pop %edi + pop %esi + leave + ret + diff --git a/system/mmx/pixel_gain_s16.s b/system/mmx/pixel_gain_s16.s new file mode 100644 index 0000000..adcfdf5 --- /dev/null +++ b/system/mmx/pixel_gain_s16.s @@ -0,0 +1,71 @@ +# Pure Data Packet mmx routine. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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. +# +.globl pixel_gain_s16 +.type pixel_gain_s16,@function + +# gain is integer, shift count is down +# void pixel_gain_s16(int *buf, int nb_8pixel_vectors, short int gain[4], unsigned long long *shift) + +pixel_gain_s16: + pushl %ebp + movl %esp, %ebp + push %esi + push %edi + + movl 20(%ebp), %edi + movq (%edi), %mm6 # get shift vector + + movl 16(%ebp), %edi + movq (%edi), %mm7 # get gain vector + + movl 8(%ebp), %esi # input array + movl 12(%ebp), %ecx # pixel count + + + .align 16 + .loop_gain: + + movq (%esi), %mm0 # load 4 pixels from memory + movq %mm0, %mm1 + pmulhw %mm7, %mm1 # apply gain (s15.0) fixed point, high word + pmullw %mm7, %mm0 # low word + + movq %mm0, %mm2 # copy + movq %mm1, %mm3 + + punpcklwd %mm1, %mm0 # unpack lsw components + punpckhwd %mm3, %mm2 # unpack msw components + + psrad %mm6, %mm0 # apply signed shift + psrad %mm6, %mm2 + + packssdw %mm2, %mm0 # pack result & saturate + movq %mm0, (%esi) # store result + + + addl $8, %esi # increment source pointer + decl %ecx + jnz .loop_gain # loop + + emms + + pop %edi + pop %esi + leave + ret + diff --git a/system/mmx/pixel_mix_s16.s b/system/mmx/pixel_mix_s16.s new file mode 100644 index 0000000..9bf41eb --- /dev/null +++ b/system/mmx/pixel_mix_s16.s @@ -0,0 +1,68 @@ +# Pure Data Packet mmx routine. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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. +# +.globl pixel_mix_s16 +.type pixel_mix_s16,@function + +# mmx rgba pixel gain +# void pixel_mix_s16(int *left, int *right, int nb_4pixel_vectors, +# short int gain_left[4], short int gain_right[4]) + +pixel_mix_s16: + pushl %ebp + movl %esp, %ebp + push %esi + push %edi + + movl 20(%ebp), %edi # int16[4] array of gains + movq (%edi), %mm6 # get left gain array + + movl 24(%ebp), %edi # int16[4] array of gains + movq (%edi), %mm7 # get right gain array + + movl 8(%ebp), %edi # left array + movl 12(%ebp), %esi # right array + movl 16(%ebp), %ecx # pixel count + + + .align 16 + .loop_mix: + +# prefetch 128(%esi) + movq (%esi), %mm1 # load right 4 pixels from memory + pmulhw %mm7, %mm1 # apply right gain + movq (%edi), %mm0 # load 4 left pixels from memory + pmulhw %mm6, %mm0 # apply left gain +# pslaw $1, %mm1 # shift left ((s).15 x (s).15 -> (s0).14)) +# pslaw $1, %mm0 + paddsw %mm0, %mm0 # no shift left arithmic, so use add instead + paddsw %mm1, %mm1 + paddsw %mm1, %mm0 # mix + movq %mm0, (%edi) + addl $8, %esi + addl $8, %edi + decl %ecx + jnz .loop_mix # loop + + emms + + + pop %edi + pop %esi + leave + ret + diff --git a/system/mmx/pixel_mul_s16.s b/system/mmx/pixel_mul_s16.s new file mode 100644 index 0000000..240a024 --- /dev/null +++ b/system/mmx/pixel_mul_s16.s @@ -0,0 +1,56 @@ +# Pure Data Packet mmx routine. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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. +# +.globl pixel_mul_s16 +.type pixel_mul_s16,@function + +# simple add +# void pixel_mul_s16(int *left, int *right, int nb_4pixel_vectors) + +pixel_mul_s16: + pushl %ebp + movl %esp, %ebp + push %esi + push %edi + + movl 8(%ebp), %edi # left array + movl 12(%ebp), %esi # right array + movl 16(%ebp), %ecx # pixel count + + + .align 16 + .loop_mix: + +# prefetch 128(%esi) + movq (%esi), %mm1 # load right 4 pixels from memory + movq (%edi), %mm0 # load 4 left pixels from memory + pmulhw %mm1, %mm0 # mul + psllw $1, %mm0 # fixed point shift correction + movq %mm0, (%edi) + addl $8, %esi + addl $8, %edi + decl %ecx + jnz .loop_mix # loop + + emms + + + pop %edi + pop %esi + leave + ret + diff --git a/system/mmx/pixel_pack_s16u8.s b/system/mmx/pixel_pack_s16u8.s new file mode 100644 index 0000000..57df702 --- /dev/null +++ b/system/mmx/pixel_pack_s16u8.s @@ -0,0 +1,126 @@ +# Pure Data Packet mmx routine. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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. +# +.globl pixel_pack_s16u8_y +.type pixel_pack_s16u8_y,@function + +# mmx rgba pixel gain +# void pixel_pack_s16u8_y(int *input, int *output, int nb_8pixel_vectors) + +pixel_pack_s16u8_y: + pushl %ebp + movl %esp, %ebp + push %esi + push %edi + +# movl 20(%ebp), %edi # int16[4] array of gains +# movq (%edi), %mm7 # get gain array +# psllw $1, %mm7 # adjust for shifted sign bit + + movl 8(%ebp), %esi # input array + movl 12(%ebp), %edi # output array + movl 16(%ebp), %ecx # pixel count + + pxor %mm6, %mm6 + + .align 16 + .loop_pack_y: + +# prefetch 128(%esi) + movq (%esi), %mm0 # load 4 pixels from memory +# pmulhw %mm7, %mm0 # apply gain + movq 8(%esi), %mm1 # load 4 pixels from memory +# pmulhw %mm7, %mm1 # apply gain + +# movq %mm0, %mm2 +# pcmpgtw %mm6, %mm2 # mm2 > 0 ? 0xffff : 0 +# pand %mm2, %mm0 + +# movq %mm1, %mm3 +# pcmpgtw %mm6, %mm3 # mm3 > 0 ? 0xffff : 0 +# pand %mm3, %mm1 + +# psllw $1, %mm0 # shift out sign bit +# psllw $1, %mm1 # shift out sign bit + + psraw $7, %mm0 # shift to lsb + psraw $7, %mm1 # shift to lsb + + packuswb %mm1, %mm0 # pack & saturate to 8bit vector + movq %mm0, (%edi) # store result in memory + + addl $16, %esi # increment source pointer + addl $8, %edi # increment dest pointer + decl %ecx + jnz .loop_pack_y # loop + + emms + + pop %edi + pop %esi + leave + ret + +.globl pixel_pack_s16u8_uv +.type pixel_pack_s16u8_uv,@function + +pixel_pack_s16u8_uv: + pushl %ebp + movl %esp, %ebp + push %esi + push %edi + +# movl 20(%ebp), %edi # int16[4] array of gains +# movq (%edi), %mm7 # get gain array + movl 8(%ebp), %esi # pixel array offset + movl 12(%ebp), %edi # nb of elements + movl 16(%ebp), %ecx # pixel count + + pcmpeqw %mm6, %mm6 + psllw $15, %mm6 + movq %mm6, %mm5 + psrlw $8, %mm5 + por %mm5, %mm6 # mm6 <- 8 times 0x80 + + .align 16 + .loop_pack_uv: + +# prefetch 128(%esi) + movq (%esi), %mm0 # load 4 pixels from memory +# pmulhw %mm7, %mm0 # apply gain + movq 8(%esi), %mm1 # load 4 pixels from memory +# pmulhw %mm7, %mm1 # apply gain + + psraw $8, %mm0 # shift to msb + psraw $8, %mm1 + + packsswb %mm1, %mm0 # pack & saturate to 8bit vector + pxor %mm6, %mm0 # flip sign bits + movq %mm0, (%edi) # store result in memory + + addl $16, %esi # increment source pointer + addl $8, %edi # increment dest pointer + decl %ecx + jnz .loop_pack_uv # loop + + emms + + pop %edi + pop %esi + leave + ret + diff --git a/system/mmx/pixel_rand_s16.s b/system/mmx/pixel_rand_s16.s new file mode 100644 index 0000000..649400b --- /dev/null +++ b/system/mmx/pixel_rand_s16.s @@ -0,0 +1,76 @@ +# Pure Data Packet mmx routine. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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. +# +.globl pixel_rand_s16 +.type pixel_rand_s16,@function + +# mmx rgba pixel gain +# void pixel_rand_s16(int *dst, nb_4pixel_vectors, short int random_seed[4]) + +pixel_rand_s16: + pushl %ebp + movl %esp, %ebp + push %esi + push %edi + + movl 16(%ebp), %esi # int16[4] array of random seeds + movl 8(%ebp), %edi # dst array + movl 12(%ebp), %ecx # pixel count + + movq (%esi), %mm6 + + + pcmpeqw %mm3, %mm3 + psrlw $15, %mm3 # get bit mask 4 times 0x0001 + + .align 16 + .loop_rand: + +# prefetch 128(%esi) + + + movq %mm6, %mm4 # get random vector + psrlw $15, %mm4 # get first component + movq %mm6, %mm5 + psrlw $14, %mm5 # get second component + pxor %mm5, %mm4 + movq %mm6, %mm5 + psrlw $12, %mm5 # get third component + pxor %mm5, %mm4 + movq %mm6, %mm5 + psrlw $3, %mm5 # get forth component + pxor %mm5, %mm4 + + psllw $1, %mm6 # shift left original random vector + pand %mm3, %mm4 # isolate new bit + por %mm4, %mm6 # combine into new random vector + + movq %mm6, (%edi) + addl $8, %edi + decl %ecx + jnz .loop_rand # loop + + + movq %mm6, (%esi) # store random seeds + + emms + + pop %edi + pop %esi + leave + ret + diff --git a/system/mmx/pixel_randmix_s16.s b/system/mmx/pixel_randmix_s16.s new file mode 100644 index 0000000..44e1702 --- /dev/null +++ b/system/mmx/pixel_randmix_s16.s @@ -0,0 +1,91 @@ +# Pure Data Packet mmx routine. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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. +# +.globl pixel_randmix_s16 +.type pixel_randmix_s16,@function + +# mmx rgba pixel gain +# void pixel_randmix_s16(int *left, int *right, int nb_4pixel_vectors, short int random_seed[4], short int threshold[4]) + +pixel_randmix_s16: + pushl %ebp + movl %esp, %ebp + push %esi + push %edi + + movl 20(%ebp), %edi # int16[4] array of random seeds + movq (%edi), %mm6 + + movl 24(%ebp), %edi # int16[4] array of thresholds + movq (%edi), %mm7 + + movl 8(%ebp), %edi # left array + movl 12(%ebp), %esi # right array + movl 16(%ebp), %ecx # pixel count + + pcmpeqw %mm3, %mm3 + psrlw $15, %mm3 # get bit mask 4 times 0x0001 + + .align 16 + .loop_randmix: + +# prefetch 128(%esi) + movq (%esi), %mm1 # load right 4 pixels from memory + movq (%edi), %mm0 # load 4 left pixels from memory + + movq %mm6, %mm2 # get random vector + pcmpgtw %mm7, %mm2 # compare random vector with threshold + movq %mm2, %mm5 + + pand %mm0, %mm2 # get left array's components + pandn %mm1, %mm5 # get right array's components + por %mm2, %mm5 + + movq %mm5, (%edi) # store pixels + + movq %mm6, %mm4 # get random vector + psrlw $15, %mm4 # get first component + movq %mm6, %mm5 + psrlw $14, %mm5 # get second component + pxor %mm5, %mm4 + movq %mm6, %mm5 + psrlw $12, %mm5 # get third component + pxor %mm5, %mm4 + movq %mm6, %mm5 + psrlw $3, %mm5 # get forth component + pxor %mm5, %mm4 + + psllw $1, %mm6 # shift left original random vector + pand %mm3, %mm4 # isolate new bit + por %mm4, %mm6 # combine into new random vector + + addl $8, %esi + addl $8, %edi + decl %ecx + jnz .loop_randmix # loop + + + movl 20(%ebp), %edi # int16[4] array of random seeds + movq %mm6, (%edi) # store random seeds + + emms + + pop %edi + pop %esi + leave + ret + diff --git a/system/mmx/pixel_resample_s16.s b/system/mmx/pixel_resample_s16.s new file mode 100644 index 0000000..3959f9c --- /dev/null +++ b/system/mmx/pixel_resample_s16.s @@ -0,0 +1,314 @@ + + +#interpolation data: +#* 4 vectors: neighbourhood for samples (TL, TR, BL, BR) +#* 2 vectors: fractional part (unsigned) +#* 2 vectors: addresses of pixel blocks + +#coord conversion data: +#1 vector: 32bit splatted address +#1 vector: 16bit splatted w-1 +#1 vector: 16bit splatted h-1 +#1 vector: 16bit splatted w (reuse w-1 with add?) +#1 dword: 32 bit line offset + +#coord generation data: several vectors for parameter update stuff.. + +#coordinate systems: 16 bit virtual coordinates (signed, center relative) +#* 2 vectors: virtual coordinates +#(evt tussenstap + conversie naar 16 bit virtual) + + +#step 1: generate virtual coords + + +#step 2: virtual coords -> block adresses + fractional adresses +#* mulhigh: real coords (x,y) (center relative) +#* add center -> unsigned (top left relative) +#* mullow: fractional part (x_frac, y_frac) +#* mulhigh, mullow, pack 32bit: y_offset +#* pack 32bit: x_offset +#* add, shift, add start address: real addresses + + +#step3: data fetch using generated addresses: +# this step would be much simpler in 4x16bit rgba. life's a bitch.. + +#step4: billinear interpolation + +#stat5: store + + + + # this can be simplified by doing 32 bit unaligned moves + # and vector unpacking on the data + + + + # cooked image data structure + # pixel environment temp storage + TL1 = 0x00 + TL2 = 0x02 + TL3 = 0x04 + TL4 = 0x06 + TR1 = 0x08 + TR2 = 0x0A + TR3 = 0x0C + TR4 = 0x0E + BL1 = 0x10 + BL2 = 0x12 + BL3 = 0x14 + BL4 = 0x16 + BR1 = 0x18 + BR2 = 0x1A + BR3 = 0x1C + BR4 = 0x1E + # addresses of pixel blocks + ADDRESS1 = 0x20 + ADDRESS2 = 0x24 + ADDRESS3 = 0x28 + ADDRESS4 = 0x2C + + # second env + address buffer (testing: not used) + SECONDBUFFER = 0x30 + + # 32bit splatted bitmap address + V2PLANEADDRESS = 0x60 + # 16bit splatted image constants + V4TWOWIDTHM1 = 0x68 + V4TWOHEIGHTM1 = 0x70 + V4LINEOFFSET = 0x78 + # data struct size + RESAMPLEDATASIZE = 0x80 + + + + # interpolation routine + # input: %mm0, %mm1 4 x 16bit unsigned top left relative virtual x and y coordinates + # %esi: temp & algo data structure + +getpixelsbilin: psrlw $1, %mm0 # convert to range 0->0x7fff [0,0.5[ + psrlw $1, %mm1 + movq %mm0, %mm2 + movq %mm1, %mm3 + movq V4TWOWIDTHM1(%esi), %mm4 # 2 * (width - 1) + movq V4TWOHEIGHTM1(%esi), %mm5 # 2 * (height - 1) + pmulhw %mm5, %mm3 # mm3 == y coord (topleft relative) + pmulhw %mm4, %mm2 # mm2 == x coord (topleft relative) + pmullw %mm5, %mm1 # mm1 == y frac (unsigned) + pmullw %mm4, %mm0 # mm0 == x frac (unsigned) + + movq %mm3, %mm5 # copy y coord + pmullw V4LINEOFFSET(%esi), %mm3 # low part of line offset + pmulhw V4LINEOFFSET(%esi), %mm5 # high part of line offset + + movq %mm2, %mm7 # copy x coord vector + pxor %mm4, %mm4 + punpcklwd %mm4, %mm2 # low part in %mm2 + punpckhwd %mm4, %mm7 # hight part in %mm7 + + movq %mm3, %mm6 # copy + punpcklwd %mm5, %mm3 # unpack low part in %mm3 + punpckhwd %mm5, %mm6 # high part int %mm6 + + paddd %mm2, %mm3 + paddd %mm7, %mm6 + pslld $1, %mm3 # convert to word adresses + pslld $1, %mm6 + + paddd V2PLANEADDRESS(%esi), %mm3 # add pixel plane address + paddd V2PLANEADDRESS(%esi), %mm6 + + movq %mm3, ADDRESS1(%esi) # store adresses + movq %mm6, ADDRESS3(%esi) + + pcmpeqw %mm2, %mm2 # all ones + movq %mm0, %mm4 # copy x frac + movq %mm1, %mm5 # copy y frac + pxor %mm2, %mm4 # compute compliment (approx negative) + pxor %mm2, %mm5 + + psrlw $1, %mm0 # shift right (0.5 * (frac x) + psrlw $1, %mm1 # shift right (0.5 * (frac y) + psrlw $1, %mm4 # shift right (0.5 * (1 - frac x) + psrlw $1, %mm5 # shift right (0.5 * (1 - frac y) + + movq %mm0, %mm2 # copy of frac x + movq %mm4, %mm3 # copy of (1-frac x) + # fetch data + + #jmp skipfetch # seems the fetch is the real killer. try to optimize this + # using 32 bit accesses & shifts + + # the src image data struct is padded to the cooked data struct + movl RESAMPLEDATASIZE(%esi), %edi + shll $1, %edi + + movl ADDRESS1(%esi), %ecx + movl ADDRESS2(%esi), %edx + + movw (%ecx), %ax + movw (%edx), %bx + movw %ax, TL1(%esi) + movw %bx, TL2(%esi) + movw 2(%ecx), %ax + movw 2(%edx), %bx + movw %ax, TR1(%esi) + movw %bx, TR2(%esi) + + addl %edi, %ecx + addl %edi, %edx + + movw (%ecx), %ax + movw (%edx), %bx + movw %ax, BL1(%esi) + movw %bx, BL2(%esi) + movw 2(%ecx), %ax + movw 2(%edx), %bx + movw %ax, BR1(%esi) + movw %bx, BR2(%esi) + + + movl ADDRESS3(%esi), %ecx + movl ADDRESS4(%esi), %edx + + + movw (%ecx), %ax + movw (%edx), %bx + movw %ax, TL3(%esi) + movw %bx, TL4(%esi) + movw 2(%ecx), %ax + movw 2(%edx), %bx + movw %ax, TR3(%esi) + movw %bx, TR4(%esi) + + addl %edi, %ecx + addl %edi, %edx + + movw (%ecx), %ax + movw (%edx), %bx + movw %ax, BL3(%esi) + movw %bx, BL4(%esi) + movw 2(%ecx), %ax + movw 2(%edx), %bx + movw %ax, BR3(%esi) + movw %bx, BR4(%esi) + + +skipfetch: + pmulhw TL1(%esi), %mm4 # bilin interpolation + pmulhw TR1(%esi), %mm0 + pmulhw BL1(%esi), %mm3 + pmulhw BR1(%esi), %mm2 + + + paddw %mm4, %mm0 + paddw %mm3, %mm2 + + pmulhw %mm5, %mm0 + pmulhw %mm1, %mm2 + + paddw %mm2, %mm0 + psllw $2, %mm0 # compensate for gain reduction + + ret + + + // linear mapping data struct + ROWSTATEX = 0x0 + ROWSTATEY = 0x8 + COLSTATEX = 0x10 + COLSTATEY = 0x18 + ROWINCX = 0x20 + ROWINCY = 0x28 + COLINCX = 0x30 + COLINCY = 0x38 + + // image data struct + LINEOFFSET = 0x0 + IMAGEADDRESS = 0x4 + WIDTH = 0x8 + HEIGHT = 0xC + IMAGEDATASIZE = 0x10 + + + +# pixel_resample_linmap_s16(void *x) +.globl pixel_resample_linmap_s16 +.type pixel_resample_linmap_s16,@function + + SOURCEIMAGE = RESAMPLEDATASIZE + DESTIMAGE = SOURCEIMAGE + IMAGEDATASIZE + LINMAPDATA = DESTIMAGE + IMAGEDATASIZE + +pixel_resample_linmap_s16: + pushl %ebp + movl %esp, %ebp + pushl %esi + pushl %edi + pushl %ebx + + + movl 8(%ebp), %esi # get data struct + movl DESTIMAGE+HEIGHT(%esi), %edx # image height + movl DESTIMAGE+IMAGEADDRESS(%esi), %edi # dest image address + movl DESTIMAGE+WIDTH(%esi), %ecx # image width + shrl $2, %ecx # vector count + .align 16 + +linmap_looprow: + movq LINMAPDATA+ROWSTATEX(%esi), %mm0 # get current coordinates + movq LINMAPDATA+ROWSTATEY(%esi), %mm1 + +linmap_loopcol: + movq %mm0, %mm4 # copy + movq %mm1, %mm5 + paddd LINMAPDATA+ROWINCX(%esi), %mm4 # increment + paddd LINMAPDATA+ROWINCY(%esi), %mm5 + movq %mm4, %mm6 # copy + movq %mm5, %mm7 + paddd LINMAPDATA+ROWINCX(%esi), %mm6 # increment + paddd LINMAPDATA+ROWINCY(%esi), %mm7 + movq %mm6, LINMAPDATA+ROWSTATEX(%esi) # store next state + movq %mm7, LINMAPDATA+ROWSTATEY(%esi) + + psrad $16, %mm0 # round to 16 bit + psrad $16, %mm1 + psrad $16, %mm4 + psrad $16, %mm5 + packssdw %mm4, %mm0 # pack new coordinates + packssdw %mm5, %mm1 + + push %ecx + push %edx + push %edi + + call getpixelsbilin # do interpolation + + pop %edi + pop %edx + pop %ecx + movq %mm0, (%edi) # store 4 pixels + addl $0x8, %edi # point to next 4 pixels + decl %ecx # dec row counter + jnz linmap_looprow + + movq LINMAPDATA+COLSTATEX(%esi), %mm0 # get column state vector + movq LINMAPDATA+COLSTATEY(%esi), %mm1 + movl DESTIMAGE+WIDTH(%esi), %ecx # image width + shrl $2, %ecx # vector count + paddd LINMAPDATA+COLINCX(%esi), %mm0 # increment + paddd LINMAPDATA+COLINCY(%esi), %mm1 + movq %mm0, LINMAPDATA+COLSTATEX(%esi) # store + movq %mm1, LINMAPDATA+COLSTATEY(%esi) + decl %edx # dec column counter + jnz linmap_loopcol + + emms + popl %ebx + popl %edi + popl %esi + leave + ret + + diff --git a/system/mmx/pixel_s1.s b/system/mmx/pixel_s1.s new file mode 100644 index 0000000..d6bc5ca --- /dev/null +++ b/system/mmx/pixel_s1.s @@ -0,0 +1,201 @@ +# Pure Data Packet mmx routine. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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 file contains ops for binary image processing + # 8x8 bit tile encoded + # low byte = bottom row + # low bit = right column + # %mm7 = scratch reg for all macros + + + # ************ load mask ******************* + # compute bit masks for rows and columns + # %mm7: scratch reg + + # load mask top + .macro ldmt count reg + pcmpeqb \reg, \reg + psllq $(64-(\count<<3)), \reg + .endm + + # load mask bottom + .macro ldmb count reg + pcmpeqb \reg, \reg + psrlq $(64-(\count<<3)), \reg + .endm + + # load mask top and bottom + .macro ldmtb count regt regb + ldmb \count, \regb + ldmt \count, \regt + .endm + + # load mask right + .macro ldmr count reg + pcmpeqb %mm7, %mm7 + psrlw $(16-\count), %mm7 + movq %mm7, \reg + psllq $8, %mm7 + por %mm7, \reg + .endm + + # load mask left + .macro ldml count reg + pcmpeqb %mm7, %mm7 + psllw $(16-\count), %mm7 + movq %mm7, \reg + psrlq $8, %mm7 + por %mm7, \reg + .endm + + # load mask left and right + .macro ldmlr count regl regr + pcmpeqb %mm7, %mm7 + psllw $(16-\count), %mm7 + movq %mm7, \regl + psrlq $8, %mm7 + por %mm7, \regl + movq \regl, \regr + psrlq $(8-\count), \regr + .endm + + # ************* shift square ********** + # shifts a square in reg, fills with zeros + + # shift square top + .macro sst count reg + psllq $(\count<<3), \reg + .endm + + # shift square bottom + .macro ssb count reg + psrlq $(\count<<3), \reg + .endm + + # not tested + # shift square left + .macro ssl count reg + movq \reg, %mm7 + pcmpeqb \reg, \reg + psllw $(16-\count), \reg + psrlw $8, \reg + pandn %mm7, \reg + psllw $(\count), \reg + .endm + + # shift square right + .macro ssr count reg + movq \reg, %mm7 + pcmpeqb \reg, \reg + psrlw $(16-\count), \reg + psllw $8, \reg + pandn %mm7, \reg + psrlw $(\count), \reg + .endm + + + # ********** combine square ************* + # combines 2 squares + + # combine right + .macro csr count regr reg + ssl \count, \reg + ssr (8-\count), \regr + por \regr, \reg + .endm + + # combine left + .macro csl count regl reg + ssr \count, \reg + ssl (8-\count), \regl + por \regl, \reg + .endm + + # combine top + .macro cst count regt reg + ssb \count, \reg + sst (8-\count), \regt + por \regt, \reg + .endm + + + # combine bottom + .macro csb count regb reg + sst \count, \reg + ssb (8-\count), \regb + por \regb, \reg + .endm + + + # ********** load combine square ************* + # loads combined square using mask + + # load combined square left + # mask should be count bits set right (i.e. 0x01) + .macro lcsml count mask source sourcel dstreg + movq \mask, \dstreg + movq \mask, %mm7 + pandn \source, \dstreg + pand \sourcel, %mm7 + psrlq $(\count), \dstreg + psllq $(8-\count), %mm7 + por %mm7, \dstreg + .endm + + + +.globl pixel_test_s1 +.type pixel_test_s1,@function + +# simple add +# void pixel_add_s16(void *dest, void *source, int nb_squares, int spacing) + + + + # + + +pixel_test_s1: + pushl %ebp + movl %esp, %ebp + push %esi + push %edi + + movl 8(%ebp), %edi # dest + movl 12(%ebp), %esi # source + movl 16(%ebp), %ecx # count + movl 20(%ebp), %edx # row distance + + ldmr 1, %mm6 + lcsml 1, %mm6, (%esi), 8(%esi), %mm0 + movq %mm0, (%edi) + + +# movq (%esi), %mm0 +# movq 8(%esi), %mm1 +# csl 4, %mm1, %mm0 +# movq %mm0, (%edi) + + emms + + + pop %edi + pop %esi + leave + ret + diff --git a/system/mmx/pixel_unpack_u8s16.s b/system/mmx/pixel_unpack_u8s16.s new file mode 100644 index 0000000..0fc14c2 --- /dev/null +++ b/system/mmx/pixel_unpack_u8s16.s @@ -0,0 +1,113 @@ +# Pure Data Packet mmx routine. +# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> +# +# 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. +# +.globl pixel_unpack_u8s16_y +.type pixel_unpack_u8s16_y,@function + +# mmx rgba pixel gain +# void pixel_unpack_u8s16_y(char *input, char *output, int32 nb_pixels_div8) + +pixel_unpack_u8s16_y: + pushl %ebp + movl %esp, %ebp + push %esi + push %edi + +# movl 20(%ebp), %edi # int16[4] array of gains +# movq (%edi), %mm7 # get gain array + + movl 8(%ebp), %esi # input uint8 pixel array + movl 12(%ebp), %edi # output sint16 pixel array + movl 16(%ebp), %ecx # nb of elements div 8 + + + .align 16 + .loop_unpack_y: + + movq (%esi), %mm5 # load 8 pixels from memory + pxor %mm0, %mm0 # zero mm0 - mm3 + pxor %mm1, %mm1 + punpcklbw %mm5, %mm0 # unpack 1st 4 pixels + punpckhbw %mm5, %mm1 # unpack 2nd 4 pixles + psrlw $0x1, %mm0 # shift right to clear sign bit 9.7 + psrlw $0x1, %mm1 +# pmulhw %mm7, %mm0 # apply gain +# pmulhw %mm7, %mm1 +# paddsw %mm0, %mm0 # correct factor 2 +# paddsw %mm1, %mm1 + movq %mm0, (%edi) # store + movq %mm1, 8(%edi) + + addl $8, %esi # increment source pointer + addl $16, %edi # increment dest pointer + decl %ecx + jnz .loop_unpack_y # loop + + emms + + pop %edi + pop %esi + leave + ret + +.globl pixel_unpack_u8s16_uv +.type pixel_unpack_u8s16_uv,@function +pixel_unpack_u8s16_uv: + pushl %ebp + movl %esp, %ebp + push %esi + push %edi + +# movl 20(%ebp), %edi # int16[4] array of gains +# movq (%edi), %mm7 # get gain array + + movl 8(%ebp), %esi # input uint8 pixel array + movl 12(%ebp), %edi # output sint16 pixel array + movl 16(%ebp), %ecx # nb of elements div 8 + + pcmpeqw %mm6, %mm6 + psllw $15, %mm6 + + .align 16 + .loop_unpack_uv: + + movq (%esi), %mm5 # load 8 pixels from memory + pxor %mm0, %mm0 # zero mm0 - mm3 + pxor %mm1, %mm1 + punpcklbw %mm5, %mm0 # unpack 1st 4 pixels + punpckhbw %mm5, %mm1 # unpack 2nd 4 pixles + pxor %mm6, %mm0 # flip sign bit (Cr and Cb are ofset by 128) + pxor %mm6, %mm1 +# pmulhw %mm7, %mm0 # apply gain +# pmulhw %mm7, %mm1 +# paddsw %mm0, %mm0 # correct factor 2 +# paddsw %mm1, %mm1 + movq %mm0, (%edi) # store + movq %mm1, 8(%edi) + + addl $8, %esi # increment source pointer + addl $16, %edi # increment dest pointer + decl %ecx + jnz .loop_unpack_uv # loop + + emms + + pop %edi + pop %esi + leave + ret + diff --git a/system/net/Makefile b/system/net/Makefile new file mode 100644 index 0000000..53d1d61 --- /dev/null +++ b/system/net/Makefile @@ -0,0 +1,11 @@ + +OBJECTS = pdp_net.o + + +include ../../Makefile.config + +all: $(OBJECTS) + +clean: + rm -f *~ + rm -f *.o diff --git a/system/net/pdp_net.c b/system/net/pdp_net.c new file mode 100644 index 0000000..04c97d6 --- /dev/null +++ b/system/net/pdp_net.c @@ -0,0 +1,685 @@ + +#include "pdp_net.h" +#include "pdp_debug.h" +#include "pdp_post.h" +#include "pdp_mem.h" + +#define D if (0) // DEBUG MSG +#define DD if (0) // DROP DEBUG MSG + +/* shared internals */ + +static int _is_udp_header(t_pdp_udp_header *header, unsigned int size) +{ + if (size < sizeof(t_pdp_udp_header)) return 0; + if (strcmp(header->signature, "PDP")) return 0; + if (PDP_UDP_VERSION != header->version) return 0; + return 1; +} + +static void _make_udp_header(t_pdp_udp_header *header) +{ + strcpy(header->signature, "PDP"); + header->version = PDP_UDP_VERSION; +} + + + + +/* R E C E I V E R */ + + +/* INTERNALS */ + +static void _send_packet(t_pdp_udp_receiver *x) +{ + _make_udp_header(&x->x_resend_header); + PDP_ASSERT(x->x_resend_udp_packet_size <= sizeof(t_pdp_udp_header) + sizeof(x->x_resend_chunks)); + + /* send the packet */ + if (-1 == sendto (x->x_socket, &x->x_resend_header, x->x_resend_udp_packet_size, 0, + (struct sockaddr *)&x->x_source_socket, x->x_sslen)){ + pdp_post("pdp_netreceive: send failed"); + } +} + +static void _send_ack_new(t_pdp_udp_receiver *x) +{ + /* setup resend header */ + x->x_resend_header.connection_id = x->x_connection_id; + x->x_resend_header.sequence_number = PDP_UDP_ACKNEW; + x->x_resend_udp_packet_size = sizeof(t_pdp_udp_header); + + _send_packet(x); + +} + + +static int _handle_PDP_UDP_NEW(t_pdp_udp_receiver *x) +{ + /* we've got a PDP_UDP_NEW packet, so prepare to receive the data */ + t_pdp_udp_newpacket *np = (t_pdp_udp_newpacket *)x->x_buf; + + + //pdp_post("conn_id = %x", x->x_header.connection_id); + //pdp_post("size = %d", np->data_size); + //pdp_post("nb_chunks = %d", np->nb_chunks); + //pdp_post("chunk_size = %d", np->chunk_size); + //pdp_post("type = %s", np->type); + + /* check if it is a resend of the PDP_UDP_NEW packet (if NEW_ACK didn't get through) + if not, prepare for reception */ + + if (x->x_connection_id != x->x_header.connection_id){ + + + /* prepare for reception : TODO add some more checks here */ + + // setup type info + if (x->x_data_type) pdp_dealloc (x->x_data_type); + x->x_data_type = pdp_alloc(1 + strlen(np->type)); + strcpy(x->x_data_type, np->type); + + // setup data buffer + x->x_data_size = np->data_size; + if (x->x_data) pdp_dealloc (x->x_data); + x->x_data = pdp_alloc(x->x_data_size); + memset(x->x_data, 0, x->x_data_size); // clear for debug + + // setup connection info + x->x_connection_id = x->x_header.connection_id; + x->x_nb_chunks = np->nb_chunks; + x->x_chunk_size = np->chunk_size; + + /* setup chunk list */ + if (x->x_chunk_list) pdp_dealloc(x->x_chunk_list); + x->x_chunk_list = pdp_alloc(sizeof(unsigned int)*x->x_nb_chunks); + memset(x->x_chunk_list, 0, sizeof(unsigned int)*x->x_nb_chunks); + + x->x_receive_finished = 0; // we're in a receiving state + x->x_packet_transferred = 0; // we didn't pass the packet yet + } + + /* send ACK */ + _send_ack_new(x); + + + + return 1; +} + +static void _handle_PDP_UDP_DONE(t_pdp_udp_receiver *x) +{ + unsigned int chunk; + unsigned int missing; + unsigned int i; + unsigned int resend_packet_size; + + + /* check the connection id */ + if (x->x_connection_id != x->x_header.connection_id) return; + + /* determine how many packets are missing */ + missing = 0; + for (i=0; i<x->x_nb_chunks; i++) + if (!x->x_chunk_list[i]) missing++; + + D pdp_post ("last packet %x had %d/%d dropped chunks", x->x_connection_id, missing, x->x_nb_chunks); + + + /* build the resend request (chunk list )*/ + if (missing > RESEND_MAX_CHUNKS) missing = RESEND_MAX_CHUNKS; + chunk = 0; + i = missing; + while(i--){ + while (x->x_chunk_list[chunk]) chunk++; // find next missing chunk + x->x_resend_chunks[i] = chunk++; // store it in list + } + + /* set the packet size to include the list */ + x->x_resend_udp_packet_size = sizeof(t_pdp_udp_header) + + missing * sizeof(unsigned int); + + /* setup resend header */ + strcpy((char *)&x->x_resend_header, "PDP"); + x->x_resend_header.version = PDP_UDP_VERSION; + x->x_resend_header.connection_id = x->x_connection_id; + x->x_resend_header.sequence_number = PDP_UDP_RESEND; + + D pdp_post("pdp_netreceive: sending RESEND response for %u chunks", missing); + + /* send out */ + _send_packet(x); + + /* indicate we're done if there's no chunks missing */ + if (!missing) x->x_receive_finished = 1; + +} + + +static int _handle_UDP_DATA(t_pdp_udp_receiver *x) +{ + unsigned int seq = x->x_header.sequence_number; + unsigned int offset = x->x_chunk_size * seq; + + /* ignore the packet if we're not expecting it */ + if ((!x->x_connection_id) || (x->x_connection_id != x->x_header.connection_id)){ + //pdp_post("pdp_netreceive: got invalid data packet: transmission id %x is not part of current transmisson %x", + // x->x_header.connection_id, x->x_connection_id); + return 0; + } + + /* check if it is valid */ + if (seq >= x->x_nb_chunks){ + pdp_post("pdp_netreceive: got invalid data packet: sequence number %u out of bound (nb_chunks=%u)", + seq, x->x_nb_chunks); + return 0; + } + + /* final check */ + PDP_ASSERT(offset + x->x_buf_size <= x->x_data_size); + + /* write & log it */ + memcpy(x->x_data + offset, x->x_buf, x->x_buf_size); + x->x_chunk_list[seq] = 1; + return 1; + +} + +/* INTERFACE */ + +/* setup */ +t_pdp_udp_receiver *pdp_udp_receiver_new(int port) +{ + t_pdp_udp_receiver *x = pdp_alloc(sizeof(*x)); + memset(x, 0, sizeof(*x)); + + /* init */ + x->x_data = 0; + x->x_data_type = 0; + x->x_data_size = 0; + x->x_chunk_list = 0; + x->x_receive_finished = 0; + x->x_packet_transferred = 0; + x->x_zero_terminator = 0; + + x->x_socket = socket(PF_INET, SOCK_DGRAM, 0); + x->x_connection_id = 0; /* zero for bootstrap (0 == an invalid id) */ + x->x_sslen = sizeof(struct sockaddr_in); + + /* bind socket */ + x->x_sa.sin_port = htons(port); + x->x_sa.sin_addr.s_addr = 0; + if (-1 != bind (x->x_socket, (struct sockaddr *)&x->x_sa, + sizeof(struct sockaddr_in))) return x; + + /* suicide if find failed */ + else { + pdp_dealloc(x); + return 0; + } +} +void pdp_udp_receiver_free(t_pdp_udp_receiver *x) +{ + if (!x) return; + if (x->x_socket != 1) close (x->x_socket); + if (x->x_data) pdp_dealloc(x->x_data); + if (x->x_data_type) pdp_dealloc (x->x_data_type); + if (x->x_chunk_list) pdp_dealloc (x->x_chunk_list); +} + +void pdp_udp_receiver_reset(t_pdp_udp_receiver *x) +{ + x->x_connection_id = 0; +} + + +/* receive loop, returns 1 on success, -1 on error, 0 on timeout */ +int pdp_udp_receiver_receive(t_pdp_udp_receiver *x, unsigned int timeout_ms) +{ + /* listen for packets */ + + unsigned int size; + struct timeval tv = {0,1000 * timeout_ms}; + fd_set inset; + FD_ZERO(&inset); + FD_SET(x->x_socket, &inset); + switch(select (x->x_socket+1, &inset, NULL, NULL, &tv)){ + case -1: + return -1; /* select error */ + case 0: + return 0; /* select time out */ + default: + break; /* data ready */ + } + + /* this won't block, since there's data available */ + if (-1 == (int)(size = recvfrom(x->x_socket, (void *)&x->x_header, + PDP_UDP_BUFSIZE+sizeof(x->x_header), 0, + (struct sockaddr *)&x->x_source_socket, &x->x_sslen))) return -1; + + /* store the data size of the packet */ + x->x_buf_size = size - sizeof(t_pdp_udp_header); + + /* parse the udp packet */ + if (_is_udp_header(&x->x_header, size)){ + + /* it is a control packet */ + if ((int)x->x_header.sequence_number < 0){ + + switch (x->x_header.sequence_number){ + case PDP_UDP_NEW: + _handle_PDP_UDP_NEW(x); + break; + + case PDP_UDP_DONE: + _handle_PDP_UDP_DONE(x); + + /* check if we got a complete packet + and signal arrival if we haven't done this already */ + if (x->x_receive_finished && !x->x_packet_transferred){ + x->x_packet_transferred = 1; + return 1; // data complete, please receive + } + break; + + default: + pdp_post("got unknown msg"); + break; + } + } + + /* it is a data packet */ + else { + _handle_UDP_DATA(x); + } + + + } + + else { + pdp_post("pdp_netreceive: got invalid UDP packet (size = %d)", size); + } + + return 0; //no major event, please poll again + +} + +/* get meta & data */ +char *pdp_udp_receiver_type(t_pdp_udp_receiver *x){return x->x_data_type;} +unsigned int pdp_udp_receiver_size(t_pdp_udp_receiver *x){return x->x_data_size;} +void *pdp_udp_receiver_data(t_pdp_udp_receiver *x){return x->x_data;} + + +/* S E N D E R */ + +/* INTERNALS */ + +static void _sleep(t_pdp_udp_sender *x) +{ + int sleep_period = x->x_sleep_period; + + if (sleep_period) { + if (!x->x_sleep_count++) usleep(x->x_sleepgrain_us); + x->x_sleep_count %= sleep_period; + } +} + +static void _send(t_pdp_udp_sender *x) +{ + //post("sending %u data bytes", x->x_buf_size); + + _make_udp_header(&x->x_header); + + PDP_ASSERT (x->x_buf_size <= PDP_UDP_BUFSIZE); + + if (-1 == sendto (x->x_socket, &x->x_header, x->x_buf_size + sizeof(t_pdp_udp_header), + 0, (struct sockaddr *)&x->x_sa, sizeof(struct sockaddr_in))) + pdp_post("pdp_netsend: send FAILED"); + + _sleep(x); + +} + + +static void _prepare_for_new_transmission(t_pdp_udp_sender *x, char *type, unsigned int size, void *data) +{ + unsigned int i; + + /* setup data for transmission */ + x->x_data_type = type; + x->x_data_size = size; + x->x_data = data; + x->x_chunk_size = x->x_udp_payload_size; + x->x_nb_chunks = (x->x_data_size - 1) / x->x_chunk_size + 1; + + /* generate a connection id (non-zero) */ + while (!(x->x_connection_id = rand())); + + /* setup chunk list to contain all chunks */ + if (x->x_chunk_list) free (x->x_chunk_list); + x->x_chunk_list_size = x->x_nb_chunks; + x->x_chunk_list = malloc(sizeof(unsigned int)*x->x_chunk_list_size); + for (i=0; i<x->x_chunk_list_size; i++) x->x_chunk_list[i] = i; + +} + +static void _send_header_packet(t_pdp_udp_sender *x) +{ + t_pdp_udp_newpacket *np = (t_pdp_udp_newpacket *)x->x_buf; /* buf contains the PDP_UDP_NEW body */ + + /* init packet */ + x->x_header.sequence_number = PDP_UDP_NEW; + x->x_header.connection_id = x->x_connection_id; + np->data_size = x->x_data_size; + np->nb_chunks = x->x_nb_chunks; + np->chunk_size = x->x_chunk_size; + strcpy(np->type, x->x_data_type); + x->x_buf_size = sizeof(*np) + strlen(np->type) + 1; + PDP_ASSERT(x->x_buf_size <= PDP_UDP_BUFSIZE); + + /* send the packet */ + _send(x); +} + +/* saend the chunks in the chunk list */ +static void _send_chunks(t_pdp_udp_sender *x){ + unsigned int i; + unsigned int count = 0; + + /* send chunks: this requires header is setup ok (sig,ver,connid)*/ + for (i=0; i<x->x_chunk_list_size; i++){ + unsigned int offset; + unsigned int current_chunk_size; + unsigned int seq = x->x_chunk_list[i]; + + PDP_ASSERT(seq < x->x_nb_chunks); + x->x_header.sequence_number = seq; // store chunk number + + /* get current chunk offset */ + offset = seq * x->x_chunk_size; + PDP_ASSERT(offset < x->x_data_size); + + + /* get current chunk size */ + current_chunk_size = (offset + x->x_chunk_size > x->x_data_size) ? + (x->x_data_size - offset) : x->x_chunk_size; + x->x_buf_size = current_chunk_size; + PDP_ASSERT(x->x_buf_size <= PDP_UDP_BUFSIZE); + + /* copy chunk to transmission buffer & send */ + PDP_ASSERT(offset + current_chunk_size <= x->x_data_size); + memcpy(x->x_buf, x->x_data + offset, current_chunk_size); + + + /* send the chunk */ + _send(x); + count++; + + } + D pdp_post("sent %d chunks, id=%x", count,x->x_connection_id); +} + +/* send a DONE packet */ +static void _send_done(t_pdp_udp_sender *x){ + x->x_header.sequence_number = PDP_UDP_DONE; + x->x_buf_size = 0; + _send(x); +} +static int _receive_packet(t_pdp_udp_sender *x, int desired_type) +/* 0 == timeout, -1 == error, 1 == got packet */ +{ + unsigned int size; + int type; + + struct timeval tv; + fd_set inset; + int sr; + + + while (1){ + int retval; + + /* wait for incoming */ + tv.tv_sec = 0; + tv.tv_usec = x->x_timeout_us; + FD_ZERO(&inset); + FD_SET(x->x_socket, &inset); + switch (select (x->x_socket+1, &inset, NULL, NULL, &tv)){ + case -1: + return -1; /* select error */ + case 0: + return 0; /* select time out */ + default: + break; /* data ready */ + } + + /* read packet */ + if (-1 == (int)(size = recv(x->x_socket, (void *)&x->x_resend_header, MAX_UDP_PACKET, 0))){ + pdp_post("pdp_netsend: error while reading from socket"); + return -1; + } + + /* check if it is a valid PDP_UDP packet */ + if (!_is_udp_header(&x->x_resend_header, size)){ + pdp_post("pdp_netsend: ignoring invalid UDP packet (size = %u)", size); + continue; + } + + + /* check connection id */ + if (x->x_connection_id != x->x_resend_header.connection_id){ + D pdp_post("pdp_netsend: ignoring ghost packet id=%x, current id=%x", + x->x_resend_header.connection_id, x->x_connection_id); + continue; + } + + /* check type */ + type = x->x_resend_header.sequence_number; + if (type != desired_type) continue; + + + /* setup data buffer for known packets */ + switch(type){ + case PDP_UDP_RESEND: + x->x_resend_items = (size - sizeof(t_pdp_udp_header)) / sizeof(unsigned int); + break; + default: + break; + } + + return 1; + } + +} + +/* get the resend list */ +static int _need_resend(t_pdp_udp_sender *x) { + + int retries = 3; + int retval; + while (retries--){ + + /* send a DONE msg */ + _send_done(x); + + /* wait for ACK */ + switch(_receive_packet(x, PDP_UDP_RESEND)){ + case 0: + /* timeout, retry */ + continue; + case -1: + /* error */ + goto move_on; + + default: + /* got PDP_UDP_RESEND packet: setup resend list */ + if (x->x_resend_items > x->x_nb_chunks){ + pdp_post("pdp_netsend: WARNING: chunk list size (%d) is too big, ignoring RESEND request", + x->x_resend_items); + x->x_resend_items = 0; + continue; + } + x->x_chunk_list_size = x->x_resend_items; + + memcpy(x->x_chunk_list, x->x_resend_chunks, sizeof(unsigned int) * x->x_resend_items); + D pdp_post("got RESEND request for %d chunks (id %x)", x->x_resend_items,x->x_connection_id); + + return x->x_chunk_list_size > 0; + } + + } + + /* timeout */ + move_on: + x->x_chunk_list_size = 0; + return 0; + + +} + + +/* INTERFACE */ + + +/* some flow control hacks */ + +void pdp_udp_sender_timeout_us(t_pdp_udp_sender *x, unsigned int timeout_us) +{ + x->x_timeout_us = timeout_us; +} + + +void pdp_udp_sender_sleepgrain_us(t_pdp_udp_sender *x, unsigned int sleepgrain_us) +{ + x->x_sleepgrain_us = sleepgrain_us; +} + +void pdp_udp_sender_sleepperiod(t_pdp_udp_sender *x, unsigned int sleepperiod) +{ + x->x_sleep_period = sleepperiod; +} + + +void pdp_udp_sender_udp_packet_size(t_pdp_udp_sender *x, unsigned int udp_packet_size) +{ + int i = (int)udp_packet_size - sizeof(t_pdp_udp_header); + if (i < 1024) i = 1024; + if (i > PDP_UDP_BUFSIZE) i = PDP_UDP_BUFSIZE; + x->x_udp_payload_size = i; +} + +void pdp_udp_sender_connect(t_pdp_udp_sender *x, char *host, unsigned int port) +{ + struct hostent *hp; + + hp = gethostbyname(host); + if (!hp){ + pdp_post("pdp_udp_sender: host %s not found", host); + } + else{ + /* host ok, setup address */ + x->x_sa.sin_family = AF_INET; + x->x_sa.sin_port = htons(port); + memcpy((char *)&x->x_sa.sin_addr, (char *)hp->h_addr, hp->h_length); + + /* create the a socket if necessary */ + if (x->x_socket == -1){ + if (-1 == (x->x_socket = socket(PF_INET, SOCK_DGRAM, 0))){ + pdp_post("pdp_udp_sender: can't create socket"); + } + if (1){ + int on = 1; + if (setsockopt(x->x_socket,SOL_SOCKET,SO_BROADCAST,(char *)&on,sizeof(on))<0) + pdp_post("pdp_udp_sender: can't set broadcast flag"); + } + } + } +} + +/* setup */ +t_pdp_udp_sender *pdp_udp_sender_new(void) +{ + t_pdp_udp_sender *x = pdp_alloc(sizeof(*x)); + memset(x,0,sizeof(*x)); + + x->x_chunk_list = 0; + + /* no connection */ + x->x_socket = -1; + + + /* set flow control */ + pdp_udp_sender_timeout_us(x, 50000); + x->x_sleep_count = 0; + pdp_udp_sender_sleepgrain_us(x, 0); + pdp_udp_sender_sleepperiod(x, 50); + pdp_udp_sender_udp_packet_size(x, 1472); //optimal udp packet size (ip: 1500 = 28 + 1472) + + + return x; +} + +void pdp_udp_sender_free(t_pdp_udp_sender *x) +{ + int i; + void* retval; + if (x->x_socket != -1) close(x->x_socket); + if (x->x_chunk_list) free (x->x_chunk_list); +} + +/* send, returns 1 on success, 0 on error */ +int pdp_udp_sender_send(t_pdp_udp_sender *x, char* type, unsigned int size, void *data) +{ + + /* SEND A PACKET */ + + /* get the type and data from caller */ + /* send header packet and make sure it has arrived */ + /* send a chunk burst */ + /* send done packet and get the resend list */ + /* repeat until send list is empty */ + + + int hs_retry = 5; // retry count for initial handshake + int rs_retry = 5; // retry count for resends + + /* check if we have a target */ + if (-1 == x->x_socket) goto transerror; + + /* setup internal state */ + _prepare_for_new_transmission(x,type,size,data); + + /* handshake a new transmission */ + do { + if (!(hs_retry--)) break; + // pdp_post("handshake retry %d for packet %x", hscount, x->x_connection_id); + _send_header_packet(x); + } while (!_receive_packet(x, PDP_UDP_ACKNEW)); + + + /* exit if no handshake was possible */ + if (hs_retry < 0){ + DD pdp_post("pdp_netsend: DROP: receiver does not accept new transmission"); + goto transerror; + } + + /* transmission loop */ + do { + if (!(rs_retry--)) break; + _send_chunks(x); + } while (_need_resend(x)); + + /* exit if transmission was not successful */ + if (rs_retry < 0){ + DD pdp_post("pdp_netsend: DROP: receiver did not confirm reception"); + goto transerror; + } + + /* send successful */ + return 1; + + transerror: + /* transmission error */ + return 0; +} diff --git a/system/pdp.c b/system/pdp.c new file mode 100644 index 0000000..d74323b --- /dev/null +++ b/system/pdp.c @@ -0,0 +1,230 @@ +/* + * Pure Data Packet system implementation: setup code + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +#include <stdio.h> +#include "pdp_config.h" +#include "pdp_post.h" + + +/* all symbols are C style */ +#ifdef __cplusplus +extern "C" +{ +#endif + +/* module setup declarations (all C-style) */ + +/* pdp system / internal stuff */ +void pdp_debug_setup(void); +void pdp_list_setup(void); +void pdp_pdsym_setup(void); +void pdp_forth_setup(void); +void pdp_forth_def_setup(void); +void pdp_symbol_setup(void); +void pdp_type_setup(void); +void pdp_packet_setup(void); +void pdp_ut_setup(void); +void pdp_queue_setup(void); +void pdp_control_setup(void); +void pdp_image_setup(void); +void pdp_bitmap_setup(void); +void pdp_matrix_setup(void); + +/* pdp modules */ +void pdp_xv_setup(void); +void pdp_add_setup(void); +void pdp_mul_setup(void); +void pdp_mix_setup(void); +void pdp_randmix_setup(void); +void pdp_qt_setup(void); +void pdp_v4l_setup(void); +void pdp_reg_setup(void); +void pdp_conv_setup(void); +void pdp_bq_setup(void); +void pdp_del_setup(void); +void pdp_snap_setup(void); +void pdp_trigger_setup(void); +void pdp_route_setup(void); +void pdp_noise_setup(void); +void pdp_gain_setup(void); +void pdp_chrot_setup(void); +void pdp_scope_setup(void); +void pdp_scale_setup(void); +void pdp_zoom_setup(void); +void pdp_scan_setup(void); +void pdp_scanxy_setup(void); +void pdp_sdl_setup(void); +void pdp_cheby_setup(void); +void pdp_grey2mask_setup(void); +void pdp_constant_setup(void); +void pdp_logic_setup(void); +void pdp_glx_setup(void); +void pdp_loop_setup(void); +void pdp_description_setup(void); +void pdp_convert_setup(void); +void pdp_stateless_setup(void); +void pdp_mat_mul_setup(void); +void pdp_mat_lu_setup(void); +void pdp_mat_vec_setup(void); +void pdp_plasma_setup(void); +void pdp_cog_setup(void); +void pdp_histo_setup(void); +void pdp_array_setup(void); +void pdp_udp_send_setup(void); +void pdp_udp_receive_setup(void); +void pdp_rawin_setup(void); +void pdp_rawout_setup(void); + + +/* hacks */ +void pdp_inspect_setup(void); + +/* testing */ +void pdp_dpd_test_setup(void); + + + + +/* library setup routine */ +void pdp_setup(void){ + + /* babble */ + pdp_post ("PDP: pure data packet"); + +#ifdef PDP_VERSION + pdp_post("PDP: version " PDP_VERSION ); +#endif + + + /* setup pdp system */ + + /* kernel */ + pdp_pdsym_setup(); + pdp_debug_setup(); + pdp_symbol_setup(); + pdp_list_setup(); + pdp_type_setup(); + pdp_packet_setup(); + pdp_control_setup(); + + /* types */ + pdp_image_setup(); + pdp_bitmap_setup(); + + + +#ifdef HAVE_PDP_GSL + pdp_matrix_setup(); +#endif + + pdp_queue_setup(); + + /* setup utility toolkit */ + pdp_ut_setup(); + + /* setup pdp pd modules*/ + pdp_add_setup(); + pdp_mul_setup(); + pdp_mix_setup(); + pdp_randmix_setup(); + pdp_reg_setup(); + pdp_conv_setup(); + pdp_bq_setup(); + pdp_del_setup(); + pdp_snap_setup(); + pdp_trigger_setup(); + pdp_route_setup(); + pdp_noise_setup(); + pdp_plasma_setup(); + pdp_gain_setup(); + pdp_chrot_setup(); + pdp_scope_setup(); + pdp_scale_setup(); + pdp_zoom_setup(); + pdp_scan_setup(); + pdp_scanxy_setup(); + + + pdp_grey2mask_setup(); + pdp_constant_setup(); + pdp_logic_setup(); + pdp_loop_setup(); + pdp_description_setup(); + pdp_convert_setup(); + pdp_stateless_setup(); + + + pdp_cog_setup(); + pdp_array_setup(); + pdp_rawin_setup(); + pdp_rawout_setup(); + + + /* experimental stuff */ + pdp_inspect_setup(); + pdp_udp_send_setup(); + pdp_udp_receive_setup(); + + /* testing */ + //pdp_dpd_test_setup(); + + /* optional stuff */ + +#ifdef HAVE_PDP_READLINE + pdp_forthconsole_setup(); +#endif + +#ifdef HAVE_PDP_GSL + pdp_histo_setup(); + pdp_cheby_setup(); + pdp_mat_mul_setup(); + pdp_mat_lu_setup(); + pdp_mat_vec_setup(); +#endif + + +#ifdef HAVE_PDP_QT + pdp_qt_setup(); +#endif + +#ifdef HAVE_PDP_XV + pdp_xv_setup(); +#endif + +#ifdef HAVE_PDP_SDL + pdp_sdl_setup(); +#endif + +#ifdef HAVE_PDP_V4L + pdp_v4l_setup(); +#endif + +#ifdef HAVE_PDP_GLX + pdp_glx_setup(); +#endif + + + + +} + +#ifdef __cplusplus +} +#endif diff --git a/system/png/Makefile b/system/png/Makefile new file mode 100644 index 0000000..9122da6 --- /dev/null +++ b/system/png/Makefile @@ -0,0 +1,11 @@ + +OBJECTS = pdp_png.o + + +include ../../Makefile.config + +all: $(OBJECTS) + +clean: + rm -f *~ + rm -f *.o diff --git a/system/png/pdp_png.c b/system/png/pdp_png.c new file mode 100644 index 0000000..f751912 --- /dev/null +++ b/system/png/pdp_png.c @@ -0,0 +1,409 @@ + +/* + * Pure Data Packet system module. - png glue code + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + +#include "pdp_packet.h" +#include "pdp_mem.h" +#include "pdp_post.h" +#include "pdp_debug.h" + +// this is an optional module +#include "pdp_config.h" + + +#ifdef HAVE_PDP_PNG +//if 0 + +#include <png.h> + +#define READING 1 +#define WRITING 2 +#define SIG_BYTES 8 + +#define D if(0) + +typedef struct +{ + FILE *x_fp; + + int x_kindof; //READING or WRITING + png_structp x_png; + png_infop x_info; + png_infop x_end_info; + + png_uint_32 x_width; + png_uint_32 x_height; + int x_bit_depth; + int x_color_type; + int x_interlace_type; + int x_compression_type; + int x_filter_type; + + int x_pdp_bitmap_type; + int x_packet; + +} t_png_image; + +static t_png_image *_init(t_png_image *x) +{ + x->x_png = 0; + x->x_info = 0; + x->x_end_info = 0; + x->x_fp = 0; + x->x_packet = -1; + return x; +} + +static int _cleanup(t_png_image *x) +{ +#define INTERNAL_ERROR 1 + if (!x) return 1; + pdp_packet_mark_unused(x->x_packet); + if (x->x_png) + switch(x->x_kindof){ + case READING: png_destroy_read_struct(&x->x_png, &x->x_info, &x->x_end_info); break; + case WRITING: png_destroy_write_struct(&x->x_png, &x->x_info); break; + default: PDP_ASSERT(INTERNAL_ERROR); + } + if (x->x_fp) fclose(x->x_fp); + return 1; +} + +static int _open_read(t_png_image* x, char *file) +{ + char header[SIG_BYTES]; + int is_png; + + x->x_fp = fopen(file, "r"); + if (!x->x_fp) { + D pdp_post("can't open %s for reading", file); + return 0; + } + fread(header, 1, SIG_BYTES, x->x_fp); + is_png = !png_sig_cmp(header, 0, SIG_BYTES); + + D pdp_post("%s is %s png file", file, is_png ? "a" : "not a"); + + return is_png; +} + +static int _open_write(t_png_image* x, char *file) +{ + char header[SIG_BYTES]; + int is_png; + + x->x_fp = fopen(file, "w"); + if (!x->x_fp) { + D pdp_post("can't open %s for writing", file); + return 0; + } + + return 1; +} + +/* progress callback */ + +static void _row_callback(png_structp p, png_uint_32 row, int pass) +{ + fprintf(stderr, "."); +} + +static int _initio_read(t_png_image *x) +{ + png_init_io(x->x_png, x->x_fp); + png_set_sig_bytes(x->x_png, SIG_BYTES); + D png_set_read_status_fn(x->x_png, _row_callback); + return 1; + +} + +static int _initio_write(t_png_image *x) +{ + png_init_io(x->x_png, x->x_fp); + D png_set_write_status_fn(x->x_png, _row_callback); + + return 1; + +} + +static int _checkimagetype(t_png_image *x) +{ + png_read_info(x->x_png, x->x_info); + png_get_IHDR(x->x_png, x->x_info, &x->x_width, &x->x_height, + &x->x_bit_depth, &x->x_color_type, &x->x_interlace_type, + &x->x_compression_type, &x->x_filter_type); + + D pdp_post("image info: w=%d, h=%d, depth=%d, type=%d", + (int)x->x_width, (int)x->x_height, (int)x->x_bit_depth, + (int)x->x_color_type); + + + /* handle paletted images: convert to 8 bit RGB(A) */ + if (x->x_color_type == PNG_COLOR_TYPE_PALETTE && + x->x_bit_depth <= 8) { + png_set_expand(x->x_png); + D pdp_post("convert palette"); + + /* check if there's an alpha channel and set PDP_BITMAP type */ + x->x_pdp_bitmap_type = + (png_get_valid(x->x_png, x->x_info, PNG_INFO_tRNS)) ? + PDP_BITMAP_RGBA : PDP_BITMAP_RGB; + + return 1; + } + + /* handle bitdepth */ + if (x->x_bit_depth < 8) { + png_set_expand(x->x_png); + D pdp_post("convert greyscale to 8 bit"); + } + if (x->x_bit_depth == 16){ + D pdp_post("stripping 16 bit to 8 bit"); + png_set_strip_16(x->x_png); + } + + + /* handle greyscale images */ + if (x->x_color_type == PNG_COLOR_TYPE_GRAY){ + x->x_pdp_bitmap_type = PDP_BITMAP_GREY; + if (png_get_valid(x->x_png, x->x_info, PNG_INFO_tRNS)){ + D pdp_post("no support for greyscale images with alpha info"); + return 0; + } + return 1; + } + + /* handle RGB imges */ + if (x->x_color_type = PNG_COLOR_TYPE_RGB){ + x->x_pdp_bitmap_type = PDP_BITMAP_RGB; + return 1; + } + + /* handle RGBA imges */ + if (x->x_color_type = PNG_COLOR_TYPE_RGBA){ + x->x_pdp_bitmap_type = PDP_BITMAP_RGBA; + return 1; + } + + + /* can't handle image type */ + D pdp_post("image type not supported"); + return 0; + +} + +#define user_error_ptr NULL +#define user_error_fn NULL +#define user_warning_fn NULL + +static int _buildstruct_read(t_png_image *x) +{ + x->x_kindof = READING; + + if (!(x->x_png = png_create_read_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn))) return 0; + + if (!(x->x_info = png_create_info_struct(x->x_png))) return 0; + if (!(x->x_end_info = png_create_info_struct(x->x_png))) return 0; + + return 1; +} + +static int _buildstruct_write(t_png_image *x) +{ + x->x_kindof = WRITING; + + if (!(x->x_png = png_create_write_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn))) return 0; + + if (!(x->x_info = png_create_info_struct(x->x_png))) return 0; + + return 1; +} + +static int _getimagedata(t_png_image *x) +{ + int nbchans = 0; + char *image_data; + png_bytep row_pointers[x->x_height]; + png_uint_32 i; + + D pdp_post("reading %d rows ", (int)x->x_height); + + switch (x->x_pdp_bitmap_type){ + case PDP_BITMAP_GREY: nbchans = 1; break; + case PDP_BITMAP_RGB: nbchans = 3; break; + case PDP_BITMAP_RGBA: nbchans = 4; break; + default: + return 0; + } + + x->x_packet = + pdp_packet_new_bitmap(x->x_pdp_bitmap_type, x->x_width, x->x_height); + if (!(image_data = pdp_packet_data(x->x_packet))) return 0; + + for(i=0; i<x->x_height; i++) + row_pointers[i] = image_data + nbchans * i * x->x_width; + + png_read_image(x->x_png, row_pointers); + + D pdp_post("DONE"); + + return 1; +} + +static int _saveimagedata(t_png_image *x, int packet) +{ + png_bytep *row_pointers; + png_uint_32 i; + int nbchans; + t_pdp *h = pdp_packet_header(packet); + char *image_data = (char *)pdp_packet_data(packet); + + if (!h) return 0; + if (PDP_BITMAP != h->type) return 0; + if (!image_data) return 0; + + x->x_width = h->info.bitmap.width; + x->x_height = h->info.bitmap.height; + + switch(h->info.image.encoding){ + case PDP_BITMAP_GREY: x->x_color_type = PNG_COLOR_TYPE_GRAY; nbchans = 1; break; + case PDP_BITMAP_RGB: x->x_color_type = PNG_COLOR_TYPE_RGB; nbchans = 3; break; + case PDP_BITMAP_RGBA: x->x_color_type = PNG_COLOR_TYPE_RGBA; nbchans = 4; break; + default: return 0; + } + + png_set_IHDR(x->x_png, x->x_info, x->x_width, x->x_height, 8, + x->x_color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + png_write_info(x->x_png, x->x_info); + + D pdp_post("writing %d rows ", (int)x->x_height); + + row_pointers = (png_bytep *)pdp_alloc(sizeof(png_bytep) * x->x_height); + for(i=0; i<x->x_height; i++) + row_pointers[i] = image_data + nbchans * i * x->x_width; + + png_write_image(x->x_png, row_pointers); + png_write_end(x->x_png, x->x_info); + pdp_dealloc(row_pointers); + + D pdp_post("DONE"); + + return 1; +} + + + +/* simple functions to load and save png images */ + +int pdp_packet_bitmap_from_png_file(char *filename) +{ + int packet = -1; + t_png_image _x; + t_png_image *x = &_x; + + if (!_init(x)) goto exit; + if (!_open_read(x, filename)) goto exit; + if (!_buildstruct_read(x)) goto exit; + if (!_initio_read(x)) goto exit; + if (!_checkimagetype(x)) goto exit; + if (!_getimagedata(x)) goto exit; + + packet = x->x_packet; + x->x_packet = -1; + _cleanup(x); + return packet; + exit: + _cleanup(x); + return -1; + +} + + + +int pdp_packet_bitmap_save_png_file(int packet, char *filename) +{ + + t_png_image _x; + t_png_image *x = &_x; + + if (!_init(x)) goto exit; + if (!_open_write(x, filename)) goto exit; + if (!_buildstruct_write(x)) goto exit; + if (!_initio_write(x)) goto exit; + if (!_saveimagedata(x, packet)) goto exit; + + _cleanup(x); + return 1; + exit: + _cleanup(x); + return 0; + +} + + + +#else //PDP_HAVE_PNG +int pdp_packet_bitmap_save_png_file(int packet, char *filename) +{ + pdp_post("WARNING: no png support, can't save png file %s", filename); + return 0; +} + +int pdp_packet_bitmap_from_png_file(char *filename) +{ + pdp_post("WARNING: no png support, can't load png file %s", filename); + return -1; +} + + +#endif //PDP_HAVE_PNG + + + + + + + + + + + + + +#if 0 +int main(int argc, char **argv) +{ + char *image = 0; + + if (argc != 2) + pdp_post("usage: %s <png file>", argv[0]); + else + image = load_png(argv[1]); + + pdp_post ("%s", image ? "OK" : "ERROR"); + +} +#endif diff --git a/system/type/Makefile b/system/type/Makefile new file mode 100644 index 0000000..5f45b0c --- /dev/null +++ b/system/type/Makefile @@ -0,0 +1,11 @@ + +OBJECTS = pdp_bitmap.o pdp_image.o $(PDP_OPTTYPES) + + +include ../../Makefile.config + +all: $(OBJECTS) + +clean: + rm -f *~ + rm -f *.o diff --git a/system/type/pdp_bitmap.c b/system/type/pdp_bitmap.c new file mode 100644 index 0000000..b3e3e07 --- /dev/null +++ b/system/type/pdp_bitmap.c @@ -0,0 +1,628 @@ +/* + * Pure Data Packet system implementation. : 8 bit image packet implementation + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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. + * + */ + + +#include <stdio.h> +#include <string.h> +#include "pdp_packet.h" +#include "pdp_type.h" +#include "pdp_llconv.h" +#include "pdp_internals.h" +#include "pdp_post.h" + + +/* the class object */ +static t_pdp_class* bitmap_class; + + +t_bitmap *pdp_packet_bitmap_info(int packet) +{ + return (t_bitmap *)pdp_packet_subheader(packet); +} + +/* check if packet is a valid image packet */ +int pdp_packet_bitmap_isvalid(int packet) +{ + t_pdp *header = pdp_packet_header(packet); + t_bitmap *image = pdp_packet_bitmap_info(packet); + if (!header) return 0; + if (PDP_BITMAP != header->type) return 0; + + return 1; + +} + + + +/* bitmap constructors */ +t_pdp_symbol *pdp_packet_bitmap_get_description(int packet) +{ + t_pdp *header = pdp_packet_header(packet); + t_bitmap *bitmap = pdp_packet_bitmap_info(packet); + char description[1024]; + char *c = description; + int encoding; + + if (!header) return pdp_gensym("invalid"); + else if (!header->desc){ + /* if description is not defined, try to reconstruct it (for backwards compat) */ + if (header->type == PDP_BITMAP){ + c += sprintf(c, "bitmap"); + encoding = bitmap->encoding; + switch(encoding){ + case PDP_BITMAP_RGB: c += sprintf(c, "/rgb"); break; + case PDP_BITMAP_RGBA: c += sprintf(c, "/rgba"); break; + case PDP_BITMAP_GREY: c += sprintf(c, "/grey"); break; + case PDP_BITMAP_YV12: c += sprintf(c, "/yv12"); break; + default: + c += sprintf(c, "/unknown"); goto exit; + } + c += sprintf(c, "/%dx%d", + bitmap->width, + bitmap->height); + exit: + return pdp_gensym(description); + } + else return pdp_gensym("unknown"); + } + else return header->desc; +} + +int pdp_packet_new_bitmap_yv12(u32 w, u32 h) +{ + t_pdp *header; + t_bitmap *bitmap; + int packet; + + + u32 size = w*h; + u32 totalnbpixels = size; + u32 packet_size = size + (size >> 1); + + packet = pdp_packet_new(PDP_BITMAP, packet_size); + header = pdp_packet_header(packet); + bitmap = pdp_packet_bitmap_info(packet); + if (!header) return -1; + + bitmap->encoding = PDP_BITMAP_YV12; + bitmap->width = w; + bitmap->height = h; + header->desc = pdp_packet_bitmap_get_description(packet); + header->theclass = bitmap_class; + + return packet; +} + +int pdp_packet_new_bitmap_grey(u32 w, u32 h) +{ + t_pdp *header; + t_bitmap *bitmap; + int packet; + + u32 size = w*h; + u32 totalnbpixels = size; + u32 packet_size = totalnbpixels; + + packet = pdp_packet_new(PDP_BITMAP, packet_size); + header = pdp_packet_header(packet); + bitmap = pdp_packet_bitmap_info(packet); + if (!header) return -1; + + bitmap->encoding = PDP_BITMAP_GREY; + bitmap->width = w; + bitmap->height = h; + header->desc = pdp_packet_bitmap_get_description(packet); + header->theclass = bitmap_class; + + return packet; +} + +int pdp_packet_new_bitmap_rgb(u32 w, u32 h) +{ + t_pdp *header; + t_bitmap *bitmap; + int packet; + + + u32 size = w*h; + u32 totalnbpixels = size; + u32 packet_size = totalnbpixels * 3; + + packet = pdp_packet_new(PDP_BITMAP, packet_size); + header = pdp_packet_header(packet); + bitmap = pdp_packet_bitmap_info(packet); + if (!header) return -1; + + bitmap->encoding = PDP_BITMAP_RGB; + bitmap->width = w; + bitmap->height = h; + header->desc = pdp_packet_bitmap_get_description(packet); + header->theclass = bitmap_class; + + return packet; +} + +int pdp_packet_new_bitmap_rgba(u32 w, u32 h) +{ + t_pdp *header; + t_bitmap *bitmap; + int packet; + + + u32 size = w*h; + u32 totalnbpixels = size; + u32 packet_size = totalnbpixels * 4; + + packet = pdp_packet_new(PDP_BITMAP, packet_size); + header = pdp_packet_header(packet); + bitmap = pdp_packet_bitmap_info(packet); + if (!header) return -1; + + bitmap->encoding = PDP_BITMAP_RGBA; + bitmap->width = w; + bitmap->height = h; + header->desc = pdp_packet_bitmap_get_description(packet); + header->theclass = bitmap_class; + + return packet; +} + +int pdp_packet_new_bitmap(int type, u32 w, u32 h) +{ + switch(type){ + case PDP_BITMAP_GREY: return pdp_packet_new_bitmap_grey(w,h); + case PDP_BITMAP_YV12: return pdp_packet_new_bitmap_yv12(w,h); + case PDP_BITMAP_RGB: return pdp_packet_new_bitmap_rgb(w,h); + case PDP_BITMAP_RGBA: return pdp_packet_new_bitmap_rgba(w,h); + default: return -1; + } +} + + +/* some utility methods */ +void pdp_llconv_flip_top_bottom(char *data, int width, int height, int pixelsize); + +/* flip top & bottom */ +void pdp_packet_bitmap_flip_top_bottom(int packet) +{ + t_bitmap *b = (t_bitmap *)pdp_packet_subheader(packet); + char *d = (char *)pdp_packet_data(packet); + int w,h; + if (!pdp_packet_bitmap_isvalid(packet)) return; + if (!b) return; + w = b->width; + h = b->height; + + switch(b->encoding){ + case PDP_BITMAP_GREY: pdp_llconv_flip_top_bottom(d,w,h,1); break; + case PDP_BITMAP_RGB: pdp_llconv_flip_top_bottom(d,w,h,3); break; + case PDP_BITMAP_RGBA: pdp_llconv_flip_top_bottom(d,w,h,4); break; + default: break; + } + +} + + + +/* conversion methods */ +// image/grey/* -> bitmap/grey/* +static int _pdp_packet_bitmap_convert_grey_to_grey8(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_image *image = pdp_packet_image_info(packet); + s16 *data = (s16 *)pdp_packet_data(packet); + u8 *new_data; + u32 w,h; + int new_p; + + if (!pdp_packet_image_isvalid(packet)) return -1; + w = image->width; + h = image->height; + + if (!((image->encoding == PDP_IMAGE_GREY) || + (image->encoding == PDP_IMAGE_YV12))) return -1; + + new_p = pdp_packet_new_bitmap_grey(w,h); + if (-1 == new_p) return -1; + new_data = (u8 *)pdp_packet_data(new_p); + + /* convert image to greyscale 8 bit */ + pdp_llconv(data,RIF_GREY______S16, new_data, RIF_GREY______U8, w, h); + + return new_p; +} + +static int _pdp_packet_bitmap_convert_YCrCb_to_rgb8(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_image *image = pdp_packet_image_info(packet); + s16 *data = (s16 *)pdp_packet_data(packet); + u8 *new_data; + u32 w,h; + int new_p; + + if (!pdp_packet_image_isvalid(packet)) return -1; + w = image->width; + h = image->height; + + if (!((image->encoding == PDP_IMAGE_YV12))) return -1; + + new_p = pdp_packet_new_bitmap_rgb(w,h); + if (-1 == new_p) return -1; + new_data = (u8 *)pdp_packet_data(new_p); + + /* convert image to greyscale 8 bit */ + pdp_llconv(data,RIF_YVU__P411_S16, new_data, RIF_RGB__P____U8, w, h); + + return new_p; +} + +static int _pdp_packet_bitmap_convert_image_to_yv12(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_image *image = pdp_packet_image_info(packet); + s16 *data = (s16 *)pdp_packet_data(packet); + u8 *new_data; + u32 w,h, nbpixels; + int new_p; + int encoding = image->encoding; + + if (!pdp_packet_image_isvalid(packet)) return -1; + w = image->width; + h = image->height; + nbpixels = w*h; + + new_p = pdp_packet_new_bitmap_yv12(w,h); + if (-1 == new_p) return -1; + new_data = (u8 *)pdp_packet_data(new_p); + + switch (encoding){ + case PDP_IMAGE_YV12: + pdp_llconv(data, RIF_YVU__P411_S16, new_data, RIF_YVU__P411_U8, w, h); + break; + case PDP_IMAGE_GREY: + pdp_llconv(data, RIF_GREY______S16, new_data, RIF_GREY______U8, w, h); + memset(new_data + nbpixels, 0x80, nbpixels>>1); + break; + default: + /* not supported, $$$TODO add more */ + pdp_packet_mark_unused(new_p); + new_p = -1; + break; + } + + return new_p; + +} + +static int _pdp_packet_bitmap_convert_rgb8_to_YCrCb(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_bitmap *bitmap = pdp_packet_bitmap_info(packet); + u8 *data = (u8 *)pdp_packet_data(packet); + s16 *new_data; + u32 w,h; + int new_p; + + w = bitmap->width; + h = bitmap->height; + new_p = pdp_packet_new_image_YCrCb(w,h); + if (-1 == new_p) return -1; + new_data = (s16 *)pdp_packet_data(new_p); + + /* convert image to greyscale 8 bit */ + pdp_llconv(data, RIF_RGB__P____U8, new_data, RIF_YVU__P411_S16, w, h); + + return new_p; +} + +static int _pdp_packet_bitmap_convert_rgb8_to_bitmap_YCrCb(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_bitmap *bitmap = pdp_packet_bitmap_info(packet); + u8 *data = (u8 *)pdp_packet_data(packet); + u8 *new_data; + u32 w,h; + int new_p; + + w = bitmap->width; + h = bitmap->height; + new_p = pdp_packet_new_bitmap_yv12(w,h); + if (-1 == new_p) return -1; + new_data = (u8 *)pdp_packet_data(new_p); + + /* convert image to greyscale 8 bit */ + pdp_llconv(data, RIF_RGB__P____U8, new_data, RIF_YVU__P411_U8, w, h); + + return new_p; +} + +static int _pdp_packet_bitmap_convert_grey8_to_grey(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_bitmap *bitmap = pdp_packet_bitmap_info(packet); + s16 *data = (s16 *)pdp_packet_data(packet); + u8 *new_data; + u32 w,h; + int new_p; + + w = bitmap->width; + h = bitmap->height; + new_p = pdp_packet_new_image_grey(w,h); + if (-1 == new_p) return -1; + new_data = (u8 *)pdp_packet_data(new_p); + + /* convert image to greyscale 8 bit */ + pdp_llconv(data, RIF_GREY______U8, new_data, RIF_GREY______S16, w, h); + + return new_p; +} +static int _pdp_packet_bitmap_convert_rgb8_to_rgba8(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_bitmap *bitmap = pdp_packet_bitmap_info(packet); + u8 *data = (u8 *)pdp_packet_data(packet); + u8 *new_data; + int w,h, new_p, i; + + w = bitmap->width; + h = bitmap->height; + new_p = pdp_packet_new_bitmap_rgba(w,h); + if (-1 == new_p) return -1; + new_data = (u8 *)pdp_packet_data(new_p); + + for(i=0; i<w*h; i++){ + new_data[4*i+0] = data[3*i + 0]; + new_data[4*i+1] = data[3*i + 1]; + new_data[4*i+2] = data[3*i + 2]; + new_data[4*i+3] = 0; + } + + return new_p; +} +static int _pdp_packet_bitmap_convert_rgba8_to_rgb8(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_bitmap *bitmap = pdp_packet_bitmap_info(packet); + u8 *data = (u8 *)pdp_packet_data(packet); + u8 *new_data; + int w,h, new_p, i; + + w = bitmap->width; + h = bitmap->height; + new_p = pdp_packet_new_bitmap_rgb(w,h); + if (-1 == new_p) return -1; + new_data = (u8 *)pdp_packet_data(new_p); + + for(i=0; i<w*h; i++){ + new_data[3*i+0] = data[4*i + 0]; + new_data[3*i+1] = data[4*i + 1]; + new_data[3*i+2] = data[4*i + 2]; + } + + return new_p; +} +static int _pdp_packet_bitmap_convert_rgb8_to_mchp(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_bitmap *bitmap = pdp_packet_bitmap_info(packet); + u8 *data = (u8 *)pdp_packet_data(packet); + s16 *new_data; + int w,h; + int new_p, i, plane; + + w = bitmap->width; + h = bitmap->height; + plane = w*h; + new_p = pdp_packet_new_image_multi(w,h,3); + if (-1 == new_p) return -1; + new_data = (s16 *)pdp_packet_data(new_p); + + for(i=0; i<w*h; i++){ + new_data[i] = ((u32)data[3*i + 0]) << 7; + new_data[i+plane] = ((u32)data[3*i + 1]) << 7; + new_data[i+plane*2] = ((u32)data[3*i + 2]) << 7; + } + + return new_p; +} + +static int _pdp_packet_bitmap_convert_yv12_to_image(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_bitmap *bitmap = pdp_packet_bitmap_info(packet); + u8 *data = (u8 *)pdp_packet_data(packet); + s16 *new_data; + int w,h; + int new_p; + + w = bitmap->width; + h = bitmap->height; + new_p = pdp_packet_new_image_YCrCb(w,h); + new_data = pdp_packet_data(new_p); + if (-1 == new_p || !new_data) return -1; + pdp_llconv(data, RIF_YVU__P411_U8, new_data, RIF_YVU__P411_S16, w, h); + + return new_p; +} + +static int _pdp_packet_bitmap_convert_mchp_to_rgb8(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_image *image = (t_image *)pdp_packet_subheader(packet); + s16 *data = (s16 *)pdp_packet_data(packet); + u8 *new_data; + int w = image->width; + int h = image->height; + int plane = w*h; + int nb_channels = image->depth; + int new_p, i; + + static inline u8 _map(s32 pixel){ + s32 mask = ~(pixel>>16); + return ((pixel >> 7) & mask); + } + + switch(nb_channels){ + default: return -1; + case 1: + if (-1 == (new_p = pdp_packet_new_bitmap_grey(w,h))) return -1; + new_data = (u8*)pdp_packet_data(new_p); + for(i=0; i<plane; i++) new_data[i] = _map(data[i]); + break; + case 3: + if (-1 == (new_p = pdp_packet_new_bitmap_rgb(w,h))) return -1; + new_data = (u8*)pdp_packet_data(new_p); + for(i=0; i<plane; i++){ + new_data[3*i+0] = _map(data[i]); + new_data[3*i+1] = _map(data[i+plane]); + new_data[3*i+2] = _map(data[i+plane*2]); + } + break; + case 4: + if (-1 == (new_p = pdp_packet_new_bitmap_rgba(w,h))) return -1; + new_data = (u8*)pdp_packet_data(new_p); + for(i=0; i<plane; i++){ + new_data[4*i+0] = _map(data[i]); + new_data[4*i+1] = _map(data[i+plane]); + new_data[4*i+2] = _map(data[i+plane*2]); + new_data[4*i+3] = _map(data[i+plane*3]); + } + break; + + + } + + return new_p; + +} + +static int _pdp_packet_bitmap_convert_fallback(int packet, t_pdp_symbol *dest_template) +{ + pdp_post("can't convert image type %s to %s", + pdp_packet_get_description(packet)->s_name, dest_template->s_name); + + return -1; +} + +static int pdp_bitmap_factory(t_pdp_symbol *type) +{ + t_pdp_list *l; + t_pdp_symbol *s; + int t; + int w = 0; + int h = 0; + int d = 0; + int p = -1; + int n = 0; + int m = 0; + char *garbage = 0; + + //pdp_post("creating:"); + //pdp_post("%s", type->s_name); + + l = pdp_type_to_list(type); + s = pdp_list_pop(l).w_symbol; // first element is "bitmap" + s = pdp_list_pop(l).w_symbol; + + /* get image type */ + if (s == pdp_gensym("grey")) t = PDP_BITMAP_GREY; + else if (s == pdp_gensym("yv12")) t = PDP_BITMAP_YV12; + else if (s == pdp_gensym("rgb")) t = PDP_BITMAP_RGB; + else goto exit; + + /* get image dimensions and create image */ + s = pdp_list_pop(l).w_symbol; + sscanf(s->s_name, "%dx%d", &w, &h); + p = pdp_packet_new_bitmap(t,w,h); + + if (p != -1){ + t_pdp *h = pdp_packet_header(p); + /* if type is not exact, delete the packet */ + if (type != h->desc) { + pdp_packet_delete(p); + p = -1; + } + } + exit: + pdp_list_free(l); + return p; +} + +void pdp_bitmap_setup(void) +{ + t_pdp_conversion_program *program; + + /* setup class object */ + bitmap_class = pdp_class_new(pdp_gensym("bitmap/*/*"), pdp_bitmap_factory); + + + /* setup conversion programs */ + program = pdp_conversion_program_new(_pdp_packet_bitmap_convert_grey_to_grey8, 0); + pdp_type_register_conversion(pdp_gensym("image/grey/*"), pdp_gensym("bitmap/grey/*"), program); + + program = pdp_conversion_program_new(_pdp_packet_bitmap_convert_grey8_to_grey, 0); + pdp_type_register_conversion(pdp_gensym("bitmap/grey/*"), pdp_gensym("image/grey/*"), program); + + program = pdp_conversion_program_new(_pdp_packet_bitmap_convert_YCrCb_to_rgb8, 0); + pdp_type_register_conversion(pdp_gensym("image/YCrCb/*"), pdp_gensym("bitmap/rgb/*"), program); + + program = pdp_conversion_program_new(_pdp_packet_bitmap_convert_image_to_yv12, 0); + pdp_type_register_conversion(pdp_gensym("image/YCrCb/*"), pdp_gensym("bitmap/yv12/*"), program); + pdp_type_register_conversion(pdp_gensym("image/grey/*"), pdp_gensym("bitmap/yv12/*"), program); + + program = pdp_conversion_program_new(_pdp_packet_bitmap_convert_yv12_to_image, 0); + pdp_type_register_conversion(pdp_gensym("bitmap/yv12/*"), pdp_gensym("image/YCrCb/*"), program); + + /* rgb->YCrCb converts the colour space */ + program = pdp_conversion_program_new(_pdp_packet_bitmap_convert_rgb8_to_YCrCb, 0); + pdp_type_register_conversion(pdp_gensym("bitmap/rgb/*"), pdp_gensym("image/YCrCb/*"), program); + + + /* rgb <-> multi does not convert the colour space */ + program = pdp_conversion_program_new(_pdp_packet_bitmap_convert_rgb8_to_mchp, 0); + pdp_type_register_conversion(pdp_gensym("bitmap/rgb/*"), pdp_gensym("image/multi/*"), program); + + program = pdp_conversion_program_new(_pdp_packet_bitmap_convert_mchp_to_rgb8, 0); + pdp_type_register_conversion(pdp_gensym("image/multi/*"), pdp_gensym("bitmap/*/*"), program); + + + /* rgb <-> rgba */ + program = pdp_conversion_program_new(_pdp_packet_bitmap_convert_rgb8_to_rgba8, 0); + pdp_type_register_conversion(pdp_gensym("bitmap/rgb/*"), pdp_gensym("bitmap/rgba/*"), program); + program = pdp_conversion_program_new(_pdp_packet_bitmap_convert_rgba8_to_rgb8, 0); + pdp_type_register_conversion(pdp_gensym("bitmap/rgba/*"), pdp_gensym("bitmap/rgb/*"), program); + + + /* fallback rgb convertor */ + program = pdp_conversion_program_new(_pdp_packet_bitmap_convert_rgb8_to_YCrCb, 0); + pdp_type_register_conversion(pdp_gensym("bitmap/rgb/*"), pdp_gensym("image/*/*"), program); + + program = pdp_conversion_program_new(_pdp_packet_bitmap_convert_rgb8_to_bitmap_YCrCb, 0); + pdp_type_register_conversion(pdp_gensym("bitmap/rgb/*"), pdp_gensym("bitmap/yv12/*"), program); + + + /* fallbacks */ + program = pdp_conversion_program_new(_pdp_packet_bitmap_convert_fallback, 0); + pdp_type_register_conversion(pdp_gensym("image/*/*"), pdp_gensym("bitmap/*/*"), program); + pdp_type_register_conversion(pdp_gensym("bitmap/*/*"), pdp_gensym("image/*/*"), program); + pdp_type_register_conversion(pdp_gensym("bitmap/*/*"), pdp_gensym("bitmap/*/*"), program); + +} diff --git a/system/type/pdp_image.c b/system/type/pdp_image.c new file mode 100644 index 0000000..66fe22b --- /dev/null +++ b/system/type/pdp_image.c @@ -0,0 +1,584 @@ +/* + * Pure Data Packet system implementation. : 16 bit image packet implementation + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 file contains methods for the image packets + pdp_packet_new_* methods are several image packet constructors + pdp_type_* are image type checkers & converters + +*/ + +#include <string.h> +#include <stdio.h> + +#include "pdp_internals.h" +#include "pdp_packet.h" +#include "pdp_imageproc.h" +#include "pdp_resample.h" +#include "pdp_list.h" +#include "pdp_post.h" +#include "pdp_type.h" + + +/* the class object */ +static t_pdp_class* image_class; + + + +/* check dimensions */ +static void _checkdim(u32 width, u32 height){ + if ((pdp_imageproc_legalwidth(width) != width) || + (pdp_imageproc_legalheight(height) != height)){ + pdp_post("WARNING: request to create image packet with illegal dimensions %d x %d", width, height); + } +} + + +/* image packet constructors */ +int pdp_packet_new_image_YCrCb(u32 w, u32 h) +{ + t_pdp *header; + t_image *image; + int packet; + + + u32 size = w*h; + u32 totalnbpixels = size + (size >> 1); + u32 packet_size = totalnbpixels << 1; + + _checkdim(w,h); + + packet = pdp_packet_new(PDP_IMAGE, packet_size); + header = pdp_packet_header(packet); + image = pdp_packet_image_info(packet); + if (!header) return -1; + + image->encoding = PDP_IMAGE_YV12; + image->width = w; + image->height = h; + header->desc = pdp_packet_image_get_description(packet); + header->theclass = image_class; + + return packet; +} + +int pdp_packet_new_image_grey(u32 w, u32 h) +{ + t_pdp *header; + t_image *image; + int packet; + + + u32 size = w*h; + u32 totalnbpixels = size; + u32 packet_size = totalnbpixels << 1; + + _checkdim(w,h); + + packet = pdp_packet_new(PDP_IMAGE, packet_size); + header = pdp_packet_header(packet); + image = pdp_packet_image_info(packet); + if (!header) return -1; + + image->encoding = PDP_IMAGE_GREY; + image->width = w; + image->height = h; + header->desc = pdp_packet_image_get_description(packet); + header->theclass = image_class; + + return packet; +} + +int pdp_packet_new_image_mchp(u32 w, u32 h, u32 d) +{ + t_pdp *header; + t_image *image; + int packet; + + + u32 size = w*h*d; + u32 totalnbpixels = size; + u32 packet_size = totalnbpixels << 1; + + _checkdim(w,h); + + packet = pdp_packet_new(PDP_IMAGE, packet_size); + header = pdp_packet_header(packet); + image = pdp_packet_image_info(packet); + if (!header) return -1; + + + image->encoding = PDP_IMAGE_MCHP; + image->width = w; + image->height = h; + image->depth = d; + header->desc = pdp_packet_image_get_description(packet); + header->theclass = image_class; + + return packet; +} + + +int pdp_packet_new_image(u32 type, u32 w, u32 h) +{ + switch (type){ + case PDP_IMAGE_YV12: + return pdp_packet_new_image_YCrCb(w,h); + case PDP_IMAGE_GREY: + return pdp_packet_new_image_grey(w,h); + default: + return -1; + } +} + + +/****************** packet type checking and conversion methods ********************/ + + + +/* check if two image packets are allocated and of the same type */ +int pdp_packet_image_compat(int packet0, int packet1) +{ + t_pdp *header0 = pdp_packet_header(packet0); + t_pdp *header1 = pdp_packet_header(packet1); + t_image *image0 = pdp_packet_image_info(packet0); + t_image *image1 = pdp_packet_image_info(packet1); + + + if (!(pdp_packet_compat(packet0, packet1))) return 0; + if (header0->type != PDP_IMAGE){ + //pdp_post("pdp_type_compat_image: not a PDP_IMAGE"); + return 0; + } + if (image0->encoding != image1->encoding){ + //pdp_post("pdp_type_compat_image: encodings differ"); + return 0; + } + if (image0->width != image1->width){ + //pdp_post("pdp_type_compat_image: image withs differ"); + return 0; + } + if (image0->height != image1->height){ + //pdp_post("pdp_type_compat_image: image heights differ"); + return 0; + } + return 1; +} + +/* check if packet is a valid image packet */ +int pdp_packet_image_isvalid(int packet) +{ + t_pdp *header = pdp_packet_header(packet); + t_image *image = pdp_packet_image_info(packet); + if (!header) return 0; + if (PDP_IMAGE != header->type) return 0; + if ((PDP_IMAGE_YV12 != image->encoding) + && (PDP_IMAGE_GREY != image->encoding) + && (PDP_IMAGE_MCHP != image->encoding)) return 0; + + return 1; + +} + +/* set the channel mask for the image */ +void pdp_packet_image_set_chanmask(int packet, unsigned int chanmask) +{ + if (pdp_packet_image_isvalid(packet)) pdp_packet_image_info(packet)->chanmask = chanmask; + +} + + +t_image *pdp_packet_image_info(int packet) +{ + return (t_image *)pdp_packet_subheader(packet); +} + + +t_pdp_symbol *pdp_packet_image_get_description(int packet) +{ + t_pdp *header = pdp_packet_header(packet); + t_image *image = pdp_packet_image_info(packet); + char description[1024]; + char *c = description; + int encoding; + + if (!header) return pdp_gensym("invalid"); + else if (!header->desc){ + /* if description is not defined, try to reconstruct it (for backwards compat) */ + if (header->type == PDP_IMAGE){ + c += sprintf(c, "image"); + encoding = image->encoding; + switch(encoding){ + case PDP_IMAGE_YV12: c += sprintf(c, "/YCrCb"); break; + case PDP_IMAGE_GREY: c += sprintf(c, "/grey"); break; + case PDP_IMAGE_MCHP: c += sprintf(c, "/multi"); break; + default: + c += sprintf(c, "/unknown"); goto exit; + } + if (encoding == PDP_IMAGE_MCHP){ + c += sprintf(c, "/%dx%dx%d", + image->width, + image->height, + image->depth); + } + else { + c += sprintf(c, "/%dx%d", + image->width, + image->height); + } + + exit: + return pdp_gensym(description); + } + else return pdp_gensym("unknown"); + } + else return header->desc; +} + + + + + +/* IMAGE PACKAGE CONVERSION ROUTINES */ + +/* note: these are internal: no extra checking is done + it is assumed the packets are of correct type (the type template associated with the conversion program) */ + +// image/YCrCb/* -> image/grey/* +// image/multi/* -> image/grey/* (only first channel) +static int _pdp_packet_image_convert_YCrCb_to_grey(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_image *image = pdp_packet_image_info(packet); + int w = image->width; + int h = image->height; + int p = pdp_packet_new_image_grey(w,h); + if (p == -1) return p; + memcpy(pdp_packet_data(p), pdp_packet_data(packet), 2*w*h); + return p; +} + +// image/grey/* -> image/YCrCb/* +static int _pdp_packet_image_convert_grey_to_YCrCb(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_image *image = pdp_packet_image_info(packet); + int w = image->width; + int h = image->height; + int p = pdp_packet_new_image_YCrCb(w,h); + int y_bytes = 2*w*h; + void *data; + if (p == -1) return p; + data = pdp_packet_data(p); + memcpy(data, pdp_packet_data(packet), y_bytes); + memset(data+y_bytes, 0, y_bytes >> 1); + return p; +} + +// image/grey/* -> image/multi/* +static int _pdp_packet_image_convert_grey_to_multi(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_image *image = pdp_packet_image_info(packet); + int w = image->width; + int h = image->height; + int p = pdp_packet_new_image_mchp(w,h,1); + int y_bytes = 2*w*h; + void *data; + if (p == -1) return p; + data = pdp_packet_data(p); + memcpy(data, pdp_packet_data(packet), y_bytes); + return p; +} + +// image/multi/* -> image/YCrCb/* (only first 3 channels) +static int _pdp_packet_image_convert_multi_to_YCrCb(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_image *image = pdp_packet_image_info(packet); + s16 *data, *newdata; + + /* get info */ + int w = image->width; + int h = image->height; + int d = image->depth; + int plane_size = w*h; + + /* create new packet */ + int newpacket = pdp_packet_new_image_YCrCb(w, h); + if (-1 == newpacket) return -1; + + data = pdp_packet_data(packet); + newdata = pdp_packet_data(newpacket); + + /* copy channel 0 */ + memcpy(newdata, data, plane_size<<1); + newdata += plane_size; + data += plane_size; + + /* copy channel 1 */ + if (d >= 1) pdp_resample_halve(data, newdata, w, h); + else memset(newdata, 0, plane_size >> 1); + data += plane_size; + newdata += (plane_size >> 2); + + + /* copy channel 2 */ + if (d >= 2) pdp_resample_halve(data, newdata, w, h); + else memset(newdata, 0, plane_size >> 1); + + return newpacket; + +} + +// image/YCrCb/* -> image/multi/* +static int _pdp_packet_image_convert_YCrCb_to_multi(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_image *image = pdp_packet_image_info(packet); + s16 *data, *newdata; + + /* get info */ + int w = image->width; + int h = image->height; + int plane_size = w*h; + + /* create new packet */ + int newpacket = pdp_packet_new_image_mchp(w, h, 3); + if (-1 == newpacket) return -1; + + data = pdp_packet_data(packet); + newdata = pdp_packet_data(newpacket); + + /* copy channel 0 */ + memcpy(newdata, data, plane_size<<1); + newdata += plane_size; + data += plane_size; + w >>= 1; + h >>= 1; + + /* copy channel 1 */ + pdp_resample_double(data, newdata, w, h); + data += (plane_size >> 2); + newdata += plane_size; + + /* copy channel 2 */ + pdp_resample_double(data, newdata, w, h); + + return newpacket; + +} + +static void _pdp_description_get_dims(t_pdp_symbol *template, int *w, int *h, int *d) +{ + char *c = template->s_name; + // get requested dimensions + *w = 0; + *h = 0; + *d = 0; + while (*c++ != '/'); + while (*c++ != '/'); + sscanf(c, "%dx%dx%d", w, h, d); + +} + +// resample image/YCrCb/* +static int _pdp_packet_image_convert_resample_YCrCb(int packet, t_pdp_symbol *dest_template) +{ + int quality = 1; + int dst_w, dst_h, dummy; + int new_packet; + unsigned int src_size, src_voffset, src_uoffset; + unsigned int dst_size, dst_voffset, dst_uoffset; + t_pdp *header0 = pdp_packet_header(packet); + t_image *image0 = pdp_packet_image_info(packet); + unsigned int src_w = image0->width; + unsigned int src_h = image0->height; + short int *src_image = (short int *)pdp_packet_data(packet); + short int *dst_image; + _pdp_description_get_dims(dest_template, &dst_w, &dst_h, &dummy); + new_packet = pdp_packet_new_image_YCrCb(dst_w, dst_h); + if (-1 == new_packet) return -1; + dst_image = (short int*)pdp_packet_data(new_packet); + src_size = src_w*src_h; + src_voffset = src_size; + src_uoffset = src_size + (src_size>>2); + dst_size = dst_w*dst_h; + dst_voffset = dst_size; + dst_uoffset = dst_size + (dst_size>>2); + if (quality){ + pdp_resample_scale_bilin(src_image, dst_image, src_w, src_h, dst_w, dst_h); + pdp_resample_scale_bilin(src_image+src_voffset, dst_image+dst_voffset, src_w>>1, src_h>>1, dst_w>>1, dst_h>>1); + pdp_resample_scale_bilin(src_image+src_uoffset, dst_image+dst_uoffset, src_w>>1, src_h>>1, dst_w>>1, dst_h>>1); + } + else{ + pdp_resample_scale_nn(src_image, dst_image, src_w, src_h, dst_w, dst_h); + pdp_resample_scale_nn(src_image+src_voffset, dst_image+dst_voffset, src_w>>1, src_h>>1, dst_w>>1, dst_h>>1); + pdp_resample_scale_nn(src_image+src_uoffset, dst_image+dst_uoffset, src_w>>1, src_h>>1, dst_w>>1, dst_h>>1); + } + return new_packet; +} + +// resample image/grey/* and image/multi/* +static int _pdp_packet_image_convert_resample_multi(int packet, t_pdp_symbol *dest_template) +{ + int quality = 1; + int dst_w, dst_h, depth; + int new_packet; + unsigned int src_size; + unsigned int dst_size; + t_pdp *header0 = pdp_packet_header(packet); + t_image *image0 = pdp_packet_image_info(packet); + unsigned int src_w = image0->width; + unsigned int src_h = image0->height; + short int *src_image = (short int *)pdp_packet_data(packet); + short int *dst_image; + _pdp_description_get_dims(dest_template, &dst_w, &dst_h, &depth); + + if (depth == 0){ + depth = 1; + new_packet = pdp_packet_new_image_grey(dst_w, dst_h); + } + else { + new_packet = pdp_packet_new_image_mchp(dst_w, dst_h, depth); + } + if (-1 == new_packet) return -1; + + dst_image = (short int*)pdp_packet_data(new_packet); + + src_size = src_w*src_h; + dst_size = dst_w*dst_h; + while (depth--){ + if (quality){ + pdp_resample_scale_bilin(src_image, dst_image, src_w, src_h, dst_w, dst_h); + } + else{ + pdp_resample_scale_nn(src_image, dst_image, src_w, src_h, dst_w, dst_h); + } + src_image += src_size; + dst_image += dst_size; + } + + return new_packet; +} + +static int _pdp_packet_image_convert_fallback(int packet, t_pdp_symbol *dest_template) +{ + pdp_post("can't convert image type %s to %s", + pdp_packet_get_description(packet)->s_name, dest_template->s_name); + + return -1; +} + + + +/* the expensive factory method */ +static int pdp_image_factory(t_pdp_symbol *type) +{ + t_pdp_list *l; + t_pdp_symbol *s; + int t; + int w = 0; + int h = 0; + int d = 0; + int p = -1; + int n = 0; + int m = 0; + char *garbage = 0; + + //pdp_post("creating:"); + //pdp_post("%s", type->s_name); + + l = pdp_type_to_list(type); + s = pdp_list_pop(l).w_symbol; // first element is "image" + s = pdp_list_pop(l).w_symbol; + + /* get image type */ + if (s == pdp_gensym("grey")) t = PDP_IMAGE_GREY; + else if (s == pdp_gensym("YCrCb")) t = PDP_IMAGE_YV12; + else if (s == pdp_gensym("multi")) t = PDP_IMAGE_MCHP; + else goto exit; + + /* get image dimensions and create image */ + s = pdp_list_pop(l).w_symbol; + switch (t){ + case PDP_IMAGE_MCHP: + m = sscanf(s->s_name, "%dx%dx%d", &w, &h, &d); + p = pdp_packet_new_image_mchp(w,h,d); + break; + default: + sscanf(s->s_name, "%dx%d", &w, &h); + p = pdp_packet_new_image(t,w,h); + break; + } + if (p != -1){ + t_pdp *h = pdp_packet_header(p); + /* if type is not exact, delete the packet */ + if (type != h->desc) { + pdp_packet_delete(p); + p = -1; + } + } + exit: + pdp_list_free(l); + return p; +} + + + +void pdp_image_words_setup(t_pdp_class *c); + +void pdp_image_setup(void) +{ + t_pdp_conversion_program *program; + + /* setup the class object */ + image_class = pdp_class_new(pdp_gensym("image/*/*"), pdp_image_factory); + + + /* setup conversion programs */ + program = pdp_conversion_program_new(_pdp_packet_image_convert_YCrCb_to_grey, 0); + pdp_type_register_conversion(pdp_gensym("image/YCrCb/*"), pdp_gensym("image/grey/*"), program); + pdp_type_register_conversion(pdp_gensym("image/multi/*"), pdp_gensym("image/grey/*"), program); + + program = pdp_conversion_program_new(_pdp_packet_image_convert_grey_to_YCrCb, 0); + pdp_type_register_conversion(pdp_gensym("image/grey/*"), pdp_gensym("image/YCrCb/*"), program); + + program = pdp_conversion_program_new(_pdp_packet_image_convert_grey_to_multi, 0); + pdp_type_register_conversion(pdp_gensym("image/grey/*"), pdp_gensym("image/multi/*"), program); + + program = pdp_conversion_program_new(_pdp_packet_image_convert_multi_to_YCrCb, 0); + pdp_type_register_conversion(pdp_gensym("image/multi/*"), pdp_gensym("image/YCrCb/*"), program); + + program = pdp_conversion_program_new(_pdp_packet_image_convert_YCrCb_to_multi, 0); + pdp_type_register_conversion(pdp_gensym("image/YCrCb/*"), pdp_gensym("image/multi/*"), program); + + program = pdp_conversion_program_new(_pdp_packet_image_convert_resample_YCrCb, 0); + pdp_type_register_conversion(pdp_gensym("image/YCrCb/*"), pdp_gensym("image/YCrCb/*"), program); + + program = pdp_conversion_program_new(_pdp_packet_image_convert_resample_multi, 0); + pdp_type_register_conversion(pdp_gensym("image/multi/*"), pdp_gensym("image/multi/*"), program); + pdp_type_register_conversion(pdp_gensym("image/grey/*"), pdp_gensym("image/grey/*"), program); + + /* catch-all fallback */ + program = pdp_conversion_program_new(_pdp_packet_image_convert_fallback, 0); + pdp_type_register_conversion(pdp_gensym("image/*/*"), pdp_gensym("image/*/*"), program); + +} diff --git a/system/type/pdp_matrix.c b/system/type/pdp_matrix.c new file mode 100644 index 0000000..a6fc827 --- /dev/null +++ b/system/type/pdp_matrix.c @@ -0,0 +1,654 @@ + +#include <string.h> +#include "pdp_matrix.h" +#include "pdp_packet.h" +#include "pdp_symbol.h" +#include "pdp_internals.h" // for pdp_packet_new, which is not a proper constructor +#include "pdp_post.h" +#include "pdp_type.h" + +/* the class object */ +static t_pdp_class *matrix_class; + + + +/* declare header and subheader variables and exit with errval if invalid */ +#define VALID_MATRIX_HEADER(packet, header, subheader, mtype, errval) \ +t_pdp * header = pdp_packet_header( packet ); \ +t_matrix * subheader = (t_matrix *)pdp_packet_subheader( packet ); \ +if (! header ) return errval; \ +if (PDP_MATRIX != header->type) return errval; \ +if (mtype) {if (subheader->type != mtype) return errval;} + + +int pdp_packet_matrix_isvalid(int p) +{ + VALID_MATRIX_HEADER(p, h, m, 0, 0); + return 1; +} + + +void *pdp_packet_matrix_get_gsl_matrix(int p, u32 type) +{ + VALID_MATRIX_HEADER(p, h, m, type, 0); + return &m->matrix; +} + +void *pdp_packet_matrix_get_gsl_vector(int p, u32 type) +{ + VALID_MATRIX_HEADER(p, h, m, type, 0); + return &m->vector; +} + +int pdp_packet_matrix_get_type(int p) +{ + VALID_MATRIX_HEADER(p, h, m, 0, 0); + return m->type; +} + +int pdp_packet_matrix_isvector(int p) +{ + VALID_MATRIX_HEADER(p, h, m, 0, 0); + return ((m->rows == 1) || (m->columns == 1)); +} + +int pdp_packet_matrix_ismatrix(int p) +{ + VALID_MATRIX_HEADER(p, h, m, 0, 0); + return ((m->rows != 1) && (m->columns != 1)); +} + + + + +/* gsl blas matrix/vector multiplication: + +vector.vector + + (const gsl_vector * x, const gsl_vector * y, double * result) + +gsl_blas_sdot +gsl_blas_ddot +gsl_blas_cdot +gsl_blas_zdot +gsl_blas_cdotu +gsl_blas_zdotu + +matrix.vector + ( + CBLAS_TRANSPOSE_t + TransA, + double alpha, + const gsl_matrix * A, + const gsl_vector * x, + double beta, + gsl_vector * y + ) + +gsl_blas_sgemv +gsl_blas_dgemv +gsl_blas_cgemv +gsl_blas_zgemv + +matrix.matrix + ( + CBLAS_TRANSPOSE_t TransA, + CBLAS_TRANSPOSE_t TransB, + double alpha, + const gsl_matrix * A, + const gsl_matrix * B, + double beta, + gsl_matrix * C + ) + +gsl_blas_sgemm +gsl_blas_dgemm +gsl_blas_cgemm +gsl_blas_zgemm + +*/ + +/* compute the matrix inverse using the LU decomposition */ +/* it only works for double real/complex */ +int pdp_packet_matrix_LU_to_inverse(int p) +{ + int new_p; + u32 n; + int type = pdp_packet_matrix_get_type(p); + t_matrix *sheader = (t_matrix *)pdp_packet_subheader(p); + gsl_matrix *m = (gsl_matrix *)pdp_packet_matrix_get_gsl_matrix(p, type); + gsl_matrix *im; + if (!m) return -1; + n = m->gsl_rows; + if (n != m->gsl_columns) return -1; + new_p = pdp_packet_new_matrix(n, n, type); + if (-1 == new_p) return -1; + im = (gsl_matrix *)pdp_packet_matrix_get_gsl_matrix(new_p, type); + + switch(type){ + case PDP_MATRIX_TYPE_RDOUBLE: + gsl_linalg_LU_invert (m, &sheader->perm, im); break; + case PDP_MATRIX_TYPE_CDOUBLE: + gsl_linalg_complex_LU_invert ((gsl_matrix_complex *)m, &sheader->perm, (gsl_matrix_complex *)im); break; + default: + pdp_packet_mark_unused(new_p); + new_p = -1; + } + return new_p; +} +/* compute the LU decomposition of a square matrix */ +/* it only works for double real/complex */ +int pdp_packet_matrix_LU(int p) +{ + int p_LU, bytes; + u32 n; + int type = pdp_packet_matrix_get_type(p); + t_matrix *sh_m_LU; + t_matrix *sh_m = (t_matrix *)pdp_packet_subheader(p); + gsl_matrix *m = (gsl_matrix *)pdp_packet_matrix_get_gsl_matrix(p, type); + gsl_matrix *m_LU; + if (!m) return -1; + n = m->gsl_rows; + if (n != m->gsl_columns) return -1; + p_LU = pdp_packet_new_matrix(n, n, type); + if (-1 == p_LU) return -1; + sh_m_LU = (t_matrix *)pdp_packet_subheader(p_LU); + m_LU = (gsl_matrix *)pdp_packet_matrix_get_gsl_matrix(p_LU, type); + /* copy matrix data: move this to copy method */ + memcpy(pdp_packet_data(p_LU), pdp_packet_data(p), sh_m->block.size); + + switch(type){ + case PDP_MATRIX_TYPE_RDOUBLE: + gsl_linalg_LU_decomp (m_LU, &sh_m_LU->perm, &sh_m_LU->signum); break; + case PDP_MATRIX_TYPE_CDOUBLE: + gsl_linalg_complex_LU_decomp ((gsl_matrix_complex *)m_LU, &sh_m_LU->perm, &sh_m_LU->signum); break; + default: + pdp_packet_mark_unused(p_LU); + p_LU = -1; + } + return p_LU; +} + +int pdp_packet_matrix_LU_solve(int p_matrix, int p_vector) +{ + int type = pdp_packet_matrix_get_type(p_matrix); + int p_result_vector = pdp_packet_clone_rw(p_vector); + gsl_matrix *m = (gsl_matrix *)pdp_packet_matrix_get_gsl_matrix(p_matrix, type); + gsl_vector *v = (gsl_vector *)pdp_packet_matrix_get_gsl_vector(p_vector, type); + gsl_vector *rv = (gsl_vector *)pdp_packet_matrix_get_gsl_vector(p_result_vector, type); + t_matrix *sh_m = (t_matrix *)pdp_packet_subheader(p_matrix); + + if (!(m && v && rv)) goto error; + + switch(type){ + case PDP_MATRIX_TYPE_RDOUBLE: + if (gsl_linalg_LU_solve (m, &sh_m->perm, v, rv)) goto error; break; + case PDP_MATRIX_TYPE_CDOUBLE: + if(gsl_linalg_complex_LU_solve ((gsl_matrix_complex*)m, &sh_m->perm, + (gsl_vector_complex *)v, (gsl_vector_complex *)rv)) goto error; break; + default: + goto error; + } + return p_result_vector; + + error: + pdp_packet_mark_unused(p_result_vector); + //post("error"); + return -1; +} + +/* matrix matrix mul: C is defining type + returns 0 on success */ +int pdp_packet_matrix_blas_mm +( + CBLAS_TRANSPOSE_t TransA, + CBLAS_TRANSPOSE_t TransB, + int pA, + int pB, + int pC, + float scale_r, + float scale_i +) +{ + gsl_complex_float cf_scale = {{scale_r, scale_i}}; + gsl_complex cd_scale = {{(double)scale_r, (double)scale_i}}; + gsl_complex_float cf_one = {{1.0f, 0.0f}}; + gsl_complex cd_one = {{1.0, 0.0}}; + gsl_matrix *mA, *mB, *mC; + int type; + type = pdp_packet_matrix_get_type(pC); + mA = (gsl_matrix *)pdp_packet_matrix_get_gsl_matrix(pA,type); + mB = (gsl_matrix *)pdp_packet_matrix_get_gsl_matrix(pB,type); + mC = (gsl_matrix *)pdp_packet_matrix_get_gsl_matrix(pC,type); + + if (!(mA && mB)) return 1; + + + switch(type){ + case PDP_MATRIX_TYPE_RFLOAT: + return gsl_blas_sgemm(TransA, TransB, scale_r, (gsl_matrix_float *)mA, + (gsl_matrix_float *)mB, 1.0f, (gsl_matrix_float *)mC); + case PDP_MATRIX_TYPE_RDOUBLE: + return gsl_blas_dgemm(TransA, TransB, (double)scale_r, (gsl_matrix *)mA, + (gsl_matrix *)mB, 1.0, (gsl_matrix *)mC); + case PDP_MATRIX_TYPE_CFLOAT: + return gsl_blas_cgemm(TransA, TransB, cf_scale, (gsl_matrix_complex_float *)mA, + (gsl_matrix_complex_float *)mB, cf_one, (gsl_matrix_complex_float *)mC); + case PDP_MATRIX_TYPE_CDOUBLE: + return gsl_blas_zgemm(TransA, TransB, cd_scale, (gsl_matrix_complex *)mA, + (gsl_matrix_complex *)mB, cd_one, (gsl_matrix_complex *)mC); + default: + return 0; + } +} + +/* matrix vector mul: C is defining type + returns 0 on success */ +int pdp_packet_matrix_blas_mv +( + CBLAS_TRANSPOSE_t TransA, + int pA, + int pb, + int pc, + float scale_r, + float scale_i +) +{ + gsl_complex_float cf_scale = {{scale_r, scale_i}}; + gsl_complex cd_scale = {{(double)scale_r, (double)scale_i}}; + gsl_complex_float cf_one = {{1.0f, 0.0f}}; + gsl_complex cd_one = {{1.0, 0.0}}; + gsl_matrix *mA; + gsl_vector *vb, *vc; + int type; + type = pdp_packet_matrix_get_type(pA); + mA = (gsl_matrix *)pdp_packet_matrix_get_gsl_matrix(pA,type); + vb = (gsl_vector *)pdp_packet_matrix_get_gsl_vector(pb,type); + vc = (gsl_vector *)pdp_packet_matrix_get_gsl_vector(pc,type); + + if (!(vb && vc)) return 1; + + + switch(type){ + case PDP_MATRIX_TYPE_RFLOAT: + return gsl_blas_sgemv(TransA, scale_r, (gsl_matrix_float *)mA, + (gsl_vector_float *)vb, 1.0f, (gsl_vector_float *)vc); + case PDP_MATRIX_TYPE_RDOUBLE: + return gsl_blas_dgemv(TransA, (double)scale_r, (gsl_matrix *)mA, + (gsl_vector *)vb, 1.0, (gsl_vector *)vc); + case PDP_MATRIX_TYPE_CFLOAT: + return gsl_blas_cgemv(TransA, cf_scale, (gsl_matrix_complex_float *)mA, + (gsl_vector_complex_float *)vb, cf_one, (gsl_vector_complex_float *)vc); + case PDP_MATRIX_TYPE_CDOUBLE: + return gsl_blas_zgemv(TransA, cd_scale, (gsl_matrix_complex *)mA, + (gsl_vector_complex *)vb, cd_one, (gsl_vector_complex *)vc); + default: + return 0; + } +} + + + +t_pdp_symbol *_pdp_matrix_get_description(t_pdp *header) +{ + t_matrix *m = (t_matrix *)(&header->info.raw); + char description[100]; + char *c = description; + int encoding; + + if (!header) return pdp_gensym("invalid"); + else if (!header->desc){ + /* if description is not defined, try to reconstruct it (for backwards compat) */ + if (header->type == PDP_MATRIX){ + + c += sprintf(c, "matrix"); + + switch(m->type){ + case PDP_MATRIX_TYPE_RFLOAT: c += sprintf(c, "/float/real"); break; + case PDP_MATRIX_TYPE_CFLOAT: c += sprintf(c, "/float/complex"); break; + case PDP_MATRIX_TYPE_RDOUBLE: c += sprintf(c, "/double/real"); break; + case PDP_MATRIX_TYPE_CDOUBLE: c += sprintf(c, "/double/complex"); break; + default: + c += sprintf(c, "/unknown"); goto exit; + } + + c += sprintf(c, "/%dx%d", (int)m->rows, (int)m->columns); + + exit: + return pdp_gensym(description); + } + else return pdp_gensym("unknown"); + } + else return header->desc; +} + + + +static void _pdp_matrix_copy(t_pdp *dst, t_pdp *src); +static void _pdp_matrix_clone(t_pdp *dst, t_pdp *src); +static void _pdp_matrix_reinit(t_pdp *dst); +static void _pdp_matrix_cleanup(t_pdp *dst); + +static size_t _pdp_matrix_mdata_byte_size(u32 rows, u32 columns, u32 type) +{ + size_t dsize = rows * columns; + switch (type){ + case PDP_MATRIX_TYPE_RFLOAT: dsize *= sizeof(float); break; + case PDP_MATRIX_TYPE_CFLOAT: dsize *= 2*sizeof(float); break; + case PDP_MATRIX_TYPE_RDOUBLE: dsize *= sizeof(double); break; + case PDP_MATRIX_TYPE_CDOUBLE: dsize *= 2*sizeof(double); break; + default: dsize = 0; + } + return dsize; +} + + +static size_t _pdp_matrix_pdata_vector_size(u32 rows, u32 columns) +{ + return (rows>columns ? rows : columns); +} + + +static void _pdp_matrix_init(t_pdp *dst, u32 rows, u32 columns, u32 type) +{ + int i; + t_matrix *m = (t_matrix *)(&dst->info.raw); + void *d = ((void *)dst) + PDP_HEADER_SIZE; + int matrix_bytesize = _pdp_matrix_mdata_byte_size(rows, columns, type); + int permsize = _pdp_matrix_pdata_vector_size(rows, columns); + + /* set meta data */ + m->type = type; + m->rows = rows; + m->columns = columns; + + /* set the block data */ + m->block.size = matrix_bytesize; + m->block.data = (double *)d; + + /* set the vector view */ + m->vector.size = (1==columns) ? rows : columns; + m->vector.stride = 1; + m->vector.data = (double *)d; + m->vector.block = &m->block; + m->vector.owner = 0; + + /* set the matrix view */ + m->matrix.gsl_rows = rows; + m->matrix.gsl_columns = columns; + m->matrix.tda = columns; + m->matrix.data = (double *)d; + m->matrix.block = &m->block; + m->matrix.owner = 0; + + /* set the permutation object & init */ + m->perm.size = permsize; + m->perm.data = (size_t *)(d + matrix_bytesize); + for(i=0; i<permsize; i++) m->perm.data[i] = i; + m->signum = -1; + + /* init packet header */ + dst->theclass = matrix_class; + dst->desc = _pdp_matrix_get_description(dst); + +} + +static void _pdp_matrix_clone(t_pdp *dst, t_pdp *src) +{ + t_matrix *m = (t_matrix *)(&src->info.raw); + _pdp_matrix_init(dst, m->rows, m->columns, m->type); + +} +static void _pdp_matrix_copy(t_pdp *dst, t_pdp *src) +{ + _pdp_matrix_clone(dst, src); + memcpy(dst + PDP_HEADER_SIZE, src + PDP_HEADER_SIZE, src->size - PDP_HEADER_SIZE); + //post("matrix copy successful"); +} +static void _pdp_matrix_reinit(t_pdp *dst) +{ + /* nothing to do, assuming data is correct */ +} +static void _pdp_matrix_cleanup(t_pdp *dst) +{ + /* no extra memory to free */ +} + +int pdp_packet_new_matrix(u32 rows, u32 columns, u32 type) +{ + t_pdp *header; + int dsize, p; + + /* compute the blocksize for the matrix data */ + /* if 0, something went wrong -> return invalid packet */ + if (!(dsize = _pdp_matrix_mdata_byte_size(rows, columns, type))) return -1; + dsize += sizeof(size_t) * _pdp_matrix_pdata_vector_size(rows, columns); + + p = pdp_packet_new(PDP_MATRIX, dsize); + if (-1 == p) return -1; + header = pdp_packet_header(p); + + _pdp_matrix_init(header, rows, columns, type); + + return p; +} + +int pdp_packet_new_matrix_product_result(CBLAS_TRANSPOSE_t TransA, CBLAS_TRANSPOSE_t TransB, int pA, int pB) +{ + gsl_matrix *mA, *mB; + u32 type = pdp_packet_matrix_get_type(pA); + + u32 colA, colB, rowA, rowB; + + /* check if A is a matrix */ + if (!type) return -1; + + mA = (gsl_matrix *)pdp_packet_matrix_get_gsl_matrix(pA, type); + mB = (gsl_matrix *)pdp_packet_matrix_get_gsl_matrix(pB, type); + + /* check if A and B are same type */ + if (!mB) return -1; + + /* get dims A */ + if (TransA == CblasNoTrans){ + rowA = mA->gsl_rows; + colA = mA->gsl_columns; + } + else { + rowA = mA->gsl_columns; + colA = mA->gsl_rows; + } + + /* get dims B */ + if (TransB == CblasNoTrans){ + rowB = mB->gsl_rows; + colB = mB->gsl_columns; + } + else { + rowB = mB->gsl_columns; + colB = mB->gsl_rows; + } + + /* check if sizes are compatible */ + if (colA != rowB) return -1; + + /* create new packet */ + return pdp_packet_new_matrix(rowA, colB, type); +} + +void pdp_packet_matrix_setzero(int p) +{ + t_matrix *m; + if (!pdp_packet_matrix_isvalid(p)) return; + m = (t_matrix *) pdp_packet_subheader(p); + memset(m->block.data, 0, m->block.size); +} + + + +/* type conversion programs */ +static int _pdp_packet_convert_matrix_to_greyimage(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_matrix *matrix = (t_matrix *)pdp_packet_subheader(packet); + void *data = pdp_packet_data(packet); + s16 *new_data; + u32 c,r, nbelements; + int new_p; + u32 i; + + c = matrix->columns; + r = matrix->rows; + nbelements = c*r; + + new_p = pdp_packet_new_image_grey(c,r); + if (-1 == new_p) return -1; + new_data = (s16 *)pdp_packet_data(new_p); + + /* convert first channel */ + switch(matrix->type){ + case PDP_MATRIX_TYPE_RFLOAT: + for (i=0; i<nbelements; i++) (new_data)[i] = (s16)(((float *)data)[i] * (float)0x8000); break; + case PDP_MATRIX_TYPE_CFLOAT: //only copy real channel + for (i=0; i<nbelements; i++) (new_data)[i] = (s16)(((float *)data)[i<<1] * (float)0x8000); break; + case PDP_MATRIX_TYPE_RDOUBLE: + for (i=0; i<nbelements; i++) (new_data)[i] = (s16)(((double *)data)[i] * (float)0x8000); break; + case PDP_MATRIX_TYPE_CDOUBLE: //only copy real channel + for (i=0; i<nbelements; i++) (new_data)[i] = (s16)(((double *)data)[i<<1] * (float)0x8000); break; + default: + pdp_packet_mark_unused(new_p); + new_p = -1; + } + return new_p; +} + +static int _pdp_packet_convert_image_to_matrix(int packet, t_pdp_symbol *dest_template, int type) +{ + t_pdp *header = pdp_packet_header(packet); + t_image *image = pdp_packet_image_info(packet); + s16 *data = (s16 *)pdp_packet_data(packet); + void *new_data; + u32 w,h, nbelements; + int new_p; + int encoding = image->encoding; + u32 i; + + if (!pdp_packet_image_isvalid(packet)) return -1; + w = image->width; + h = image->height; + nbelements = w*h; + + new_p = pdp_packet_new_matrix(h,w, type); + if (-1 == new_p) return -1; + new_data = pdp_packet_data(new_p); + + switch (encoding){ + case PDP_IMAGE_YV12: + case PDP_IMAGE_GREY: + case PDP_IMAGE_MCHP: + /* convert first channel */ + switch(type){ + case PDP_MATRIX_TYPE_RFLOAT: + for (i=0; i<nbelements; i++) + ((float *)new_data)[i] = ((float)data[i]) * (1.0f / (float)0x8000); break; + case PDP_MATRIX_TYPE_RDOUBLE: + for (i=0; i<nbelements; i++) + ((double *)new_data)[i] = ((double)data[i]) * (1.0f / (double)0x8000); break; + case PDP_MATRIX_TYPE_CFLOAT: + for (i=0; i<nbelements; i++){ + ((float *)new_data)[i*2] = ((float)data[i]) * (1.0f / (float)0x8000); + ((float *)new_data)[i*2+1] = 0.0f; + } + break; + case PDP_MATRIX_TYPE_CDOUBLE: + for (i=0; i<nbelements; i++){ + ((double *)new_data)[i*2] = ((double)data[i]) * (1.0f / (double)0x8000); + ((double *)new_data)[i*2+1] = 0.0; + } + break; + default: + pdp_post("_pdp_packet_convert_image_to_matrix: INTERNAL ERROR"); + } + break; + default: + pdp_packet_mark_unused(new_p); + new_p = -1; + break; + } + + return new_p; + +} + +static int _pdp_packet_convert_image_to_floatmatrix(int packet, t_pdp_symbol *dest_template){ + return _pdp_packet_convert_image_to_matrix(packet, dest_template, PDP_MATRIX_TYPE_RFLOAT);} +static int _pdp_packet_convert_image_to_doublematrix(int packet, t_pdp_symbol *dest_template){ + return _pdp_packet_convert_image_to_matrix(packet, dest_template, PDP_MATRIX_TYPE_RDOUBLE);} +static int _pdp_packet_convert_image_to_complexfloatmatrix(int packet, t_pdp_symbol *dest_template){ + return _pdp_packet_convert_image_to_matrix(packet, dest_template, PDP_MATRIX_TYPE_CFLOAT);} +static int _pdp_packet_convert_image_to_complexdoublematrix(int packet, t_pdp_symbol *dest_template){ + return _pdp_packet_convert_image_to_matrix(packet, dest_template, PDP_MATRIX_TYPE_CDOUBLE);} + + +static int _pdp_packet_matrix_convert_fallback(int packet, t_pdp_symbol *dest_template) +{ + pdp_post("can't convert image type %s to %s", + pdp_packet_get_description(packet)->s_name, dest_template->s_name); + + return -1; +} + + +/* this seems like a nice spot to place a dummy gsl signal handler */ +static void _gsl_error_handler (const char * reason, + const char * file, + int line, + int gsl_errno) +{ + //pdp_post("gsl error:\nREASON: %s\nFILE:%s\nLINE:%d\nERRNO:%d", reason, file, line, gsl_errno); +} + +static int pdp_matrix_factory(t_pdp_symbol *type) +{ + return -1; +} +void pdp_matrix_setup(void) +{ + t_pdp_conversion_program *program; + + + /* setup the class */ + matrix_class = pdp_class_new(pdp_gensym("matrix/*/*/*"), pdp_matrix_factory); + matrix_class->copy = _pdp_matrix_copy; + //matrix_class->clone = _pdp_matrix_clone; // is now solved through (symbol based) constructor + matrix_class->wakeup = _pdp_matrix_reinit; + matrix_class->cleanup = _pdp_matrix_cleanup; + + + /* image -> matrix: default = double/real (most ops available) */ + program = pdp_conversion_program_new(_pdp_packet_convert_image_to_doublematrix, 0); + pdp_type_register_conversion(pdp_gensym("image/*/*"), pdp_gensym("matrix/double/real/*"), program); + program = pdp_conversion_program_new(_pdp_packet_convert_image_to_floatmatrix, 0); + pdp_type_register_conversion(pdp_gensym("image/*/*"), pdp_gensym("matrix/float/real/*"), program); + program = pdp_conversion_program_new(_pdp_packet_convert_image_to_complexdoublematrix, 0); + pdp_type_register_conversion(pdp_gensym("image/*/*"), pdp_gensym("matrix/double/complex/*"), program); + program = pdp_conversion_program_new(_pdp_packet_convert_image_to_complexfloatmatrix, 0); + pdp_type_register_conversion(pdp_gensym("image/*/*"), pdp_gensym("matrix/float/complex/*"), program); + + /* matrix -> image */ + program = pdp_conversion_program_new(_pdp_packet_convert_matrix_to_greyimage, 0); + pdp_type_register_conversion(pdp_gensym("matrix/*/*/*"), pdp_gensym("image/grey/*"), program); + + /* fallbacks */ + program = pdp_conversion_program_new(_pdp_packet_matrix_convert_fallback, 0); + pdp_type_register_conversion(pdp_gensym("matrix/*/*/*"), pdp_gensym("image/*/*"), program); + pdp_type_register_conversion(pdp_gensym("matrix/*/*/*"), pdp_gensym("bitmap/*/*"), program); + pdp_type_register_conversion(pdp_gensym("image/*/*"), pdp_gensym("matrix/*/*/*/*"), program); + pdp_type_register_conversion(pdp_gensym("bitmap/*/*"), pdp_gensym("matrix/*/*/*/*"), program); + + /* setup gsl handler */ + if(gsl_set_error_handler(_gsl_error_handler)){ + pdp_post("pdp_matrix_setup: WARNING: overriding gsl error handler."); + } + +} |