aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--opengl/abstractions/3dp_basicscene.pd25
-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/include/Makefile5
-rw-r--r--opengl/include/pdp_3Dcontext.h94
-rw-r--r--opengl/include/pdp_3dp_base.h35
-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.c216
-rw-r--r--opengl/system/Makefile8
-rw-r--r--opengl/system/pdp_3Dcontext_common.c267
-rw-r--r--opengl/system/pdp_3Dcontext_glx.c374
-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.c80
-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
43 files changed, 6120 insertions, 0 deletions
diff --git a/opengl/abstractions/3dp_basicscene.pd b/opengl/abstractions/3dp_basicscene.pd
new file mode 100644
index 0000000..4050b52
--- /dev/null
+++ b/opengl/abstractions/3dp_basicscene.pd
@@ -0,0 +1,25 @@
+#N canvas 97 639 450 300 10;
+#X obj 54 72 metro 40;
+#X obj 54 140 3dp_push;
+#X floatatom 375 162 5 0 0;
+#X obj 254 216 3dp_light 0;
+#X obj 54 169 3dp_mouserotate;
+#X obj 54 111 3dp_windowcontext;
+#X text 19 12 a basic 3d scene with a light source and mouse view rotation
+;
+#X obj 54 218 outlet;
+#X obj 254 192 3dp_view transz 10;
+#X obj 54 46 inlet;
+#X obj 254 158 3dp_view roty;
+#X floatatom 340 129 5 0 0;
+#X connect 0 0 5 0;
+#X connect 1 0 4 0;
+#X connect 1 1 10 0;
+#X connect 2 0 8 1;
+#X connect 4 0 7 0;
+#X connect 5 0 1 0;
+#X connect 5 1 4 1;
+#X connect 8 0 3 0;
+#X connect 9 0 0 0;
+#X connect 10 0 8 0;
+#X connect 11 0 10 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/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..2af1dcf
--- /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);
+ void pdp_packet_3Dcontext_win_send_events(int packet, t_outlet *outlet);
+ 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..5c53f51
--- /dev/null
+++ b/opengl/include/pdp_3dp_base.h
@@ -0,0 +1,35 @@
+#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..a475692
--- /dev/null
+++ b/opengl/modules/pdp_3d_windowcontext.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_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)
+{
+ 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)
+{
+ int p = pdp_3dp_base_move_context_packet(x);
+ t_pdp_procqueue *q = pdp_3dp_base_get_queue(x);
+ pdp_procqueue_wait(q);
+ //post("FIXME: pdp_3d_windowcontext_close: wait for thread");
+ pdp_packet_delete(p);
+}
+
+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;
+
+ /* check if at least one processing chain is done (two busy = max) */
+ 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 */
+ p = pdp_3dp_base_get_context_packet(x);
+ pdp_packet_3Dcontext_win_send_events(p, x->x_eventout);
+
+ /* 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..c26999a
--- /dev/null
+++ b/opengl/system/pdp_3Dcontext_glx.c
@@ -0,0 +1,374 @@
+
+/*
+ * 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 */
+ 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.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.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_free((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);
+}
+
+
+void pdp_packet_3Dcontext_win_send_events(int packet, t_outlet *outlet)
+{
+ 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_send_events(xwin, outlet);
+ _pdp_3Dcontext_set_window_size(c, xwin);
+}
+
+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->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.dpy);
+
+ /* 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 */
+
+void pdp_3Dcontext_glx_setup(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.dpy = XOpenDisplay(":0"))){
+ post("pdp_opengl_system_setup: can't open display");
+ goto init_failed;
+ }
+
+
+ /* get screen */
+ pdp_glx_env.screen = DefaultScreen(pdp_glx_env.dpy);
+
+ /* get visual */
+ if (NULL == (pdp_glx_env.visual = glXChooseVisual(pdp_glx_env.dpy, pdp_glx_env.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.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->reinit = _3Dcontext_reinit;
+ context_class->clone = _3Dcontext_clone;
+ context_class->copy = _3Dcontext_copy;
+
+
+ /* setup conversion programs: NOT IMPLEMENTED */
+
+
+ return;
+
+
+ init_failed_close_dpy:
+ XCloseDisplay(pdp_glx_env.dpy);
+ init_failed:
+ post("pdp_opengl_system_setup: ERROR: pdp_opengl init failed. i sense a crash coming..");
+
+}
+
+
+#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..46e1c7a
--- /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_brandnew(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->reinit = _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..4bbda49
--- /dev/null
+++ b/opengl/system/setup.c
@@ -0,0 +1,80 @@
+#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);
+
+
+void pdp_opengl_setup(void)
+{
+ int i;
+ post("PDP: pdp_opengl extension library");
+
+ /* setup system */
+ pdp_opengl_system_setup();
+
+ /* setup packet types */
+ pdp_3Dcontext_glx_setup();
+ pdp_3Dcontext_common_setup();
+ pdp_texture_setup();
+
+
+ /* setup modules */
+ pdp_3d_windowcontext_setup();
+ pdp_3d_draw_setup();
+ pdp_3d_view_setup();
+ pdp_3d_push_setup();
+ pdp_3d_light_setup();
+ pdp_3d_dlist_setup();
+ pdp_3d_color_setup();
+ pdp_3d_snap_setup();
+ pdp_3d_drawmesh_setup();
+ pdp_3d_for_setup();
+ pdp_3d_state_setup();
+ 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;