diff options
Diffstat (limited to 'opengl/system')
-rw-r--r-- | opengl/system/Makefile | 8 | ||||
-rw-r--r-- | opengl/system/pdp_3Dcontext_common.c | 267 | ||||
-rw-r--r-- | opengl/system/pdp_3Dcontext_glx.c | 393 | ||||
-rw-r--r-- | opengl/system/pdp_3dp_base.c | 30 | ||||
-rw-r--r-- | opengl/system/pdp_mesh.c | 560 | ||||
-rw-r--r-- | opengl/system/pdp_opengl.c | 76 | ||||
-rw-r--r-- | opengl/system/pdp_texture.c | 541 | ||||
-rw-r--r-- | opengl/system/setup.c | 83 |
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 |