aboutsummaryrefslogtreecommitdiff
path: root/opengl/system
diff options
context:
space:
mode:
Diffstat (limited to 'opengl/system')
-rw-r--r--opengl/system/Makefile8
-rw-r--r--opengl/system/pdp_3Dcontext_common.c267
-rw-r--r--opengl/system/pdp_3Dcontext_glx.c393
-rw-r--r--opengl/system/pdp_3dp_base.c30
-rw-r--r--opengl/system/pdp_mesh.c560
-rw-r--r--opengl/system/pdp_opengl.c76
-rw-r--r--opengl/system/pdp_texture.c541
-rw-r--r--opengl/system/setup.c83
8 files changed, 1958 insertions, 0 deletions
diff --git a/opengl/system/Makefile b/opengl/system/Makefile
new file mode 100644
index 0000000..0a31482
--- /dev/null
+++ b/opengl/system/Makefile
@@ -0,0 +1,8 @@
+include ../Makefile.config
+
+all: pdp_texture.o pdp_3Dcontext_glx.o pdp_3Dcontext_common.o \
+ pdp_opengl.o pdp_3dp_base.o pdp_mesh.o setup.o
+
+clean:
+ rm -rf *~ *.o
+
diff --git a/opengl/system/pdp_3Dcontext_common.c b/opengl/system/pdp_3Dcontext_common.c
new file mode 100644
index 0000000..185e2be
--- /dev/null
+++ b/opengl/system/pdp_3Dcontext_common.c
@@ -0,0 +1,267 @@
+
+/*
+ * OpenGL Extension Module for pdp - pbuffer packet implementation
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ this code uses glx. i don't know if it is worth to take into
+ account portabiliy. since it will take a while until pdp runs
+ on anything else than linux. but in any case, providing a windows/osx
+ implementation here should not be too difficult..
+*/
+
+#include "pdp_3Dcontext.h"
+#include <GL/gl.h>
+//#include <GL/glx.h>
+#include <GL/glu.h>
+//#include <GL/glut.h>
+
+#define D if (0)
+
+/* constructor */
+
+/* pbuf operators */
+
+u32 pdp_packet_3Dcontext_width(int packet)
+{
+ t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
+ if (c) return c->width;
+ else return 0;
+}
+
+u32 pdp_packet_3Dcontext_height(int packet)
+{
+ t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
+ if (c) return c->height;
+ else return 0;
+}
+
+u32 pdp_packet_3Dcontext_subwidth(int packet)
+{
+ t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
+ if (c) return c->sub_width;
+ else return 0;
+}
+
+
+u32 pdp_packet_3Dcontext_subheight(int packet)
+{
+ t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
+ if (c) return c->sub_height;
+ else return 0;
+}
+
+
+void pdp_packet_3Dcontext_set_subwidth(int packet, u32 w)
+{
+ t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
+ if (c) c->sub_width = w;
+}
+
+
+void pdp_packet_3Dcontext_set_subheight(int packet, u32 h)
+{
+ t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
+ if (c) c->sub_height = h;
+}
+
+
+float pdp_packet_3Dcontext_subaspect(int packet)
+{
+ t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
+ if (c) return (float)c->sub_width/c->sub_height;
+ else return 0;
+}
+
+int pdp_packet_3Dcontext_isvalid(int packet)
+{
+ t_pdp *header = pdp_packet_header(packet);
+ t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
+
+ if (!header) return 0;
+ if (!c) return 0;
+ if (PDP_3DCONTEXT != header->type) return 0;
+ return 1;
+}
+
+t_3Dcontext *pdp_packet_3Dcontext_info(int packet)
+{
+ t_pdp *header = pdp_packet_header(packet);
+ if (!header) return 0;
+ if (PDP_3DCONTEXT != header->type) return 0;
+ return (t_3Dcontext *)&header->info.raw;
+}
+
+
+
+void pdp_llconv_flip_top_bottom(char *data, int width, int height, int pixelsize);
+
+int pdp_packet_3Dcontext_snap_to_bitmap(int packet, int w, int h)
+{
+ int x, y, new_p, i;
+ char *data = 0;
+ // char r;
+ // int extra = 5;
+
+ if (!pdp_packet_3Dcontext_isvalid(packet)) goto error;
+
+ x = pdp_packet_3Dcontext_subwidth(packet);
+ y = pdp_packet_3Dcontext_subheight(packet);
+
+ x = (x - w) >> 1;
+ y = (y - h) >> 1;
+ x = (x < 0 ) ? 0 : x;
+ y = (y < 0 ) ? 0 : y;
+
+ new_p = pdp_packet_new_bitmap_rgb(w, h);
+ data = (char *)pdp_packet_data(new_p);
+ if (-1 == new_p || !data) goto error;
+ pdp_packet_3Dcontext_set_rendering_context(packet);
+
+ // D post("BEGIN READPIXELS %d %d %d %d %x", w, h, x, y, data);
+
+ //for (i=0; i<w*h; i++){
+ // data[3*i] = 255;
+ // data[3*i+1] = 255;
+ // data[3*i+2] = 0;
+ //}
+ // r = random();
+ // data[w*h*3] = r;
+
+ /* seems nvidia drivers 4191 have a bug
+ when w % 4 is not zero */
+ glReadPixels(x,y, w ,h,GL_RGB,GL_UNSIGNED_BYTE, data);
+
+ /* inplace swap top to bottom (textures and buffers have
+ another coordinate system than standard images)
+ instead of fixing this by using a different texture coordinate
+ system, a memory swap is performed. this is more expensive
+ but eliminates hassle when converting between buffers, textures
+ and bitmaps */
+
+ pdp_llconv_flip_top_bottom(data, w, h, 3);
+
+ // if (r != data[w*h*3]) post("PANIC");
+
+ // post("END READPIXELS %d %d", w, h);
+
+
+ return new_p;
+
+ error:
+ return -1;
+
+}
+
+
+
+
+/* move these to the pdp_3d_context object: they're too specific */
+
+/* setup for 2d operation from pbuf dimensions */
+void pdp_packet_3Dcontext_setup_2d_context(int p)
+{
+ u32 w;
+ u32 h;
+ float asp;
+ if (!pdp_packet_3Dcontext_isvalid(p)) return;
+ w = pdp_packet_3Dcontext_subwidth(p);
+ h = pdp_packet_3Dcontext_subheight(p);
+ asp = pdp_packet_3Dcontext_subaspect(p);
+
+
+ /* set the viewport to the size of the sub frame */
+ glViewport(0, 0, w, h);
+
+ /* set orthogonal projection, with a relative frame size of (2asp x 2) */
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluOrtho2D(0, 2*asp, 0, 2);
+
+ /* set the center of view */
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(asp, 1, 0);
+ glScalef(1,-1,1);
+
+
+}
+
+/* setup for 3d operation from pbuf dimensions */
+void pdp_packet_3Dcontext_setup_3d_context(int p)
+{
+ u32 w;
+ u32 h;
+ int i;
+ float asp;
+ float m_perspect[] = {-1.f, /* left */
+ 1.f, /* right */
+ -1.f, /* bottom */
+ 1.f, /* top */
+ 1.f, /* front */
+ 20.f};/* back */
+
+ if (!pdp_packet_3Dcontext_isvalid(p)) return;
+ w = pdp_packet_3Dcontext_subwidth(p);
+ h = pdp_packet_3Dcontext_subheight(p);
+ asp = pdp_packet_3Dcontext_subaspect(p);
+
+
+ /* set the viewport to the size of the sub frame */
+ glViewport(0, 0, w, h);
+
+ /* set orthogonal projection, with a relative frame size of (2asp x 2) */
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(m_perspect[0] * asp, m_perspect[1] * asp, // left, right
+ m_perspect[2], m_perspect[3], // bottom, top
+ m_perspect[4], m_perspect[5]); // front, back
+
+ /* reset texture matrix */
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+
+
+ /* set the center of view */
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ gluLookAt(0, 0, 4, 0, 0, 0, 0, 1, 0);
+ //glTranslatef(asp, 1, 0);
+
+
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_AUTO_NORMAL);
+ glEnable(GL_NORMALIZE);
+ glShadeModel(GL_SMOOTH);
+ //glShadeModel(GL_FLAT);
+
+
+ /* disable everything that is enabled in other modules
+ this resets the ogl state to its initial conditions */
+ glDisable(GL_LIGHTING);
+ for (i=0; i<8; i++) glDisable(GL_LIGHT0 + i);
+ glDisable(GL_COLOR_MATERIAL);
+
+
+}
+
+
+void pdp_3Dcontext_common_setup(void)
+{
+}
diff --git a/opengl/system/pdp_3Dcontext_glx.c b/opengl/system/pdp_3Dcontext_glx.c
new file mode 100644
index 0000000..ac25a13
--- /dev/null
+++ b/opengl/system/pdp_3Dcontext_glx.c
@@ -0,0 +1,393 @@
+
+/*
+ * OpenGL Extension Module for pdp - opengl system stuff
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* this file contains the platform dependent opengl setup routines (glx)
+ and pdp_packet_3Dcontext methods */
+
+#include "pdp_opengl.h"
+#include "pdp_xwindow.h"
+#include "pdp_internals.h"
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <GL/glu.h>
+//#include <GL/glut.h>
+
+/* all symbols are C-style */
+#ifdef __cplusplus
+//extern "C"
+//{
+#endif
+
+// this is buggy: disabled
+#define PRIVATE_CONTEXT 0
+
+
+/* structure to hold the (platform dependent) gl environment setup */
+typedef struct _gl_env
+{
+ bool initialized; /* data structure is consistent */
+
+ XVisualInfo *visual; /* the visual info structure for the context */
+ GLXContext context; /* the rendering context used to render to windows or pbufs */
+ GLXFBConfig *config; /* the framebuffer config object */
+
+ t_pdp_xdisplay *xdpy; /* pdp's x display object */
+
+ //Display *dpy; /* x display connection */
+ //int screen; /* x screen */
+ int last_context_packet; /* the packet that is currently rendered too (for caching) */
+} t_gl_env;
+
+static t_gl_env pdp_glx_env;
+static t_pdp_class *context_class;
+
+/* PDP_3DCONTEXT packet methods */
+
+/* set/unset ogl rendering context to pbuf */
+void pdp_packet_3Dcontext_set_rendering_context(int packet)
+{
+ t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
+
+
+ if (!c) return;
+
+
+ /* don't do a glx call if the context is still the same */
+ if (pdp_glx_env.last_context_packet == packet) return;
+
+ //post("new current context is %d", packet);
+
+
+ /* pbuffer */
+ switch(c->encoding){
+ case PDP_3DCONTEXT_WINDOW:
+ //glFinish();
+ //glXMakeCurrent(pdp_glx_env.dpy, ((t_pdp_xwindow *)c->drawable)->win, pdp_glx_env.context);
+ glXMakeCurrent(pdp_glx_env.xdpy->dpy, ((t_pdp_xwindow *)c->drawable)->win, (GLXContext)c->context);
+ pdp_glx_env.last_context_packet = packet;
+ break;
+ case PDP_3DCONTEXT_PBUFFER:
+ //glXMakeCurrent(pdp_glx_env.dpy, (GLXPbuffer)c->drawable, pdp_glx_env.context);
+ //glXMakeContextCurrent(c->dpy, c->drawable.pbuf, c->drawable.pbuf, c->context);
+ pdp_glx_env.last_context_packet = -1;
+ break;
+ default:
+ pdp_glx_env.last_context_packet = -1;
+ break;
+ }
+
+}
+
+void pdp_packet_3Dcontext_unset_rendering_context(int packet)
+{
+ t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
+ if (!c) return;
+
+ /* pbuffer */
+ switch(c->encoding){
+ case PDP_3DCONTEXT_WINDOW:
+ glXMakeCurrent(pdp_glx_env.xdpy->dpy, None, NULL);
+ pdp_glx_env.last_context_packet = -1;
+ break;
+ case PDP_3DCONTEXT_PBUFFER:
+ //glXMakeCurrent(pdp_glx_env.dpy, None, NULL);
+ //glXMakeContextCurrent(c->dpy, c->drawable.pbuf, c->drawable.pbuf, c->context);
+ break;
+ default:
+ break;
+ }
+}
+
+
+/* cons/des */
+static void _3Dcontext_clone(t_pdp *dst, t_pdp *src)
+{
+ post("ERROR: clone not supported for 3Dcontext packets");
+}
+
+static void _3Dcontext_copy(t_pdp *dst, t_pdp *src)
+{
+ post("ERROR: copy not supported for 3Dcontext packets");
+}
+
+static void _3Dcontext_reinit(t_pdp *dst)
+{
+ /* leave the packet as is */
+}
+static void _3Dcontext_cleanup(t_pdp *dst)
+{
+ t_3Dcontext *c = (t_3Dcontext *)(&dst->info.raw);
+
+ /* reset context packet cache, in case this packet was the current context. */
+ pdp_glx_env.last_context_packet = -1;
+
+ switch(c->encoding){
+ case PDP_3DCONTEXT_WINDOW:
+#if PRIVATE_CONTEXT
+ glXDestroyContext (pdp_glx_env.dpy, (GLXContext)c->context);
+#endif
+ pdp_xwindow_cleanup((t_pdp_xwindow *)c->drawable);
+ free(c->drawable);
+ break;
+
+ case PDP_3DCONTEXT_PBUFFER:
+ break;
+ //glXDestroyContext(c->dpy, c->context);
+ //glXDestroyPbuffer(c->dpy, c->drawable.pbuf);
+ default:
+ break;
+ }
+}
+
+
+/* setup packet methods */
+static void _3Dcontext_init_methods(t_pdp *header)
+{
+ header->theclass = context_class;
+ header->flags = PDP_FLAG_DONOTCOPY;
+}
+
+
+
+/* window specific methods */
+
+
+void _pdp_3Dcontext_set_window_size(t_3Dcontext *c, t_pdp_xwindow *xwin)
+{
+ c->width = xwin->winwidth;
+ c->sub_width = xwin->winwidth;
+ c->height = xwin->winheight;
+ c->sub_height= xwin->winheight;
+}
+
+/* resize the window */
+void pdp_packet_3Dcontext_win_resize(int packet, int width, int height)
+{
+ t_pdp_xwindow *xwin;
+ t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
+ if (!c) return;
+ if (PDP_3DCONTEXT_WINDOW != c->encoding) return;
+ xwin = (t_pdp_xwindow *)c->drawable;
+ pdp_xwindow_resize(xwin, width, height);
+ _pdp_3Dcontext_set_window_size(c, xwin);
+}
+
+
+t_pdp_list *pdp_packet_3Dcontext_win_get_eventlist(int packet)
+{
+ t_pdp_list *eventlist;
+ t_pdp_xwindow *xwin;
+ t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
+ if (!c) return 0;
+ if (PDP_3DCONTEXT_WINDOW != c->encoding) return 0;
+ xwin = (t_pdp_xwindow *)c->drawable;
+ eventlist = pdp_xwindow_get_eventlist(xwin);
+ _pdp_3Dcontext_set_window_size(c, xwin);
+ return eventlist;
+}
+
+void pdp_packet_3Dcontext_win_cursor(int packet, bool toggle)
+{
+ t_pdp_xwindow *xwin;
+ t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
+ if (!c) return;
+ if (PDP_3DCONTEXT_WINDOW != c->encoding) return;
+ xwin = (t_pdp_xwindow *)c->drawable;
+ pdp_xwindow_cursor(xwin, toggle);
+
+}
+
+void pdp_packet_3Dcontext_win_swapbuffers(int packet)
+{
+ t_pdp_xwindow *xwin;
+ t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
+ if (!c) return;
+ if (PDP_3DCONTEXT_WINDOW != c->encoding) return;
+ xwin = (t_pdp_xwindow *)c->drawable;
+ glXSwapBuffers(xwin->xdisplay->dpy,xwin->win);
+ //glFinish();
+
+}
+
+
+/* constructors */
+
+/* construct (or reuse) a window packet */
+int pdp_packet_new_3Dcontext_win(void)
+{
+ /* $$$FIXME: this assumes packet can't be reused */
+ int p = pdp_packet_new(PDP_3DCONTEXT, 0);
+ t_pdp_xwindow *xwin;
+ t_3Dcontext *c;
+ t_pdp *header = pdp_packet_header(p);
+ if (!header) return -1; /* pool full ? */
+ c = (t_3Dcontext *)&header->info.raw;
+
+ if (c->drawable){
+ xwin = (t_pdp_xwindow *)c->drawable;
+ }
+ else{
+ xwin = (t_pdp_xwindow *)malloc(sizeof(*xwin));
+ }
+
+ pdp_xwindow_init(xwin);
+ pdp_xwindow_create_on_display(xwin, pdp_glx_env.xdpy);
+
+ /* init subheader */
+#if PRIVATE_CONTEXT
+ if (NULL == (c->context = (void *)glXCreateContext(pdp_glx_env.dpy, pdp_glx_env.visual, pdp_glx_env.context, True))){
+ post("pdp_packet_new_3Dcontext_wind: ERROR: can't create rendering context");
+ }
+#else
+ c->context = (void *)pdp_glx_env.context;
+#endif
+ c->drawable = xwin;
+ c->encoding = PDP_3DCONTEXT_WINDOW;
+ _pdp_3Dcontext_set_window_size(c, xwin);
+
+ /* init packet methods */
+ _3Dcontext_init_methods(header);
+
+ /* init header */
+ header->desc = pdp_gensym("3Dcontext/window");
+ header->flags = PDP_FLAG_DONOTCOPY;
+
+ return p;
+
+
+}
+
+/* pbuf constructor */
+int pdp_packet_new_3Dcontext_pbuf(u32 width, u32 height, u32 depth)
+{
+ post("ERROR: 3Dcontext/pbuffer packets not implemented");
+ return -1;
+}
+
+
+/* this is a notifier sent when the processing thread which
+ executes gl commands is changed. we need to release the current context
+ before another thread can take it. */
+void pdp_3Dcontext_prepare_for_thread_switch(void)
+{
+ pdp_packet_3Dcontext_unset_rendering_context(pdp_glx_env.last_context_packet);
+}
+
+
+
+
+
+/* setup routine */
+static void pdp_3Dcontext_glx_setup_inthread(void)
+{
+ /* this opens the connection to the x server and creates a render context
+ for windows (glx < 1.3) or windows/pbufs (glx >= 1.3) */
+
+ static int dblBuf24[] = {GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_ALPHA_SIZE, 0,
+ GLX_DEPTH_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None};
+
+ pdp_glx_env.initialized = 0;
+
+
+ /* init xlib for thread usage */
+ if (!XInitThreads()){
+ post("pdp_opengl_system_setup: can't init Xlib for thread usage.");
+ goto init_failed;
+ }
+
+
+ /* open display:
+ the first display on the local machine is opened, not DISPLAY.
+ since pdp_opengl is all about direct rendering, and there
+ is no way to specify another display, or even close it and
+ open it again, this seems to be the "least surprise" solution.
+ it enables the pd interface to be displayed on another display,
+ using the DISPLAY environment variable. */
+
+
+
+
+
+ if (NULL == (pdp_glx_env.xdpy = pdp_xdisplay_new(":0"))){
+ post("pdp_opengl_system_setup: can't open display");
+ goto init_failed;
+ }
+
+
+ /* get visual */
+ if (NULL == (pdp_glx_env.visual = glXChooseVisual(pdp_glx_env.xdpy->dpy, pdp_glx_env.xdpy->screen, dblBuf24))){
+ post("pdp_opengl_system_setup: can't find appropriate visual");
+ goto init_failed_close_dpy;
+ }
+
+
+ /* create a (direct) rendering context */
+ if (NULL == (pdp_glx_env.context = glXCreateContext(pdp_glx_env.xdpy->dpy, pdp_glx_env.visual, 0, True))){
+ post("pdp_opengl_system_setup: can't create rendering context");
+ goto init_failed_close_dpy;
+ }
+
+
+ //post("pdp_opengl_system_setup: pdp_opengl init OK.");
+ pdp_glx_env.last_context_packet = -1;
+ pdp_glx_env.initialized = 1;
+
+ /* setup class object */
+ context_class = pdp_class_new(pdp_gensym("3Dcontext/*"), 0);
+ context_class->cleanup = _3Dcontext_cleanup;
+ context_class->wakeup = _3Dcontext_reinit;
+ //context_class->clone = _3Dcontext_clone;
+ context_class->copy = _3Dcontext_copy;
+
+
+ /* setup conversion programs: NOT IMPLEMENTED */
+ return;
+
+
+ init_failed_close_dpy:
+ pdp_xdisplay_free(pdp_glx_env.xdpy);
+ pdp_glx_env.xdpy = 0;
+ init_failed:
+ post("pdp_opengl_system_setup: FATAL ERROR: pdp_opengl init failed.");
+ exit(1);
+
+}
+
+/* run the setup routine in the procqueue thread, and wait for it to finish */
+/* NOTE: this seems to make an Xlib deadlock problem go away when running
+ pd with realtime scheduling. frankly, i'm very puzzled by this problem
+ and even more by the way this workaround solves it. anyhow... */
+void pdp_3Dcontext_glx_setup(void)
+{
+ t_pdp_procqueue *q = pdp_opengl_get_queue();
+ pdp_procqueue_add(q, 0, pdp_3Dcontext_glx_setup_inthread, 0, 0);
+ pdp_procqueue_flush(q);
+}
+
+#ifdef __cplusplus
+//}
+#endif
diff --git a/opengl/system/pdp_3dp_base.c b/opengl/system/pdp_3dp_base.c
new file mode 100644
index 0000000..5190c11
--- /dev/null
+++ b/opengl/system/pdp_3dp_base.c
@@ -0,0 +1,30 @@
+#include "pdp_opengl.h"
+#include "pdp_3dp_base.h"
+
+#define THIS(b) t_pdp_3pd_base *b = (t_pdp_3pd_base *)x
+
+/* destructor */
+void pdp_3dp_base_free(void *x)
+{
+ // free super
+ pdp_dpd_base_free(x);
+}
+
+/* init method */
+void pdp_3dp_base_init(void *x)
+{
+ // init super
+ pdp_dpd_base_init(x);
+
+ // set processing queue to pdp_opengl system queue
+ pdp_dpd_base_set_queue(x, pdp_opengl_get_queue());
+
+}
+
+/* class setup method */
+void pdp_3dp_base_setup(t_class *class)
+{
+ // setup super
+ pdp_dpd_base_setup(class);
+}
+
diff --git a/opengl/system/pdp_mesh.c b/opengl/system/pdp_mesh.c
new file mode 100644
index 0000000..b319d1e
--- /dev/null
+++ b/opengl/system/pdp_mesh.c
@@ -0,0 +1,560 @@
+/*
+ * Pure Data Packet module. mesh implementation
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* a very naive approach to triangular meshes */
+
+
+// $$TODO: some serious memory corruption in this file our the list implementation
+
+
+#include <math.h>
+
+#include "pdp.h"
+#include "pdp_mesh.h"
+
+
+/* VERTEX methods */
+void vertex_add_triangle(t_vertex *v, t_triangle *t)
+{
+ pdp_list_add_pointer(v->trilist, t);
+}
+void vertex_remove_triangle(t_vertex *v, t_triangle *t)
+{
+ pdp_list_remove_pointer(v->trilist, t);
+}
+void vertex_add_neighbour(t_vertex *v, t_vertex *neighbour)
+{
+ pdp_list_add_pointer_to_set(v->vertlist, neighbour);
+};
+
+
+/* constructor/destructors are "private"
+ they may only be called by the mesh object to ensure
+ the vector list stays sound (i.e. without duplicates) */
+void _vertex_free(t_vertex *v)
+{
+ if (!v->trilist) post("WARNING: vertex %x has empty trilist", v);
+ else{
+ pdp_list_free(v->trilist);
+ v->trilist = 0;
+ }
+ if (!v->vertlist) post("WARNING: vertex %x has empty vertlist", v);
+ {
+ pdp_list_free(v->vertlist);
+ v->vertlist = 0;
+ }
+ pdp_dealloc(v);
+}
+
+t_vertex *_vertex_new(float *c, float *n)
+{
+ int k;
+ t_vertex *v = (t_vertex *) pdp_alloc(sizeof(t_vertex));
+ I3(k) v->c[k] = c[k];
+ I3(k) v->n[k] = n[k];
+ v->trilist = pdp_list_new(0);
+ v->vertlist = pdp_list_new(0);
+ return v;
+}
+
+
+void vertex_compute_normal_random(t_vertex *v){int k; I3(k) v->n[k] = _rand();}
+void vertex_compute_normal_sphere(t_vertex *v){int k; I3(k) v->n[k] = v->c[k];}
+void vertex_compute_normal_prism(t_vertex *v)
+{
+ float scale = 0.0f;
+ float sum[] = {0.0f, 0.0f, 0.0f};
+ int k;
+ t_pdp_atom* i;
+ t_pdp_list *vl = v->vertlist;
+ t_vertex *vtx;
+
+ PDP_POINTER_IN(vl, i, vtx) {
+ I3(k) sum[k] += vtx->c[k];
+ scale = scale + 1.0f;
+ }
+ scale = 1.0f / scale;
+ I3(k) sum[k] *= scale;
+ I3(k) v->n[k] = v->c[k] - sum[k];
+
+ //post("computed normal (%f, %f, %f) of vertex (%f, %f, %f)", v->n[0], v->n[1], v->n[2], v->c[0], v->c[1], v->c[2]);
+};
+void vertex_compute_normal_average(t_vertex *v)
+{
+ int triangles = pdp_list_size(v->trilist);
+ float scale = 1.0f / ((float)triangles);
+ t_pdp_atom* i;
+ int k;
+ t_triangle *t;
+
+ I3(k) v->n[k] = 0; //reset normal
+ PDP_POINTER_IN(v->trilist, i, t){
+ I3(k) v->n[k] += t->n[k];
+ }
+ _vector3_scale(v->n, scale);
+
+
+}
+
+
+float vertex_normalize(t_vertex *v)
+{
+ return _vector3_normalize(v->c);
+}
+
+
+/* TRIANGLE methods */
+
+/* create triangle (a connection between 3 vertices):
+ counterclockwize with facing front
+ this method is "private"
+ you can only create triangles as part of a mesh */
+t_triangle *_triangle_new(t_vertex *v0, t_vertex *v1, t_vertex *v2)
+{
+ int k;
+
+ t_triangle *t = (t_triangle *)pdp_alloc(sizeof(t_triangle));
+
+ /* store vertex references */
+ t->v[0] = v0;
+ t->v[1] = v1;
+ t->v[2] = v2;
+
+ /* reset median vertices */
+ I3(k) t->m[k] = 0;
+
+ /* connect triangle to vertices */
+ vertex_add_triangle(v0, t);
+ vertex_add_triangle(v1, t);
+ vertex_add_triangle(v2, t);
+
+ /* connect vertices to vertices */
+ vertex_add_neighbour(v0, v1);
+ vertex_add_neighbour(v0, v2);
+ vertex_add_neighbour(v1, v0);
+ vertex_add_neighbour(v1, v2);
+ vertex_add_neighbour(v2, v0);
+ vertex_add_neighbour(v2, v1);
+
+ return t;
+}
+
+/* delete a triangle, disconnecting the vertices */
+void _triangle_free(t_triangle *t)
+{
+ int k;
+
+ /* remove the triangle reference of the vertices */
+ I3(k) vertex_remove_triangle(t->v[k], t);
+
+ /* set references to zero (bug catcher) */
+ I3(k) t->v[k] = 0;
+ I3(k) t->m[k] = 0;
+
+ /* free struct */
+ pdp_dealloc(t);
+
+}
+
+/* get triangle that shares the link between v0 and v1 */
+t_triangle *triangle_neighbour(t_triangle *t, t_vertex *v0, t_vertex *v1)
+{
+ t_pdp_atom* it;
+ t_triangle *tri;
+ PDP_POINTER_IN(v1->trilist, it, tri){
+ if (tri != t && pdp_list_contains_pointer(v0->trilist, tri)) return tri;
+ }
+ return 0;
+}
+
+/* add a median vector to a link in a triangle
+ note: vertices must be in triangle, or behaviour is undefined */
+void triangle_add_median(t_triangle *t, t_vertex *v0, t_vertex *v1, t_vertex *median)
+{
+
+ /* link 0 1 */
+ if (!((v0 == t->v[2]) || (v1 == t->v[2]))) t->m[0] = median;
+
+ /* link 1 2 */
+ else if (!((v0 == t->v[0]) || (v1 == t->v[0]))) t->m[1] = median;
+
+ /* link 2 0 */
+ else t->m[2] = median;
+}
+
+void triangle_compute_normal(t_triangle *t)
+{
+ int k;
+ float v0[3];
+ float v1[3];
+ I3(k) v0[k] = t->v[1]->c[k] - t->v[0]->c[k];
+ I3(k) v1[k] = t->v[2]->c[k] - t->v[0]->c[k];
+ _vector3_cross(v0,v1,t->n);
+}
+
+void triangle_compute_unit_normal(t_triangle *t)
+{
+ triangle_compute_normal(t);
+ _vector3_normalize(t->n);
+}
+
+/* MESH methods */
+
+/* add and remove methods for vertices and triangles */
+t_vertex *mesh_vertex_add(t_mesh *m, float *c, float *n)
+{
+ t_vertex *v = _vertex_new(c, n);
+ pdp_list_add_pointer(m->vertices, v);
+ return v;
+}
+
+void mesh_vertex_remove(t_mesh *m, t_vertex *v)
+{
+ pdp_list_remove_pointer(m->vertices, v);
+ _vertex_free(v);
+}
+
+t_triangle *mesh_triangle_add(t_mesh *m, t_vertex *v0, t_vertex *v1, t_vertex *v2)
+{
+ t_triangle *t = _triangle_new(v0,v1,v2);
+ pdp_list_add_pointer(m->triangles, t);
+ return t;
+}
+
+void mesh_triangle_remove(t_mesh *m, t_triangle *t)
+{
+ pdp_list_remove_pointer(m->triangles, t);
+ _triangle_free(t);
+}
+
+/* calculate normals */
+void mesh_calculate_normals(t_mesh *m)
+{
+ t_pdp_atom* it;
+ t_pdp_atom* it_tri;
+ t_pdp_list *l = m->vertices;
+ t_pdp_list *l_tri = m->triangles;
+ t_vertex *v;
+ t_triangle *t;
+ //while (v = pdp_list_getnext_pointer(l, &it)) vertex_compute_normal_sphere(v);
+ switch(m->normal_type){
+ default:
+ case MESH_NORMAL_SPHERE: PDP_POINTER_IN(l, it, v) vertex_compute_normal_sphere(v); break;
+ case MESH_NORMAL_PRISM: PDP_POINTER_IN(l, it, v) vertex_compute_normal_prism(v); break;
+ case MESH_NORMAL_RANDOM: PDP_POINTER_IN(l, it, v) vertex_compute_normal_random(v); break;
+ case MESH_NORMAL_AVERAGE:
+ PDP_POINTER_IN(l_tri, it_tri, t) triangle_compute_unit_normal(t);
+ PDP_POINTER_IN(l, it, v) vertex_compute_normal_average(v);
+ break;
+ }
+}
+
+/* split a triangle in 4, using the intermedia median vertex storage */
+void mesh_split_four(t_mesh *m, t_triangle *old_t)
+{
+ int k;
+ t_vertex *v[6];
+
+ /* some intermediates */
+ t_triangle *neighbour;
+ t_float newv[] = {0,0,0};
+ t_float nullvect[] = {0,0,0};
+
+
+ /* get main vertices */
+ I3(k) v[k] = old_t->v[k];
+
+ /* get median vertices inserted by neighbouring triangles */
+ I3(k) v[k+3] = old_t->m[k];
+
+#define GET_MEDIAN(v, v0, v1) \
+ if (!v){ \
+ I3(k) newv[k] = 0.5f * (v0->c[k] + v1->c[k]); \
+ v = mesh_vertex_add(m, newv, nullvect); \
+ /*vertex_normalize(v);*/ \
+ if (neighbour = triangle_neighbour(old_t, v0, v1)){ \
+ triangle_add_median(neighbour, v0, v1, v); \
+ } \
+ }
+
+ GET_MEDIAN(v[3], v[0], v[1])
+ GET_MEDIAN(v[4], v[1], v[2])
+ GET_MEDIAN(v[5], v[2], v[0])
+
+#undef GET_MEDIAN
+
+ /* remove the old triangle */
+ mesh_triangle_remove(m, old_t);
+
+ /* create 4 new triangles */
+ mesh_triangle_add(m, v[0], v[3], v[5]);
+ mesh_triangle_add(m, v[1], v[4], v[3]);
+ mesh_triangle_add(m, v[2], v[5], v[4]);
+ mesh_triangle_add(m, v[3], v[4], v[5]);
+
+}
+
+/* split a triangle in 3 */
+void mesh_split_three(t_mesh *m, t_triangle *old_t)
+{
+ int k, l;
+ t_vertex *v[4];
+ t_float newv[] = {0,0,0};
+ t_float nullvect[] = {0,0,0};
+
+ /* get vertices */
+ I3(k) v[k] = old_t->v[k];
+
+ /* remove a triangle */
+ mesh_triangle_remove(m, old_t);
+
+ /* compute new vertex coordinates */
+ I3(k) I3(l) newv[k] += 0.33333f * v[l]->c[k];
+
+ /* create new vertex */
+ v[3] = mesh_vertex_add(m, newv, nullvect);
+ //vertex_normalize(v[3]);
+
+ /* create 3 new triangles */
+ mesh_triangle_add(m, v[0], v[1], v[3]);
+ mesh_triangle_add(m, v[1], v[2], v[3]);
+ mesh_triangle_add(m, v[2], v[0], v[3]);
+
+}
+
+
+
+void mesh_split_all_four(t_mesh *m)
+{
+ t_triangle *t;
+ t_pdp_list *l = pdp_list_copy(m->triangles);
+
+ //post("split_all_four: nb triangles %d", pdp_list_size(m->triangles));
+
+ while (l->elements){
+ t = pdp_list_pop(l).w_pointer;
+ mesh_split_four(m, t);
+ }
+ mesh_calculate_normals(m);
+ pdp_list_free(l);
+}
+
+
+void mesh_split_all_three(t_mesh *m)
+{
+ t_triangle *t;
+ t_pdp_list *l = pdp_list_copy(m->triangles);
+
+ //post("split_all_three: nb triangles %d", pdp_list_size(m->triangles));
+
+ while (l->elements){
+ t = pdp_list_pop(l).w_pointer;
+ mesh_split_three(m, t);
+ }
+ mesh_calculate_normals(m);
+ pdp_list_free(l);
+}
+
+void mesh_split_random_three(t_mesh *m)
+{
+ int size = pdp_list_size(m->triangles);
+ t_triangle *t = pdp_list_index(m->triangles, (random() % size)).w_pointer;
+ mesh_split_three(m, t);
+ mesh_calculate_normals(m);
+}
+
+
+
+void mesh_free(t_mesh *m)
+{
+ t_pdp_list *l;
+ t_triangle *t;
+ t_vertex *v;
+
+ /* delete all triangles */
+ while (m->triangles->elements){
+ t = pdp_list_pop(m->triangles).w_pointer;
+ //post("freeing triangle %x", t);
+ _triangle_free(t);
+ }
+ pdp_list_free(m->triangles);
+ m->triangles = 0;
+
+ /* delete all vertices */
+ while (m->vertices->elements){
+ v = pdp_list_pop(m->vertices).w_pointer;
+ //post("freeing vertex %x", v);
+ _vertex_free(v);
+ }
+ pdp_list_free(m->vertices);
+ m->vertices = 0;
+
+ pdp_dealloc(m);
+
+}
+
+
+t_mesh *_mesh_new(void)
+{
+ t_mesh *m = (t_mesh *)pdp_alloc(sizeof(t_mesh));
+
+ /* create main vertex and triangle lists */
+ m->triangles = pdp_list_new(0);
+ m->vertices = pdp_list_new(0);
+
+ /* set normal type */
+ m->normal_type = MESH_NORMAL_PRISM;
+
+ return m;
+}
+
+/* init tetra */
+t_mesh *mesh_new_tetra(void)
+{
+ int k;
+ t_triangle *t[4];
+ t_vertex *v[4];
+ t_pdp_atom* it;
+ t_triangle *tri;
+ t_mesh *m = _mesh_new();
+
+ float n[] = {0,0,0};
+ float fv[4][3] = {{2,0,0},{0,2,0},{0,0,2}, {-1,-1,-1}};
+
+ /* add vertices */
+ I4(k) v[k] = mesh_vertex_add(m, &fv[k][0], n);
+ I4(k) vertex_normalize(v[k]);
+
+ /* add triangles */
+ mesh_triangle_add(m, v[0], v[1], v[2]);
+ mesh_triangle_add(m, v[1], v[0], v[3]);
+ mesh_triangle_add(m, v[0], v[2], v[3]);
+ mesh_triangle_add(m, v[1], v[3], v[2]);
+
+
+ /* compute normals */
+ mesh_calculate_normals(m);
+
+ return m;
+}
+
+
+void _mesh_relax_compute_resultant_spring(t_mesh *m, float *center, float d0, float r0)
+{
+ int k;
+ t_pdp_atom *i, *j;
+ t_vertex *v, *w;
+
+ PDP_POINTER_IN(m->vertices, i, v){
+ float scale = 0.0f;
+ float r;
+
+ /* compute contribution of origin link */
+ I3(k) v->n[k] = v->c[k] - center[k];
+ r = _vector3_normalize(v->n);
+ I3(k) v->n[k] *= (r0 - r);
+
+ PDP_POINTER_IN(v->vertlist, j, w){
+ int k;
+ float f[3];
+ float d, l;
+
+ /* compute force contribution of one link (model: spring with rest length == d0) */
+ I3(k) f[k] = w->c[k] - v->c[k]; // PC: f == distance vector
+ d = _vector3_normalize(f); // PC: d == distance, vector == unit norm
+ I3(k) v->n[k] += (d - d0) * f[k]; // PC: n == n_prev + fource resultant
+ }
+ }
+}
+
+void _mesh_relax_apply_force(t_mesh *m, float k)
+{
+ t_pdp_atom* it;
+ t_vertex *v;
+
+ PDP_POINTER_IN(m->vertices, it, v){
+ int i;
+ /* apply fource vector with step */
+ I3(i) v->c[i] += k * v->n[i];
+ }
+
+}
+
+void mesh_compute_center(t_mesh *m, float *c)
+{
+ t_pdp_atom*(it);
+ t_vertex *v;
+ float scale;
+ int k;
+
+ I3(k) c[k] = 0;
+ PDP_POINTER_IN(m->vertices, it, v){
+ I3(k) c[k] += v->c[k];
+ }
+ scale = 1.0f / ((float)pdp_list_size(m->vertices));
+ I3(k) c[k] *= scale;
+
+}
+
+void mesh_translate(t_mesh *m, float *c)
+{
+ t_pdp_atom *it;
+ t_vertex *v;
+ int k;
+
+ PDP_POINTER_IN(m->vertices, it, v){
+ I3(k) v->c[k] += c[k];
+ }
+}
+
+/* relax a mesh (move toward equal link length) */
+void mesh_relax(t_mesh *m, float step, float d0, float r0)
+{
+ int k;
+ float c[3];
+ mesh_compute_center(m, c);
+ I3(k) c[k] = -c[k];
+ mesh_translate(m, c);
+ I3(k) c[k] = 0;
+ _mesh_relax_compute_resultant_spring(m, c, d0, r0); /* compute force resultant */
+ _mesh_relax_apply_force(m, step); /* apply "time step towards desired distance" */
+ mesh_calculate_normals(m); /* restore normals */
+}
+
+
+
+/* print some debug information */
+void mesh_debug(t_mesh *m)
+{
+ int k;
+ int boundary_edges = 0;
+ t_pdp_atom* it;
+ t_triangle *t;
+ post("mesh info");
+ post("\tnumber of vertices = %d", pdp_list_size(m->vertices));
+ post("\tnumber of triangles = %d", pdp_list_size(m->triangles));
+
+ PDP_POINTER_IN(m->triangles, it, t){
+ I3(k) if (!triangle_neighbour(t, t->v[k], t->v[(k+1)%3])) boundary_edges++;
+ }
+ post("\tnumber of boundaray edges = %d", boundary_edges);
+
+
+}
diff --git a/opengl/system/pdp_opengl.c b/opengl/system/pdp_opengl.c
new file mode 100644
index 0000000..541af75
--- /dev/null
+++ b/opengl/system/pdp_opengl.c
@@ -0,0 +1,76 @@
+
+/*
+ * OpenGL Extension Module for pdp - opengl system stuff
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "pdp.h"
+#include "pdp_control.h"
+
+#define PDP_3DP_QUEUE_LOGSIZE 16
+#define PDP_3DP_QUEUE_DELTIME 1.0f
+
+
+
+void pdp_3Dcontext_prepare_for_thread_switch(void *);
+static t_pdp_procqueue _3dp_queue;
+
+
+static void pdp_control_thread(void *x, t_symbol *s, int argc, t_atom *argv)
+{
+ int t = 0;
+ float f;
+ if (argc != 1) return;
+ if (argv[0].a_type != A_FLOAT) return;
+ f = argv[0].a_w.w_float;
+ t = (f != 0.0f);
+ post("3dp thread switched %s", t ? "on":"off");
+
+
+ /* when we switch threads, the glx system needs to be notified
+ because it has to release the render context. this is done
+ in a process method, so it is run in the correct thread. */
+
+
+ pdp_procqueue_add(&_3dp_queue, 0, pdp_3Dcontext_prepare_for_thread_switch, 0, 0);
+ pdp_procqueue_wait(&_3dp_queue);
+
+
+ /* fresh start: enable/disable the thread dispatching */
+ pdp_procqueue_use_thread(&_3dp_queue, t);
+
+}
+
+/* kernel setup */
+void pdp_opengl_system_setup(void)
+{
+ /* init the 3dp queue */
+ pdp_procqueue_init(&_3dp_queue, PDP_3DP_QUEUE_DELTIME, PDP_3DP_QUEUE_LOGSIZE);
+
+ /* scheduler uses the thread */
+ pdp_procqueue_use_thread(&_3dp_queue, 1);
+ //pdp_procqueue_use_thread(&_3dp_queue, 0); //DEBUG: disable 3dp thread
+
+ /* add pdp_control method for thread */
+ pdp_control_addmethod((t_method)pdp_control_thread, gensym("3dthread"));
+}
+
+t_pdp_procqueue* pdp_opengl_get_queue(void){return (&_3dp_queue);}
+
+
+
diff --git a/opengl/system/pdp_texture.c b/opengl/system/pdp_texture.c
new file mode 100644
index 0000000..8bc7b21
--- /dev/null
+++ b/opengl/system/pdp_texture.c
@@ -0,0 +1,541 @@
+/*
+ * OpenGL Extension Module for pdp - texture packet implementation
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/* this modules implemtents the opengl texture packet
+ it contains only portable opengl code */
+
+#include <stdio.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include "pdp_opengl.h"
+#include "pdp_texture.h"
+#include "pdp_dpd_command.h"
+
+
+static t_pdp_class *texture_class;
+
+static t_pdp_dpd_commandfactory _tex_cf;
+
+typedef struct _texture_command
+{
+ t_pdp_dpd_command base;
+ int p_src;
+ int p_dst;
+} t_texture_command;
+
+
+/* all symbols are C-style */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+/* returns a pointer to the packet subheader given the pdp header */
+static t_texture *_pdp_tex_info(t_pdp *x)
+{
+ return (t_texture *)&(x->info.raw);
+}
+
+
+/* create a pow of 2 texture dimension, ge than 8 */
+static int _round_to_pow_2(int n){
+ int r = 8;
+ while (n > r) r <<= 1;
+ return r;
+}
+
+t_pdp_symbol *_pdp_get_tex_description_from_params(GLsizei width, GLsizei height, GLint format)
+{
+ char description[1024];
+ char *c = description;
+
+ c += sprintf(c, "texture");
+ switch(format){
+ case GL_LUMINANCE: c += sprintf(c, "/grey"); break;
+ case GL_RGB: c += sprintf(c, "/rgb"); break;
+ case GL_RGBA: c += sprintf(c, "/rgba"); break;
+ default:
+ c += sprintf(c, "/unknown"); goto exit;
+ }
+ c += sprintf(c, "/%dx%d", width, height);
+
+ exit:
+ return pdp_gensym(description);
+}
+
+t_pdp_symbol *_pdp_tex_get_description(t_pdp *header)
+{
+ t_texture *texture = _pdp_tex_info(header);
+ int encoding;
+
+ if (!header) return pdp_gensym("invalid");
+ else if (!header->desc){
+ if (header->type == PDP_TEXTURE){
+ /* if description is not defined, try to construct it */
+ return _pdp_get_tex_description_from_params(texture->width, texture->height, texture->format);
+ }
+ else return pdp_gensym("unknown");
+ }
+ else return header->desc;
+}
+
+
+static int _pdp_packet_texture_old_or_dummy(u32 width, u32 height, s32 format);
+static void _pdp_packet_gentexture(int packet);
+
+static void texture_command_convert_bitmap_to_texture(t_texture_command *c)
+{
+ t_texture *t = (t_texture *)pdp_packet_subheader(c->p_dst);
+
+ /* make sure packet contains a texture, since it is created with _pdp_packet_reuse_texture */
+ _pdp_packet_gentexture(c->p_dst);
+
+ /* flip source image before uploading */
+ pdp_packet_bitmap_flip_top_bottom(c->p_src);
+
+ /* fill texture */
+ pdp_packet_texture_make_current(c->p_dst);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, t->sub_width, t->sub_height,
+ t->format, GL_UNSIGNED_BYTE, (char *)pdp_packet_data(c->p_src));
+
+ /* decrease refcount */
+ pdp_packet_mark_unused(c->p_src);
+ pdp_packet_mark_unused(c->p_dst);
+
+ //post("conversion done");
+ pdp_dpd_command_suicide(c);
+}
+
+
+/* converters to standard pdp types */
+int _pdp_packet_texture_convert_image_to_texture(int packet, t_pdp_symbol *dest_template)
+{
+ int p_temp, p;
+
+ //post ("converting to bitmap");
+ p_temp = pdp_packet_convert_rw(packet, pdp_gensym("bitmap/*/*"));
+ if (p_temp == -1) return -1;
+
+ //post ("converting to texture");
+ p = pdp_packet_convert_rw(p_temp, pdp_gensym("texture/*/*"));
+ pdp_packet_mark_unused(p_temp);
+ return p;
+}
+
+
+
+/* converters to standard pdp types */
+int _pdp_packet_texture_convert_bitmap_to_texture(int packet, t_pdp_symbol *dest_template)
+{
+ t_pdp *header = pdp_packet_header(packet);
+ void *data = pdp_packet_data (packet);
+ int new_p;
+ u32 w;
+ u32 h;
+ t_texture_command *c;
+
+ if (!pdp_packet_bitmap_isvalid(packet)) return -1;
+
+ w = header->info.image.width;
+ h = header->info.image.height;
+
+ switch (header->info.image.encoding){
+ case PDP_BITMAP_GREY:
+ /* create greyscale texture */
+ new_p = _pdp_packet_texture_old_or_dummy(w,h, GL_LUMINANCE);
+ break;
+ case PDP_BITMAP_RGB:
+ /* create rgb texture */
+ new_p = _pdp_packet_texture_old_or_dummy(w,h, GL_RGB);
+ break;
+ case PDP_BITMAP_RGBA:
+ /* create greyscale texture */
+ new_p = _pdp_packet_texture_old_or_dummy(w,h, GL_RGBA);
+ break;
+ default:
+ new_p = -1;
+ break;
+ }
+
+ if (new_p != -1){
+
+ /* remark: this is a hack. a texture has to be created
+ when a rendering context is active. this means it has
+ to be created in the correct thread. therefore a dpd
+ command is added to the 3dp queue. this seems to work,
+ but without a dropping mechanism, this can overload the
+ queue. the real solution would be to add a converter
+ object to a 3dp chain, or to accept image or bitmap
+ packets in 3dp objects */
+
+
+ /* dispatch command */
+ c = (t_texture_command *)pdp_dpd_commandfactory_get_new_command(&_tex_cf);
+ c->p_src = pdp_packet_copy_rw(packet);
+ c->p_dst = pdp_packet_copy_ro(new_p);
+ pdp_procqueue_add(pdp_opengl_get_queue(), c, texture_command_convert_bitmap_to_texture, 0, 0);
+ }
+ return new_p;
+
+}
+
+
+
+int _pdp_packet_texture_convert_texture_to_bitmap(int packet, t_pdp_symbol *dest_template0)
+{
+ post("_pdp_packet_texture_convert_texture_to_bitmap not implemented.");
+ return -1;
+}
+
+
+t_texture *pdp_packet_texture_info(int packet)
+{
+ t_pdp *header = pdp_packet_header(packet);
+ if (pdp_packet_texture_isvalid(packet)) return _pdp_tex_info(header);
+ else return 0;
+}
+
+/* check if valid texture packet. all other methods assume packet is valid */
+int pdp_packet_texture_isvalid(int packet)
+{
+ t_pdp *header;
+ if (!(header = pdp_packet_header(packet))) return 0;
+ if (PDP_TEXTURE != header->type) return 0;
+ return glIsTexture(_pdp_tex_info(header)->tex_obj);
+}
+
+
+
+static void _tex_init_obj(t_texture *t)
+{
+ //u8 *dummydata;
+ //int i;
+
+ glBindTexture(GL_TEXTURE_2D, t->tex_obj);
+ glTexImage2D(GL_TEXTURE_2D, 0, t->format, t->width, t->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+
+ /* debug
+ dummydata = (u8 *)malloc(t->width*t->height*4);
+ for (i=0; i<t->width*t->height*4; i++){dummydata[i] = random(); }
+ glTexImage2D(GL_TEXTURE_2D, 0, t->format, t->width, t->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, dummydata);
+ free(dummydata);
+ */
+
+}
+
+
+static void _pdp_tex_copy(t_pdp *dst, t_pdp *src);
+static void _pdp_tex_clone(t_pdp *dst, t_pdp *src);
+static void _pdp_tex_reinit(t_pdp *dst);
+static void _pdp_tex_cleanup(t_pdp *dst);
+
+static void _pdp_tex_init_methods(t_pdp *h)
+{
+ h->theclass = texture_class;
+}
+
+static void _pdp_tex_reinit(t_pdp *dst)
+{
+ /* this does nothing. texture is assumed to be in a valid state */
+}
+static void _pdp_tex_clone(t_pdp *dst, t_pdp *src)
+{
+ t_texture *dst_t = _pdp_tex_info(dst);
+ t_texture *src_t = _pdp_tex_info(src);
+
+ //post("WARNING: _pdp_tex_clone: should not be called from outside 3d thread");
+
+ /* determine if destination texture is valid */
+ if (glIsTexture(dst_t->tex_obj)){
+ /* check format */
+ if ((dst_t->width >= src_t->width)
+ && (dst_t->height >= src_t->height)
+ && (dst_t->format == src_t->format)){
+ dst_t->sub_width = src_t->sub_width;
+ dst_t->sub_height = src_t->sub_height;
+ return;
+ }
+ }
+ /* not initialized, so we need to create a new one */
+ else {
+ glGenTextures(1, (GLuint*)&dst_t->tex_obj);
+ }
+
+ /* setup header */
+ dst_t->width = src_t->width;
+ dst_t->height = src_t->height;
+ dst_t->format = src_t->format;
+ dst_t->sub_width = src_t->sub_width;
+ dst_t->sub_height = src_t->sub_height;
+
+ /* setup packet methods */
+ _pdp_tex_init_methods(dst);
+
+ /* init description */
+ dst->desc = _pdp_tex_get_description(dst);
+
+}
+static void _pdp_tex_copy(t_pdp *dst, t_pdp *src)
+{
+ /* texture copying is inefficient. for the tex extensions there is no analogy
+ for "efficient in-place processing"
+ this means the pdp_packet_register_rw() call should be avoided
+ this inconsistency should be tucked away in a texture base class */
+
+ /* todo: use texture combining extensions for this */
+
+ post("WARNING: fanout is not yet implemented correctly for texture packets");
+
+ /* not implemented yet, just a call to the clone method */
+ _pdp_tex_clone(dst, src);
+}
+
+static void _pdp_tex_cleanup(t_pdp *dst)
+{
+ t_texture *t = _pdp_tex_info(dst);
+ glDeleteTextures(1, (GLuint*)&t->tex_obj);
+ t->tex_obj = -1; /* is this value guaranteed to be invalid? */
+}
+
+
+/* texture constructors */
+
+/* reuse a texture, or create a "dummy" == packet with everything except a valid texture object */
+static int _pdp_packet_texture_old_or_dummy(u32 width, u32 height, s32 format)
+{
+ int p = -1;
+ t_pdp *h;
+ t_texture *t;
+
+ int p2_w = _round_to_pow_2(width);
+ int p2_h = _round_to_pow_2(height);
+
+
+ /* try to reuse a texture packet or get a new one */
+ p = pdp_packet_reuse(_pdp_get_tex_description_from_params(p2_w, p2_h, format));
+ if (-1 == p) p = pdp_packet_create(PDP_TEXTURE, 0);
+ if (-1 == p) return -1;
+
+ h = pdp_packet_header(p);
+ t = _pdp_tex_info(h);
+
+ /* check if alloc succeded */
+ if (!h) return -1;
+
+ /* check if tex is already initialized */
+ if (pdp_packet_texture_isvalid(p)){
+ /* check format */
+ if ((t->width >= width) && (t->height >= height) && (t->format == format)){
+ //post("pdp_packet_new_tex: reused");
+ t->sub_width = width;
+ t->sub_height = height;
+ return p;
+ }
+ post("ERROR: pdp_packet_new_texture: pdp_packet_reuse returned wrong type");
+ }
+
+ /* determine the texture dims * setup rest of data struct */
+ t->width = 64;
+ t->height = 64;
+ while (t->width < width) t->width <<= 1;
+ while (t->height < height) t->height <<= 1;
+
+ t->format = format;
+ t->sub_width = width;
+ t->sub_height = height;
+
+ _pdp_tex_init_methods(h);
+
+
+ /* init the texture */
+ //_tex_init_obj(t);
+
+ /* init description */
+ h->desc = _pdp_tex_get_description(h);
+
+
+ return p;
+}
+
+/* don't call this method on a non-texture object! */
+static void _pdp_packet_gentexture(int p)
+{
+ t_texture *t;
+ if (!pdp_packet_texture_isvalid(p)){
+ /* not initialized, so we need to create a new one */
+ // post("generating texture");
+ t = (t_texture *)pdp_packet_subheader(p);
+
+ /* create the texture object */
+ glGenTextures(1, (GLuint *)&t->tex_obj);
+
+ /* init the texture */
+ _tex_init_obj(t);
+
+ }
+}
+
+int pdp_packet_new_texture(u32 width, u32 height, s32 format)
+{
+ t_texture *t;
+ int p = _pdp_packet_texture_old_or_dummy(width, height, format);
+
+ //post("WARNING: pdp_packet_new_texture: this method should not be called outside the 3dp thread");
+
+ if (p == -1) return -1;
+ _pdp_packet_gentexture(p);
+ return p;
+}
+
+
+/* high level texture packet operators */
+
+/* make a texture the current texture context */
+void pdp_packet_texture_make_current(int packet)
+{
+ t_texture *t = pdp_packet_texture_info(packet);
+ if (!t) return;
+ glBindTexture(GL_TEXTURE_2D, t->tex_obj);
+}
+
+void pdp_packet_texture_make_current_enable(int packet)
+{
+ glEnable(GL_TEXTURE_2D);
+ pdp_packet_texture_make_current(packet);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+}
+
+float pdp_packet_texture_fracx(int packet)
+{
+ t_texture *t = pdp_packet_texture_info(packet);
+ if (!t) return 0.0;
+ return (float)t->sub_width/t->width;
+}
+
+float pdp_packet_texture_fracy(int packet)
+{
+ t_texture *t = pdp_packet_texture_info(packet);
+ if (!t) return 0.0;
+ return (float)t->sub_height/t->height;
+}
+
+u32 pdp_packet_texture_total_width(int packet)
+{
+ t_texture *t = pdp_packet_texture_info(packet);
+ if (!t) return 0;
+ return t->width;
+
+}
+u32 pdp_packet_texture_total_height(int packet)
+{
+ t_texture *t = pdp_packet_texture_info(packet);
+ if (!t) return 0;
+ return t->height;
+
+}
+
+u32 pdp_packet_texture_sub_width(int packet)
+{
+ t_texture *t = pdp_packet_texture_info(packet);
+ if (!t) return 0;
+ return t->sub_width;
+
+}
+u32 pdp_packet_texture_sub_height(int packet)
+{
+ t_texture *t = pdp_packet_texture_info(packet);
+ if (!t) return 0;
+ return t->sub_height;
+}
+
+float pdp_packet_texture_sub_aspect(int packet)
+{
+ t_texture *t = pdp_packet_texture_info(packet);
+ if (!t) return 0;
+ return (float)t->sub_width/t->sub_height;
+}
+
+/* setup for 2d operation from texture dimensions */
+void pdp_packet_texture_setup_2d_context(int p)
+{
+ u32 w;
+ u32 h;
+ float asp;
+ if (!pdp_packet_texture_isvalid(p)) return;
+ w = pdp_packet_texture_sub_width(p);
+ h = pdp_packet_texture_sub_height(p);
+ asp = pdp_packet_texture_sub_aspect(p);
+
+ /* set the viewport to the size of the sub texture */
+ glViewport(0, 0, w, h);
+
+ /* set orthogonal projection, with a relative frame size of (2asp x 2) */
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluOrtho2D(0.0, 2*asp, 0, 2);
+
+ /* set the center of view */
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(asp, 1, 0);
+ glScalef(1,-1,1);
+}
+
+void pdp_texture_setup(void)
+{
+ t_pdp_conversion_program *program;
+
+ /* setup packet class */
+ texture_class = pdp_class_new(pdp_gensym("texture/*/*"), 0);
+ texture_class->cleanup = _pdp_tex_cleanup;
+ texture_class->wakeup = _pdp_tex_reinit;
+ //texture_class->clone = _pdp_tex_clone;
+ texture_class->copy = _pdp_tex_copy;
+
+ /* init command list */
+ pdp_dpd_commandfactory_init(&_tex_cf, sizeof(t_texture_command));
+
+
+
+ /* setup programs */
+ program = pdp_conversion_program_new(_pdp_packet_texture_convert_bitmap_to_texture, 0);
+ pdp_type_register_conversion(pdp_gensym("bitmap/*/*"), pdp_gensym("texture/*/*"), program);
+
+ /* this is a hack to use until the type conversion system has a proper search algo */
+ program = pdp_conversion_program_new(_pdp_packet_texture_convert_image_to_texture, 0);
+ pdp_type_register_conversion(pdp_gensym("image/*/*"), pdp_gensym("texture/*/*"), program);
+
+
+ program = pdp_conversion_program_new(_pdp_packet_texture_convert_texture_to_bitmap, 0);
+ pdp_type_register_conversion(pdp_gensym("texture/*/*"), pdp_gensym("bitmap/*/*"), program);
+
+}
+
+/* all symbols are C-style */
+#ifdef __cplusplus
+}
+#endif
diff --git a/opengl/system/setup.c b/opengl/system/setup.c
new file mode 100644
index 0000000..18d267a
--- /dev/null
+++ b/opengl/system/setup.c
@@ -0,0 +1,83 @@
+#include "pdp_opengl.h"
+
+/* 3dp overview:
+
+ - texture packets (gl)
+ - drawable packets (glX windows and pbufs)
+
+ the 3dp system connects to a display server and creates a common context
+ this can be a pbuf context (if supported, glx >= 1.3) or a normal glX context
+ textures are standard opengl
+ drawable packets are wrappers around glx drawables (windows or pbufs)
+ they share the central display connection and rendering context
+
+*/
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* opengl lib kernel setup */
+void pdp_opengl_system_setup(void);
+
+/* packet type setup */
+void pdp_3Dcontext_glx_setup(void); /* glx specific part of the 3D context packet */
+void pdp_3Dcontext_common_setup(void); /* common part of the 3D context packet */
+void pdp_texture_setup(void); /* texture packet */
+
+
+/* module setup */
+void pdp_3d_windowcontext_setup(void);
+void pdp_3d_draw_setup(void);
+void pdp_3d_view_setup(void);
+void pdp_3d_light_setup(void);
+void pdp_3d_color_setup(void);
+void pdp_3d_push_setup(void);
+void pdp_3d_snap_setup(void);
+void pdp_3d_dlist_setup(void);
+void pdp_3d_drawmesh_setup(void);
+void pdp_3d_for_setup(void);
+void pdp_3d_state_setup(void);
+void pdp_3d_subcontext_setup(void);
+
+
+ //#define D(x) { pdp_post_n( #x ".." ); x; pdp_post("done"); }
+#define D(x) x
+
+void pdp_opengl_setup(void)
+{
+ int i;
+ post("PDP: pdp_opengl extension library");
+
+ /* setup system */
+ D(pdp_opengl_system_setup());
+
+ /* setup packet types */
+ D(pdp_3Dcontext_glx_setup());
+ D(pdp_3Dcontext_common_setup());
+ D(pdp_texture_setup());
+
+
+ /* setup modules */
+ D(pdp_3d_windowcontext_setup());
+ D(pdp_3d_draw_setup());
+ D(pdp_3d_view_setup());
+ D(pdp_3d_push_setup());
+ D(pdp_3d_light_setup());
+ D(pdp_3d_dlist_setup());
+ D(pdp_3d_color_setup());
+ D(pdp_3d_snap_setup());
+ D(pdp_3d_drawmesh_setup());
+ D(pdp_3d_for_setup());
+ D(pdp_3d_state_setup());
+ D(pdp_3d_subcontext_setup());
+
+
+}
+
+
+#ifdef __cplusplus
+}
+#endif