aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans-Christoph Steiner <eighthave@users.sourceforge.net>2005-12-16 01:05:40 +0000
committerHans-Christoph Steiner <eighthave@users.sourceforge.net>2005-12-16 01:05:40 +0000
commitb694c274836ac8b04d644711ac324eac2e9ab83e (patch)
tree36b6a5c17f7e1f414f80697210c2ed3e8005035b
parente28a07fba67af0af818dda6afa4cf67c09700816 (diff)
checking in pdp 0.12.4 from http://zwizwa.fartit.com/pd/pdp/pdp-0.12.4.tar.gz
svn path=/trunk/externals/pdp/; revision=4232
-rw-r--r--debug/gdb_pdp_load29
-rw-r--r--debug/gdb_pdp_load_rt10
-rw-r--r--doc/examples/example01.pd45
-rw-r--r--doc/examples/example02.pd44
-rw-r--r--doc/examples/example03.pd86
-rw-r--r--doc/examples/example04.pd85
-rw-r--r--doc/examples/example05.pd142
-rw-r--r--doc/examples/example06.pd76
-rw-r--r--doc/examples/example07.pd73
-rw-r--r--doc/examples/example08.pd57
-rw-r--r--doc/examples/example09.pd35
-rw-r--r--doc/examples/example10.pd55
-rw-r--r--doc/examples/example11.pd80
-rw-r--r--doc/examples/example12.pd42
-rw-r--r--doc/examples/example13.pd104
-rw-r--r--doc/examples/example14.pd54
-rw-r--r--doc/examples/example15.pd27
-rw-r--r--doc/introduction/control.pd17
-rw-r--r--doc/introduction/input_output.pd82
-rw-r--r--doc/introduction/quicktime.pd101
-rw-r--r--doc/introduction/traffic.pd101
-rw-r--r--doc/objects/README4
-rw-r--r--doc/objects/pdp_abs.pd21
-rw-r--r--doc/objects/pdp_add.pd34
-rw-r--r--doc/objects/pdp_and.pd24
-rw-r--r--doc/objects/pdp_bitdepth.pd32
-rw-r--r--doc/objects/pdp_bitmask.pd22
-rw-r--r--doc/objects/pdp_bq.pd154
-rw-r--r--doc/objects/pdp_bqt.pd98
-rw-r--r--doc/objects/pdp_cheby.pd66
-rw-r--r--doc/objects/pdp_chrot.pd13
-rw-r--r--doc/objects/pdp_cog.pd32
-rw-r--r--doc/objects/pdp_constant.pd21
-rw-r--r--doc/objects/pdp_control.pd59
-rw-r--r--doc/objects/pdp_conv.pd44
-rw-r--r--doc/objects/pdp_convert.pd17
-rw-r--r--doc/objects/pdp_del.pd31
-rw-r--r--doc/objects/pdp_description.pd28
-rw-r--r--doc/objects/pdp_flip_lr.pd11
-rw-r--r--doc/objects/pdp_flip_tb.pd11
-rw-r--r--doc/objects/pdp_gain.pd23
-rw-r--r--doc/objects/pdp_grey2mask.pd25
-rw-r--r--doc/objects/pdp_help_input.pd79
-rw-r--r--doc/objects/pdp_help_output.pd14
-rw-r--r--doc/objects/pdp_histo.pd36
-rw-r--r--doc/objects/pdp_hthresh.pd26
-rw-r--r--doc/objects/pdp_loop.pd62
-rw-r--r--doc/objects/pdp_mix.pd21
-rw-r--r--doc/objects/pdp_mix2.pd25
-rw-r--r--doc/objects/pdp_mul.pd28
-rw-r--r--doc/objects/pdp_netsend.pd62
-rw-r--r--doc/objects/pdp_noise.pd21
-rw-r--r--doc/objects/pdp_not.pd21
-rw-r--r--doc/objects/pdp_or.pd24
-rw-r--r--doc/objects/pdp_plasma.pd29
-rw-r--r--doc/objects/pdp_pointcloud.pd32
-rw-r--r--doc/objects/pdp_positive.pd27
-rw-r--r--doc/objects/pdp_qt.pd71
-rw-r--r--doc/objects/pdp_qt~.pd25
-rw-r--r--doc/objects/pdp_randmix.pd24
-rw-r--r--doc/objects/pdp_rawin.pd28
-rw-r--r--doc/objects/pdp_rawout.pd28
-rw-r--r--doc/objects/pdp_reg.pd38
-rw-r--r--doc/objects/pdp_rotate.pd30
-rw-r--r--doc/objects/pdp_route.pd22
-rw-r--r--doc/objects/pdp_scale.pd32
-rw-r--r--doc/objects/pdp_scanxy~.pd76
-rw-r--r--doc/objects/pdp_scan~.pd41
-rw-r--r--doc/objects/pdp_scope~.pd23
-rw-r--r--doc/objects/pdp_sign.pd25
-rw-r--r--doc/objects/pdp_snap.pd21
-rw-r--r--doc/objects/pdp_sthresh.pd26
-rw-r--r--doc/objects/pdp_trigger.pd79
-rw-r--r--doc/objects/pdp_v4l.pd71
-rw-r--r--doc/objects/pdp_xor.pd28
-rw-r--r--doc/objects/pdp_xv.pd61
-rw-r--r--doc/objects/pdp_zoom.pd41
-rw-r--r--doc/objects/pdp_zrot.pd47
-rw-r--r--doc/objects/pdp_zthresh.pd21
-rw-r--r--include/Makefile6
-rw-r--r--include/pdp.h158
-rw-r--r--include/pdp_ascii.h39
-rw-r--r--include/pdp_base.h136
-rw-r--r--include/pdp_bitmap.h96
-rw-r--r--include/pdp_comm.h120
-rw-r--r--include/pdp_compat.h17
-rw-r--r--include/pdp_config.h89
-rw-r--r--include/pdp_config.h.in88
-rw-r--r--include/pdp_control.h12
-rw-r--r--include/pdp_debug.h16
-rw-r--r--include/pdp_dpd_base.h141
-rw-r--r--include/pdp_dpd_command.h79
-rw-r--r--include/pdp_image.h95
-rw-r--r--include/pdp_imagebase.h51
-rw-r--r--include/pdp_imageproc.h226
-rw-r--r--include/pdp_internals.h59
-rw-r--r--include/pdp_list.h240
-rw-r--r--include/pdp_list_macros.h27
-rw-r--r--include/pdp_llconv.h81
-rw-r--r--include/pdp_matrix.h94
-rw-r--r--include/pdp_mem.h46
-rw-r--r--include/pdp_mmx.h171
-rw-r--r--include/pdp_net.h197
-rw-r--r--include/pdp_packet.h214
-rw-r--r--include/pdp_pd.h7
-rw-r--r--include/pdp_png.h28
-rw-r--r--include/pdp_post.h29
-rw-r--r--include/pdp_queue.h123
-rw-r--r--include/pdp_resample.h50
-rw-r--r--include/pdp_symbol.h136
-rw-r--r--include/pdp_type.h180
-rw-r--r--include/pdp_type.h_old180
-rw-r--r--include/pdp_types.h57
-rw-r--r--include/pdp_xvideo.h78
-rw-r--r--include/pdp_xwindow.h122
-rw-r--r--include/pwc-ioctl.h176
-rw-r--r--modules/Makefile20
-rw-r--r--modules/README30
-rw-r--r--modules/generic/Makefile15
-rw-r--r--modules/generic/README2
-rw-r--r--modules/generic/pdp_convert.c104
-rw-r--r--modules/generic/pdp_del.c193
-rw-r--r--modules/generic/pdp_description.c98
-rw-r--r--modules/generic/pdp_inspect.c124
-rw-r--r--modules/generic/pdp_loop.c296
-rw-r--r--modules/generic/pdp_rawin.c299
-rw-r--r--modules/generic/pdp_rawout.c320
-rw-r--r--modules/generic/pdp_reg.c170
-rw-r--r--modules/generic/pdp_route.c146
-rw-r--r--modules/generic/pdp_snap.c120
-rw-r--r--modules/generic/pdp_trigger.c192
-rw-r--r--modules/generic/pdp_udp_receive.c203
-rw-r--r--modules/generic/pdp_udp_send.c336
-rw-r--r--modules/image_basic/Makefile19
-rw-r--r--modules/image_basic/README5
-rw-r--r--modules/image_basic/pdp_add.c109
-rw-r--r--modules/image_basic/pdp_bq.c462
-rw-r--r--modules/image_basic/pdp_cheby.c189
-rw-r--r--modules/image_basic/pdp_constant.c162
-rw-r--r--modules/image_basic/pdp_conv.c212
-rw-r--r--modules/image_basic/pdp_gain.c111
-rw-r--r--modules/image_basic/pdp_logic.c252
-rw-r--r--modules/image_basic/pdp_mix.c165
-rw-r--r--modules/image_basic/pdp_mul.c85
-rw-r--r--modules/image_basic/pdp_noise.c160
-rw-r--r--modules/image_basic/pdp_plasma.c166
-rw-r--r--modules/image_basic/pdp_randmix.c113
-rw-r--r--modules/image_basic/pdp_stateless.c185
-rw-r--r--modules/image_basic/pdp_zoom.c221
-rw-r--r--modules/image_io/Makefile11
-rw-r--r--modules/image_io/README2
-rw-r--r--modules/image_io/pdp_glx.c582
-rw-r--r--modules/image_io/pdp_qt.c974
-rw-r--r--modules/image_io/pdp_sdl.c337
-rw-r--r--modules/image_io/pdp_v4l.c835
-rw-r--r--modules/image_io/pdp_xv.c343
-rw-r--r--modules/image_special/Makefile15
-rw-r--r--modules/image_special/README2
-rw-r--r--modules/image_special/pdp_array.c194
-rw-r--r--modules/image_special/pdp_chrot.c144
-rw-r--r--modules/image_special/pdp_cog.c243
-rw-r--r--modules/image_special/pdp_grey2mask.c195
-rw-r--r--modules/image_special/pdp_histo.c415
-rw-r--r--modules/image_special/pdp_scale.c277
-rw-r--r--modules/image_special/pdp_scan.c231
-rw-r--r--modules/image_special/pdp_scanxy.c207
-rw-r--r--modules/image_special/pdp_scope.c317
-rw-r--r--modules/matrix_basic/Makefile12
-rw-r--r--modules/matrix_basic/README5
-rw-r--r--modules/matrix_basic/clusterstuff.c540
-rw-r--r--modules/matrix_basic/pdp_mat_lu.c143
-rw-r--r--modules/matrix_basic/pdp_mat_mul.c308
-rw-r--r--modules/matrix_basic/pdp_mat_vec.c213
-rw-r--r--modules/test/Makefile13
-rw-r--r--modules/test/README1
-rw-r--r--modules/test/pdp_dpd_test.c104
-rw-r--r--opengl/Makefile27
-rw-r--r--opengl/Makefile.config25
-rw-r--r--opengl/README248
-rw-r--r--opengl/TODO124
-rw-r--r--opengl/abstractions/3dp_basicscene.pd27
-rw-r--r--opengl/abstractions/3dp_blend.pd13
-rw-r--r--opengl/abstractions/3dp_display_texture.pd31
-rw-r--r--opengl/abstractions/3dp_fixedsizewindowcontext.pd31
-rw-r--r--opengl/abstractions/3dp_mouserotate.pd37
-rw-r--r--opengl/abstractions/3dp_screenshot.pd21
-rw-r--r--opengl/abstractions/elbat.pd41
-rw-r--r--opengl/abstractions/randomnormal.pd39
-rw-r--r--opengl/abstractions/randomwalk2D.pd51
-rw-r--r--opengl/abstractions/smoothupdate.pd49
-rw-r--r--opengl/doc/examples/arm.pd40
-rw-r--r--opengl/doc/examples/example01.pd257
-rw-r--r--opengl/doc/examples/example02.pd46
-rw-r--r--opengl/doc/examples/example03.pd65
-rw-r--r--opengl/doc/examples/example04.pd25
-rw-r--r--opengl/doc/examples/example05.pd41
-rw-r--r--opengl/doc/examples/example06.pd85
-rw-r--r--opengl/doc/examples/example07.pd25
-rw-r--r--opengl/doc/examples/example08.pd94
-rw-r--r--opengl/doc/examples/example09.pd90
-rw-r--r--opengl/doc/examples/example10.pd39
-rw-r--r--opengl/doc/examples/example11.pd77
-rw-r--r--opengl/doc/examples/example12.pd90
-rw-r--r--opengl/doc/examples/example13.pd81
-rw-r--r--opengl/doc/examples/example14.pd66
-rw-r--r--opengl/doc/examples/example15.pd126
-rw-r--r--opengl/doc/examples/example16.pd107
-rw-r--r--opengl/doc/objects/3dp_for.pd91
-rw-r--r--opengl/include/Makefile5
-rw-r--r--opengl/include/pdp_3Dcontext.h94
-rw-r--r--opengl/include/pdp_3dp_base.h36
-rw-r--r--opengl/include/pdp_mesh.h210
-rw-r--r--opengl/include/pdp_opengl.h33
-rw-r--r--opengl/include/pdp_texture.h93
-rw-r--r--opengl/modules/Makefile10
-rw-r--r--opengl/modules/README3
-rw-r--r--opengl/modules/pdp_3d_color.c167
-rw-r--r--opengl/modules/pdp_3d_context.c163
-rw-r--r--opengl/modules/pdp_3d_dlist.c183
-rw-r--r--opengl/modules/pdp_3d_draw.c500
-rw-r--r--opengl/modules/pdp_3d_drawmesh.c340
-rw-r--r--opengl/modules/pdp_3d_for.c106
-rw-r--r--opengl/modules/pdp_3d_light.c155
-rw-r--r--opengl/modules/pdp_3d_push.c181
-rw-r--r--opengl/modules/pdp_3d_snap.c216
-rw-r--r--opengl/modules/pdp_3d_state.c135
-rw-r--r--opengl/modules/pdp_3d_subcontext.c116
-rw-r--r--opengl/modules/pdp_3d_view.c231
-rw-r--r--opengl/modules/pdp_3d_windowcontext.c232
-rw-r--r--opengl/system/Makefile8
-rw-r--r--opengl/system/pdp_3Dcontext_common.c267
-rw-r--r--opengl/system/pdp_3Dcontext_glx.c393
-rw-r--r--opengl/system/pdp_3dp_base.c30
-rw-r--r--opengl/system/pdp_mesh.c560
-rw-r--r--opengl/system/pdp_opengl.c76
-rw-r--r--opengl/system/pdp_texture.c541
-rw-r--r--opengl/system/setup.c83
-rw-r--r--opengl/test/arm.pd39
-rw-r--r--opengl/test/meshtest.pd200
-rw-r--r--opengl/test/pdp_ogl_draw_limb.pd361
-rw-r--r--opengl/test/textest.pd54
-rw-r--r--puredata/CONTENTS10
-rw-r--r--puredata/Makefile12
-rw-r--r--puredata/pdp_base.c415
-rw-r--r--puredata/pdp_comm.c367
-rw-r--r--puredata/pdp_compat.c57
-rw-r--r--puredata/pdp_control.c186
-rw-r--r--puredata/pdp_dpd_base.c270
-rw-r--r--puredata/pdp_imagebase.c79
-rw-r--r--puredata/pdp_queue.c386
-rw-r--r--puredata/pdp_ut.c262
-rw-r--r--scaf/COPYING340
-rw-r--r--scaf/Makefile43
-rw-r--r--scaf/Makefile.config30
-rw-r--r--scaf/Makefile.config.in30
-rw-r--r--scaf/README92
-rw-r--r--scaf/README.scaf98
-rw-r--r--scaf/TODO3
-rw-r--r--scaf/compiler/Makefile6
-rw-r--r--scaf/compiler/kernel.scaf130
-rw-r--r--scaf/compiler/optim.rules74
-rwxr-xr-xscaf/compiler/scafc44
-rwxr-xr-xscaf/compiler/scafc.pl269
-rw-r--r--scaf/compiler/scafmacro.s487
-rwxr-xr-xscaf/configure4124
-rw-r--r--scaf/configure.ac53
-rw-r--r--scaf/doc/pdp_ca.pd78
-rw-r--r--scaf/include/Makefile6
-rw-r--r--scaf/include/pdp_ca.h74
-rw-r--r--scaf/pdp/Makefile13
-rw-r--r--scaf/pdp/pdp_ca.c919
-rw-r--r--scaf/pdp/pdp_ca_system.c324
-rw-r--r--scaf/pdp/scaf_feeder.s50
-rw-r--r--scaf/rules/Makefile14
-rw-r--r--scaf/rules/carules.scaf118
-rw-r--r--scaf/test/test_pdp_ca.pd132
-rw-r--r--scaf/test/test_pdp_ca2.pd154
-rw-r--r--scaf/test/test_pdp_ca3.pd161
-rw-r--r--system/CONTENTS9
-rw-r--r--system/Makefile30
-rw-r--r--system/X11/Makefile11
-rw-r--r--system/X11/pdp_xvideo.c201
-rw-r--r--system/X11/pdp_xwindow.c623
-rw-r--r--system/image/Makefile21
-rw-r--r--system/image/pdp_imageproc_common.c610
-rw-r--r--system/image/pdp_imageproc_mmx.c594
-rw-r--r--system/image/pdp_imageproc_portable.c681
-rw-r--r--system/image/pdp_llconv.c574
-rw-r--r--system/image/pdp_llconv_mmx.c55
-rw-r--r--system/image/pdp_llconv_portable.c82
-rw-r--r--system/image/pdp_resample.c204
-rw-r--r--system/kernel/CONTENTS7
-rw-r--r--system/kernel/Makefile16
-rw-r--r--system/kernel/pdp_debug.c21
-rw-r--r--system/kernel/pdp_dpd_command.c87
-rw-r--r--system/kernel/pdp_list.c931
-rw-r--r--system/kernel/pdp_mem.c129
-rw-r--r--system/kernel/pdp_packet.c634
-rw-r--r--system/kernel/pdp_packet2.c623
-rw-r--r--system/kernel/pdp_post.c48
-rw-r--r--system/kernel/pdp_symbol.c196
-rw-r--r--system/kernel/pdp_type.c473
-rw-r--r--system/mmx/Makefile31
-rw-r--r--system/mmx/pdp_mmx_test.c62
-rw-r--r--system/mmx/pixel_add_s16.s55
-rw-r--r--system/mmx/pixel_biquad_dirI_s16.s361
-rw-r--r--system/mmx/pixel_biquad_s16.s451
-rw-r--r--system/mmx/pixel_ca_s1.s189
-rw-r--r--system/mmx/pixel_cascade_s16.s330
-rw-r--r--system/mmx/pixel_cheby_s16.s90
-rw-r--r--system/mmx/pixel_conv_hor_s16.s134
-rw-r--r--system/mmx/pixel_conv_ver_s16.s128
-rw-r--r--system/mmx/pixel_crot_s16.s153
-rw-r--r--system/mmx/pixel_gain.s83
-rw-r--r--system/mmx/pixel_gain_s16.s71
-rw-r--r--system/mmx/pixel_mix_s16.s68
-rw-r--r--system/mmx/pixel_mul_s16.s56
-rw-r--r--system/mmx/pixel_pack_s16u8.s126
-rw-r--r--system/mmx/pixel_rand_s16.s76
-rw-r--r--system/mmx/pixel_randmix_s16.s91
-rw-r--r--system/mmx/pixel_resample_s16.s314
-rw-r--r--system/mmx/pixel_s1.s201
-rw-r--r--system/mmx/pixel_unpack_u8s16.s113
-rw-r--r--system/net/Makefile11
-rw-r--r--system/net/pdp_net.c685
-rw-r--r--system/pdp.c230
-rw-r--r--system/png/Makefile11
-rw-r--r--system/png/pdp_png.c409
-rw-r--r--system/type/Makefile11
-rw-r--r--system/type/pdp_bitmap.c628
-rw-r--r--system/type/pdp_image.c584
-rw-r--r--system/type/pdp_matrix.c654
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.");
+ }
+
+}