Update of /cvsroot/pure-data/externals/pdp/opengl/system
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6756/opengl/system
Added Files:
Makefile pdp_3Dcontext_common.c pdp_3Dcontext_glx.c
pdp_3dp_base.c pdp_mesh.c pdp_opengl.c pdp_texture.c setup.c
Log Message:
checking in pdp 0.12.4 from http://zwizwa.fartit.com/pd/pdp/pdp-0.12.4.tar.gz
--- NEW FILE: pdp_3Dcontext_common.c ---
/*
* OpenGL Extension Module for pdp - pbuffer packet implementation
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the 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)
{
}
--- NEW FILE: pdp_mesh.c ---
/*
* Pure Data Packet module. mesh implementation
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the 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);
}
--- NEW FILE: Makefile ---
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
--- NEW FILE: setup.c ---
#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
--- NEW FILE: pdp_3dp_base.c ---
#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);
}
--- NEW FILE: pdp_texture.c ---
/*
* OpenGL Extension Module for pdp - texture packet implementation
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the 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
--- NEW FILE: pdp_opengl.c ---
/*
* OpenGL Extension Module for pdp - opengl system stuff
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the 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);}
--- NEW FILE: pdp_3Dcontext_glx.c ---
/*
* OpenGL Extension Module for pdp - opengl system stuff
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the 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
Update of /cvsroot/pure-data/externals/pdp/puredata
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6756/puredata
Added Files:
CONTENTS Makefile pdp_base.c pdp_comm.c pdp_compat.c
pdp_control.c pdp_dpd_base.c pdp_imagebase.c pdp_queue.c
pdp_ut.c
Log Message:
checking in pdp 0.12.4 from http://zwizwa.fartit.com/pd/pdp/pdp-0.12.4.tar.gz
--- NEW FILE: pdp_imagebase.c ---
/*
* Pure Data Packet image processor base class implementation.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
This file contains the pdp image base class object.
*/
#include "pdp_imagebase.h"
#include <stdarg.h>
static void pdp_imagebase_chanmask(t_pdp_base *b, t_floatarg f)
{
int i = (int)f;
if (i < 0) i = -1;
b->b_channel_mask = i;
}
void pdp_imagebase_setup(t_class *c)
{
/* parent class setup */
pdp_base_setup(c);
/* add pdp base class methods */
class_addmethod(c, (t_method)pdp_imagebase_chanmask, gensym("chanmask"), A_FLOAT, A_NULL);
}
/* pdp base instance constructor */
void pdp_imagebase_init(void *x)
{
int i;
t_pdp_imagebase *b = (t_pdp_imagebase *)x;
/* init super */
pdp_base_init(x);
/* convert all active incoming packet types to image */
pdp_base_set_type_template(x, 0, pdp_gensym("image/*/*"));
/* default chanmask == all */
b->b_channel_mask = -1;
}
/* base instance destructor */
void pdp_imagebase_free(void *x)
{
/* free super */
pdp_base_free(x);
}
/* chanmask getter */
u32 pdp_imagebase_get_chanmask(void *x)
{
t_pdp_base *b = (t_pdp_base *)x;
return b->b_channel_mask;
}
--- NEW FILE: pdp_dpd_base.c ---
/*
* Pure Data Packet module. DPD base class implementation.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "pdp_dpd_base.h"
#include "pdp_internals.h"
#define THIS(b) t_pdp_dpd_base *b = (t_pdp_dpd_base *)x
#ifdef __cplusplus
extern "C"
{
#endif
/* PRIVATE METHODS */
/* dpd packet context input handler */
static void _pdp_dpd_base_context_input(t_pdp_dpd_base *b, t_symbol *s, t_floatarg f)
{
int p = (int)f;
int i;
//post ("pdp_dpd_base_context_input: got %s %d", s->s_name, p);
/* sources/sinks have active inlet disabled */
if (b->b_dpd_active_inlet_disabled) return;
/* handle inspect message */
if (s == S_INSPECT){
/* store packet for inspector */
b->b_context_packet = p;
/* add inspector to pdp queue
this is special: it doesn't use a command object */
pdp_dpd_base_queue_command(b, b, b->b_inspector_method, b->b_inspector_callback, 0);
}
/* handle accumulate message */
if (s == S_ACCUMULATE){
/* store context for accumulator methods */
b->b_context_packet = p;
/* call bang */
pdp_dpd_base_bang(b);
}
}
/* default command object (returns self) */
void *_pdp_dpd_base_get_command_object(void *x){return x;}
/* PUBLIC METHODS */
void pdp_dpd_base_queue_command(void *x, void *c, t_pdp_method process,
t_pdp_method callback, int *id)
{
THIS(b);
t_pdp_procqueue *q = pdp_base_get_queue(x);
pdp_procqueue_add(q, c, process, callback, id);
}
/* bang method (propagate context to outlet) : it is not registered as a pd message by default ! */
void pdp_dpd_base_bang(void *x)
{
THIS(b);
int i, id;
void *cobj;
/* move passive pdp packets in place */
pdp_base_movepassive(x);
/* get command object (or use self) */
cobj = b->b_command_factory_method ? (b->b_command_factory_method)(b) : b;
//post(" command object is %x. object is %x", cobj, b);
/* queue acc method & propagate for all outlets */
for (i=b->b_nb_context_outlets; i--;){
/* propagate the context packet to the outlet */
if (b->b_outlet_enable[i]){
pdp_dpd_base_queue_command(x, cobj, b->b_accum_method[i], b->b_accum_callback[i], 0);
outlet_dpd(b->b_context_outlet[i], b->b_context_packet);
}
else{
//post("outlet %d disabled", i);
}
}
/* queue cleanup method */
if (b->b_cleanup_method)
//pdp_procqueue_add(b->b_q, b, b->b_cleanup_method, 0, &b->b_cleanup_queue_id);
pdp_dpd_base_queue_command(x, cobj, b->b_cleanup_method, b->b_cleanup_callback, 0);
/* send communication complete notify */
if (b->b_complete_notify)
(b->b_complete_notify)(x);
}
/* get/set context packet */
int pdp_dpd_base_get_context_packet(void *x){
THIS(b);
return b->b_context_packet;
}
int pdp_dpd_base_move_context_packet(void *x){
THIS(b);
int p = b->b_context_packet;
b->b_context_packet = -1;
return p;
}
void pdp_dpd_base_set_context_packet(void *x, int p){
THIS(b);
pdp_packet_mark_unused(b->b_context_packet);
b->b_context_packet = p;
}
/* add a cleanup callback (called after all propagation is finished) for sources/sinks */
void pdp_dpd_base_add_cleanup(void *x, t_pdp_method cleanup_method, t_pdp_method cleanup_callback)
{
THIS(b);
b->b_cleanup_method = cleanup_method;
b->b_cleanup_callback = cleanup_callback;
//b->b_cleanup_queue_id = -1;
}
/* add a inspector callback */
void pdp_dpd_base_add_inspector(void *x, t_pdp_method inspector_method)
{
THIS(b);
b->b_inspector_method = inspector_method;
//b->b_inspector_queue_id = -1;
}
/* add a context outlet */
t_outlet *pdp_dpd_base_add_outlet(void *x, t_pdp_method accum_method, t_pdp_method accum_callback)
{
THIS(b);
int i = b->b_nb_context_outlets;
if (i < PDP_DPD_MAX_CONTEXT_OUTLETS){
b->b_context_outlet[i] = outlet_new((t_object *)b, &s_anything);
b->b_outlet_enable[i] = 1;
b->b_accum_method[i] = accum_method;
b->b_accum_callback[i] = accum_callback;
//b->b_accum_queue_id[i] = -1;
b->b_nb_context_outlets++;
return b->b_context_outlet[i];
}
else{
post("pdp_dpd_base_add_outlet: no more free outlet slots");
return 0;
}
}
/* destructor */
void pdp_dpd_base_free(void *x)
{
THIS(b);
/* free base */
pdp_base_free(b);
}
void pdp_dpd_base_disable_active_inlet(void *x)
{
THIS(b);
b->b_dpd_active_inlet_disabled = 1;
}
void pdp_dpd_base_enable_outlet(void *x, int outlet, int toggle)
{
THIS(b);
if (outlet >=0 && outlet < PDP_DPD_MAX_CONTEXT_OUTLETS){
b->b_outlet_enable[outlet] = toggle;
}
}
void pdp_dpd_base_register_complete_notify(void *x, t_pdp_method method)
{
THIS(b);
b->b_complete_notify = method;
}
void pdp_dpd_base_register_command_factory_method(void *x, t_pdp_newmethod command_factory_method)
{
THIS(b);
b->b_command_factory_method = command_factory_method;
}
/* init method */
void pdp_dpd_base_init(void *x)
{
THIS(b);
/* super init */
pdp_base_init(b);
/* disable pdp messages on active inlet (dpd messages are used as sync) */
pdp_base_disable_active_inlet(b);
/* init data */
b->b_nb_context_outlets = 0;
b->b_context_packet = -1;
b->b_cleanup_method = 0;
//b->b_cleanup_queue_id = -1;
b->b_inspector_method = 0;
//b->b_inspector_queue_id = -1;
b->b_dpd_active_inlet_disabled = 0;
// default notify == none
b->b_complete_notify = 0;
// default command object getter
b->b_command_factory_method = 0;
}
void pdp_dpd_base_setup(t_class *class)
{
pdp_base_setup(class);
class_addmethod(class, (t_method)_pdp_dpd_base_context_input, gensym("dpd"), A_SYMBOL, A_FLOAT, A_NULL);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: Makefile ---
OBJECTS = pdp_base.o pdp_imagebase.o pdp_dpd_base.o pdp_ut.o pdp_queue.o pdp_comm.o \
pdp_control.o pdp_compat.o $(PDP_PDMOD)
include ../Makefile.config
all: $(OBJECTS)
clean:
rm -f *~
rm -f *.o
--- NEW FILE: pdp_comm.c ---
/*
* Pure Data Packet system implementation.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/* this file contains misc communication (packet) methods for pd */
#include <stdio.h>
#include "pdp_pd.h"
#include "pdp_internals.h"
#include "pdp_packet.h"
#include "pdp_comm.h"
#include "pdp_type.h"
#include "pdp_control.h"
#include "pdp_mem.h"
#include "pdp_queue.h" // for notify drop: fix this (should be from pdp_control.h)
#include "pdp_debug.h"
/* all symbols are C style */
#ifdef __cplusplus
extern "C"
{
#endif
/* interface to pd system:
pdp/dpd communication protocol in pd
pd <-> pdp atom and list conversion */
/* NOTE: when using the outlet_pdp methods, the packet
is no longer read/write, but can be readonly */
/* NOTE: since 0.13 the passing packet is no more.
in order to limit copying. processors should always register ro,
and replace with writable when packet needs to be written in the process method */
/* send a packet to an outlet */
void outlet_pdp_register(t_outlet *out, int packetid)
{
t_atom atom[2];
SETFLOAT(atom+1, (float)packetid);
/* during the following phase,
objects can register a ro copy */
SETSYMBOL(atom+0, S_REGISTER_RO);
outlet_anything(out, S_PDP, 2, atom);
/* DEPRECIATED: objects can register a rw copy
but this will always copy the packet. it is better
to perform a pdp_packet_replace_with_writable operation during the process step */
SETSYMBOL(atom+0, S_REGISTER_RW);
outlet_anything(out, S_PDP, 2, atom);
}
/* send a packet to an outlet */
void outlet_pdp_process(t_outlet *out)
{
t_atom atom[2];
/* set a dummy invalid packet.
this is for uniform pdp messages in pd, for ease of routing. */
SETFLOAT(atom+1, (float)-1);
/* during the process phase, objects can perform pdp_packet_replace_with_writable
and process the packet data */
SETSYMBOL(atom+0, S_PROCESS);
outlet_anything(out, S_PDP, 2, atom);
}
/* for compat */
void outlet_pdp(t_outlet *out, int packetid)
{
outlet_pdp_register(out, packetid);
outlet_pdp_process(out);
}
/* send an accumulation packet to an outlet */
void outlet_dpd(t_outlet *out, int packetid)
{
t_atom atom[2];
SETFLOAT(atom+1, (float)packetid);
SETSYMBOL(atom+0, S_INSPECT);
outlet_anything(out, S_DPD, 2, atom);
SETSYMBOL(atom+0, S_ACCUMULATE);
outlet_anything(out, S_DPD, 2, atom);
}
/* unregister a packet and send it to an outlet */
void
pdp_packet_pass_if_valid(t_outlet *outlet, int *packet_ptr)
{
t_pdp *header = pdp_packet_header(*packet_ptr);
if (header){
/* send register phase */
outlet_pdp_register(outlet, *packet_ptr);
/* unregister */
pdp_packet_mark_unused(*packet_ptr);
*packet_ptr = -1;
/* send process phase */
outlet_pdp_process(outlet);
}
}
void
pdp_packet_replace_if_valid(int *dpacket, int *spacket)
{
if (-1 != *spacket){
pdp_packet_mark_unused(*dpacket);
*dpacket = *spacket;
*spacket = -1;
}
}
int
pdp_packet_copy_ro_or_drop(int *dpacket, int spacket)
{
int drop = 0;
if (*dpacket == -1) *dpacket = pdp_packet_copy_ro(spacket);
else {
/* send a notification there is a dropped packet */
pdp_control_notify_drop(spacket);
drop = 1;
}
return drop;
}
int
pdp_packet_copy_rw_or_drop(int *dpacket, int spacket)
{
int drop = 0;
if (*dpacket == -1) *dpacket = pdp_packet_copy_rw(spacket);
else {
/* send a notification there is a dropped packet */
pdp_control_notify_drop(spacket);
drop = 1;
}
return drop;
}
int
pdp_packet_convert_ro_or_drop(int *dpacket, int spacket, t_pdp_symbol *template)
{
int drop = 0;
if (!template) return pdp_packet_copy_ro_or_drop(dpacket, spacket);
if (*dpacket == -1) *dpacket = pdp_packet_convert_ro(spacket, template);
else {
/* send a notification there is a dropped packet */
pdp_control_notify_drop(spacket);
drop = 1;
}
return drop;
}
int
pdp_packet_convert_rw_or_drop(int *dpacket, int spacket, t_pdp_symbol *template)
{
int drop = 0;
if (!template) return pdp_packet_copy_rw_or_drop(dpacket, spacket);
if (*dpacket == -1) *dpacket = pdp_packet_convert_rw(spacket, template);
else {
/* send a notification there is a dropped packet */
pdp_control_notify_drop(spacket);
drop = 1;
}
return drop;
}
/* send a pdp list to a pd outlet. packets are not copied but passed! */
void outlet_pdp_atom(t_outlet *out, t_pdp_atom *a)
{
int packet = -1;
if (!a) return;
switch(a->t){
case a_float:
outlet_float(out, a->w.w_float);
return;
case a_int:
outlet_float(out, (float)a->w.w_int);
return;
case a_symbol:
outlet_symbol(out, gensym(a->w.w_symbol->s_name));
return;
case a_list:
outlet_pdp_list(out, a->w.w_list);
return;
case a_packet:
pdp_packet_pass_if_valid(out, &a->w.w_packet);
return;
default:
return;
}
}
void outlet_pdp_list(t_outlet *out, struct _pdp_list *l)
{
int elements;
t_atom *atomlist;
t_pdp_atom *pdp_a;
t_atom *pd_a;
t_symbol *pd_selector;
if (!l) return;
switch(l->elements){
case 0: /* bang */
outlet_bang(out);
return;
case 1: /* atom */
outlet_pdp_atom(out, l->first);
return;
default: /* proper list*/
elements = l->elements;
/* allocate list */
atomlist = pdp_alloc(sizeof (t_atom) * l->elements);
pd_a = atomlist;
pdp_a = l->first;
/* setup selector */
if (pdp_a->t != a_symbol){
pd_selector = gensym("list");
}
else {
pd_selector = gensym(pdp_a->w.w_symbol->s_name);
elements--;
pdp_a = pdp_a->next;
}
/* setup atoms */
while (pdp_a){
switch(pdp_a->t){
case a_float:
SETFLOAT(pd_a, pdp_a->w.w_float);
break;
case a_int:
SETFLOAT(pd_a, (float)pdp_a->w.w_int);
break;
case a_symbol:
SETSYMBOL(pd_a, gensym(pdp_a->w.w_symbol->s_name));
break;
default:
SETSYMBOL(pd_a, gensym("invalid"));
break;
}
pdp_a = pdp_a->next;
pd_a++;
}
/* send out */
outlet_anything(out, pd_selector, elements, atomlist);
/* clean up */
pdp_dealloc(atomlist);
}
}
void pd_atom_to_pdp_atom(t_atom *pdatom, t_pdp_atom *pdpatom)
{
switch (pdatom->a_type){
case A_FLOAT:
pdpatom->t = a_float;
pdpatom->w.w_float = pdatom->a_w.w_float;
break;
case A_SYMBOL:
pdpatom->t = a_symbol;
pdpatom->w.w_symbol = pdp_gensym(pdatom->a_w.w_symbol->s_name);
break;
default:
pdpatom->t = a_undef;
break;
}
}
/* some "accelerated" pd symbols */
t_symbol s_pdp = {"pdp", 0, 0};
t_symbol s_register_ro = {"register_ro", 0, 0};
t_symbol s_register_rw = {"register_rw", 0, 0};
t_symbol s_process = {"process", 0, 0};
t_symbol s_dpd = {"dpd", 0, 0};
t_symbol s_inspect = {"inspect", 0, 0};
t_symbol s_accumulate = {"accumulate", 0, 0};
t_symbol s_chanmask = {"chanmask", 0, 0};
// internal pd method
t_symbol *dogensym(char *s, t_symbol *oldsym);
static void _addsym(t_symbol *s)
{
/* don't kill me for this one..
if the symbol is already defined and used, .. well, that's a problem
but right now it seems a reasonable hack */
t_symbol *sret = dogensym(s->s_name, s);
if (s != sret){
post("PDP INIT ERROR: pd symbol clash adding symbol %s: new=%08x old=%08x", s->s_name, s, sret);
post("try loading pdp before other libraries");
}
}
void
pdp_pdsym_setup(void)
{
_addsym(&s_pdp);
_addsym(&s_register_ro);
_addsym(&s_register_rw);
_addsym(&s_process);
_addsym(&s_dpd);
_addsym(&s_inspect);
_addsym(&s_accumulate);
_addsym(&s_chanmask);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: pdp_compat.c ---
/*
* Pure Data Packet system implementation. Compatibility routines.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/* this file contains misc communication methods */
#include <stdio.h>
#include "pdp_pd.h"
#include "pdp_comm.h"
#include "pdp_internals.h"
/* all symbols are C style */
#ifdef __cplusplus
extern "C"
{
#endif
void
pdp_pass_if_valid(t_outlet *outlet, int *packet)
{
pdp_packet_pass_if_valid(outlet, packet);
}
void
pdp_replace_if_valid(int *dpacket, int *spacket)
{
pdp_packet_replace_if_valid(dpacket, spacket);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: pdp_control.c ---
/*
* Pure Data Packet system implementation: control object
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/* this is an actual pd class that is used for communication with the
pdp framework */
#include "pdp_internals.h"
#include "pdp_control.h"
#include "pdp_packet.h"
#include <stdio.h>
/* all symbols are C style */
#ifdef __cplusplus
extern "C"
{
#endif
static long dropped_packets;
static t_class* pdp_control_class;
/* pdp control instance data */
struct _pdp_control;
typedef struct _pdp_control
{
t_object x_obj;
t_outlet *x_outlet0;
struct _pdp_control *x_next;
} t_pdp_control;
static t_pdp_control *pdp_control_list;
static void pdp_control_info(t_pdp_control *x)
{
}
static void pdp_control_collectgarbage(t_pdp_control *x)
{
int nb_packets_freed = pdp_pool_collect_garbage();
post("pdp_control: freed %d packets", nb_packets_freed);
}
static void pdp_control_set_mem_limit(t_pdp_control *x, t_floatarg f)
{
int limit = (int)f;
if (limit < 0) limit = 0;
pdp_pool_set_max_mem_usage(limit);
if (limit) post("pdp_control: set memory limit to %d bytes", limit);
else post("pdp_control: disabled memory limit");
}
static void pdp_control_thread(t_pdp_control *x, t_floatarg f)
{
int t = (int)f;
if (t){
post("pdp_control: pdp is now using its own processing thread");
pdp_queue_use_thread(1);
}
else {
post("pdp_control: pdp is now using the main pd thread");
pdp_queue_use_thread(0);
}
}
static void pdp_control_send_drop_message(t_pdp_control *x)
{
t_atom atom[1];
t_symbol *s = gensym("pdp_drop");
SETFLOAT(atom+0, (float)dropped_packets);
outlet_anything(x->x_outlet0, s, 1, atom);
}
static void pdp_control_free(t_pdp_control *x)
{
/* remove from linked list */
t_pdp_control *curr = pdp_control_list;
if (pdp_control_list == x) pdp_control_list = x->x_next;
else while (curr){
if (curr->x_next == x) {
curr->x_next = x->x_next;
break;
}
else {
curr = curr->x_next;
}
}
}
static void *pdp_control_new(void)
{
t_pdp_control *x = (t_pdp_control *)pd_new(pdp_control_class);
x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
/* add to list */
x->x_next = pdp_control_list;
pdp_control_list = x;
return x;
}
/************************* class methods ***************************************/
void pdp_control_addmethod(t_method m, t_symbol *s)
{
class_addmethod(pdp_control_class, m, s, A_GIMME, A_NULL);
}
void pdp_control_setup(void)
{
pdp_control_list = 0;
dropped_packets = 0;
/* setup pd class data */
pdp_control_class = class_new(gensym("pdp_control"), (t_newmethod)pdp_control_new,
(t_method)pdp_control_free, sizeof(t_pdp_control), 0, A_NULL);
class_addmethod(pdp_control_class, (t_method)pdp_control_info, gensym("info"), A_NULL);
class_addmethod(pdp_control_class, (t_method)pdp_control_thread, gensym("thread"), A_DEFFLOAT, A_NULL);
class_addmethod(pdp_control_class, (t_method)pdp_control_collectgarbage, gensym("collectgarbage"), A_NULL);
class_addmethod(pdp_control_class, (t_method)pdp_control_set_mem_limit, gensym("memlimit"), A_FLOAT, A_NULL);
}
void pdp_control_notify_broadcast(t_pdp_control_method_notify *notify)
{
t_pdp_control *curr = pdp_control_list;
while (curr){
(*notify)(curr);
curr = curr->x_next;
}
}
/************************* notify class methods *************************/
void pdp_control_notify_drop(int packet)
{
dropped_packets++;
/* send drop notify to controller class instances */
pdp_control_notify_broadcast(pdp_control_send_drop_message);
//post("dropped packet");
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: CONTENTS ---
base pdp base pd object
image_base image processing base pd object
dpd_base bucket base pd object
comm pdp communication protocol in pd
compat legacy pdp stuff
control control pdp from within pd
fp object interface to the forth system
forthconsole console interface to the forth system
queue processing queue and synchro stuff
ut some utility pd objects
--- NEW FILE: pdp_ut.c ---
/*
* Pure Data Packet - Utility toolkit objects.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/* This file contains some small utility pd objects that make working with
pdp objects a lot easier. Mainly as glue to be used in the abstractions
in the distro. */
#include "pdp_pd.h"
#include <math.h>
/* this object does an add, scale, clip operation */
t_class *pdp_ut_addscaleclip_class;
typedef struct pdp_ut_addscaleclip_struct
{
t_object x_obj;
t_outlet *x_outlet0;
t_float x_min;
t_float x_max;
t_float x_offset;
t_float x_scale;
} t_pdp_ut_addscaleclip;
static void pdp_ut_addscaleclip_float(t_pdp_ut_addscaleclip *x, t_floatarg f)
{
f += x->x_offset;
f *= x->x_scale;
f = (f < x->x_min) ? x->x_min : f;
f = (f > x->x_max) ? x->x_max : f;
outlet_float(x->x_outlet0, f);
}
static void pdp_ut_addscaleclip_free(t_pdp_ut_addscaleclip *x){}
void *pdp_ut_addscaleclip_new(t_floatarg offset, t_floatarg scale, t_floatarg min, t_floatarg max)
{
t_pdp_ut_addscaleclip *x = (t_pdp_ut_addscaleclip *)pd_new(pdp_ut_addscaleclip_class);
x->x_outlet0 = outlet_new(&x->x_obj, &s_float);
x->x_offset = offset;
x->x_scale = scale;
x->x_min = min;
x->x_max = max;
return (void *)x;
}
void pdp_ut_addscaleclip_setup(void)
{
pdp_ut_addscaleclip_class = class_new(gensym("pdp_ut_addscaleclip"), (t_newmethod)pdp_ut_addscaleclip_new,
(t_method)pdp_ut_addscaleclip_free, sizeof(t_pdp_ut_addscaleclip), 0,
A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
class_addfloat(pdp_ut_addscaleclip_class, pdp_ut_addscaleclip_float);
}
/* pdp_ut_logmap does a logarithmic parameter mapping [0->1] x -> min(max/min)^x max an add, scale, clip operation */
/* pdp_ut_logmap_comp does x -> min(max/min)^(1-x) */
/* pdp_ut_linmap dos x -> min + (max - min * x */
t_class *pdp_ut_linmap_class;
t_class *pdp_ut_logmap_class;
t_class *pdp_ut_logmap_comp_class;
typedef struct pdp_ut_map_struct
{
t_object x_obj;
t_outlet *x_outlet0;
t_float x_min;
t_float x_max;
} t_pdp_ut_map;
static void pdp_ut_logmap_float(t_pdp_ut_map *x, t_floatarg f)
{
f = (f < 0.0f) ? 0.0f : f;
f = (f > 1.0f) ? 1.0f : f;
f = x->x_min * pow((x->x_max / x->x_min), f);
outlet_float(x->x_outlet0, f);
}
static void pdp_ut_linmap_float(t_pdp_ut_map *x, t_floatarg f)
{
f = (f < 0.0f) ? 0.0f : f;
f = (f > 1.0f) ? 1.0f : f;
f = x->x_min + ((x->x_max - x->x_min) * f);
outlet_float(x->x_outlet0, f);
}
static void pdp_ut_logmap_comp_float(t_pdp_ut_map *x, t_floatarg f)
{
f = (f < 0.0f) ? 0.0f : f;
f = (f > 1.0f) ? 1.0f : f;
f = x->x_min * pow((x->x_max / x->x_min), (1.0f - f));
outlet_float(x->x_outlet0, f);
}
static void pdp_ut_map_free(t_pdp_ut_map *x){}
void pdp_ut_map_init(t_pdp_ut_map *x, t_floatarg min, t_floatarg max)
{
x->x_outlet0 = outlet_new(&x->x_obj, &s_float);
x->x_min = min;
x->x_max = max;
}
void *pdp_ut_logmap_new(t_floatarg min, t_floatarg max)
{
t_pdp_ut_map *x = (t_pdp_ut_map *)pd_new(pdp_ut_logmap_class);
pdp_ut_map_init(x, min, max);
return (void *)x;
}
void *pdp_ut_linmap_new(t_floatarg min, t_floatarg max)
{
t_pdp_ut_map *x = (t_pdp_ut_map *)pd_new(pdp_ut_linmap_class);
pdp_ut_map_init(x, min, max);
return (void *)x;
}
void *pdp_ut_logmap_comp_new(t_floatarg min, t_floatarg max)
{
t_pdp_ut_map *x = (t_pdp_ut_map *)pd_new(pdp_ut_logmap_comp_class);
pdp_ut_map_init(x, min, max);
return (void *)x;
}
void pdp_ut_logmap_setup(void)
{
pdp_ut_logmap_class = class_new(gensym("pdp_ut_logmap"), (t_newmethod)pdp_ut_logmap_new,
(t_method)pdp_ut_map_free, sizeof(t_pdp_ut_map), 0,
A_FLOAT, A_FLOAT, A_NULL);
class_addfloat(pdp_ut_logmap_class, pdp_ut_logmap_float);
}
void pdp_ut_logmap_comp_setup(void)
{
pdp_ut_logmap_comp_class = class_new(gensym("pdp_ut_logmap_comp"), (t_newmethod)pdp_ut_logmap_comp_new,
(t_method)pdp_ut_map_free, sizeof(t_pdp_ut_map), 0,
A_FLOAT, A_FLOAT, A_NULL);
class_addfloat(pdp_ut_logmap_comp_class, pdp_ut_logmap_comp_float);
}
void pdp_ut_linmap_setup(void)
{
pdp_ut_linmap_class = class_new(gensym("pdp_ut_linmap"), (t_newmethod)pdp_ut_linmap_new,
(t_method)pdp_ut_map_free, sizeof(t_pdp_ut_map), 0,
A_FLOAT, A_FLOAT, A_NULL);
class_addfloat(pdp_ut_linmap_class, pdp_ut_linmap_float);
}
t_class *pdp_ut_rgb2ycrcb_class;
typedef struct pdp_ut_rgb2ycrcb
{
t_object x_obj;
t_outlet *x_outlet_luma;
t_outlet *x_outlet_chroma_red;
t_outlet *x_outlet_chroma_blue;
t_float x_red, x_green, x_blue;
} t_pdp_ut_rgb2ycrcb;
static void pdp_ut_rgb2ycrcb_bang (t_pdp_ut_rgb2ycrcb* x)
{
float luma = 0.299f * x->x_red + 0.587f * x->x_green + 0.114f * x->x_blue;
float chroma_red = (x->x_red - luma) * 0.713f;
float chroma_blue = (x->x_blue - luma) * 0.565f;
outlet_float(x->x_outlet_chroma_blue, chroma_blue);
outlet_float(x->x_outlet_chroma_red, chroma_red);
outlet_float(x->x_outlet_luma, luma);
}
static void pdp_ut_rgb2ycrcb_red (t_pdp_ut_rgb2ycrcb* x, t_floatarg f) {x->x_red = f; pdp_ut_rgb2ycrcb_bang(x);}
static void pdp_ut_rgb2ycrcb_green (t_pdp_ut_rgb2ycrcb* x, t_floatarg f) {x->x_green = f; pdp_ut_rgb2ycrcb_bang(x);}
static void pdp_ut_rgb2ycrcb_blue (t_pdp_ut_rgb2ycrcb* x, t_floatarg f) {x->x_blue = f; pdp_ut_rgb2ycrcb_bang(x);}
static void pdp_ut_rgb2ycrcb_free (t_pdp_ut_rgb2ycrcb* x) {}
static void* pdp_ut_rgb2ycrcb_new(void)
{
t_pdp_ut_rgb2ycrcb *x = (t_pdp_ut_rgb2ycrcb *)pd_new(pdp_ut_rgb2ycrcb_class);
inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("green"));
inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("blue"));
x->x_outlet_luma = outlet_new(&x->x_obj, &s_float);
x->x_outlet_chroma_red = outlet_new(&x->x_obj, &s_float);
x->x_outlet_chroma_blue = outlet_new(&x->x_obj, &s_float);
x->x_red = 0.0f;
x->x_green = 0.0f;
x->x_blue = 0.0f;
return (void *)x;
}
void pdp_ut_rgb2ycrcb_setup(void)
{
pdp_ut_rgb2ycrcb_class = class_new(gensym("pdp_ut_rgb2ycrcb"), (t_newmethod)pdp_ut_rgb2ycrcb_new,
(t_method)pdp_ut_rgb2ycrcb_free, sizeof(t_pdp_ut_rgb2ycrcb), 0, A_NULL);
class_addfloat(pdp_ut_rgb2ycrcb_class, pdp_ut_rgb2ycrcb_red);
class_addmethod(pdp_ut_rgb2ycrcb_class, (t_method)pdp_ut_rgb2ycrcb_green, gensym("green"), A_FLOAT, A_NULL);
class_addmethod(pdp_ut_rgb2ycrcb_class, (t_method)pdp_ut_rgb2ycrcb_blue, gensym("blue"), A_FLOAT, A_NULL);
}
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_ut_setup(void)
{
pdp_ut_addscaleclip_setup();
pdp_ut_logmap_setup();
pdp_ut_logmap_comp_setup();
pdp_ut_linmap_setup();
pdp_ut_rgb2ycrcb_setup();
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: pdp_queue.c ---
/*
* Pure Data Packet - processor queue module.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
this is a the processor queue pdp system module
it receives tasks from objects that are schedules to
be computed in another thread. the object is signalled back
when the task is completed, using a polling mechanism
based on a pd clock.
the queue object can be reused. the pdp system however only
has one instance (one pdp queue. pdp remains a serial program, though
it can run in a separate thread)
*/
#include <string.h>
#include "pdp_queue.h"
#include "pdp_mem.h"
#define D if (0)
#ifdef __cplusplus
extern "C"
{
#endif
#define PDP_QUEUE_LOGSIZE 10
#define PDP_QUEUE_DELTIME 10.0f
/* there are 3 synchro methods, which can be used i.e. to ensure
all processing is done before shared resources are freed.
all 3 wait for the processing thread to finish, and
_wait: leaves callback queue untouched
_finish: clears the queue_id item in the callback queue
_flush: waits for thread and calls callbacks
and loops until callback list is empty
*/
/********************* general purpose pd process queue class *********************/
void pdp_procqueue_wait(t_pdp_procqueue *q)
{
D post("pdp_procqueue_wait(%x): waiting for pdp_queue_thread to finish processing", q);
pthread_mutex_lock(&q->mut);
while(((q->curr - q->head) & q->mask) != 0){
pthread_cond_wait(&q->cond_processingdone, &q->mut);
}
pthread_mutex_unlock(&q->mut);
D post("pdp_procqueue_wait(%x): pdp_procqueue_thread has finished processing", q);
}
void pdp_procqueue_finish(t_pdp_procqueue *q, int index)
{
if (-1 == index) {
//post("pdp_pq_remove: index == -1");
return;
}
/* wait for processing thread to finish*/
pdp_procqueue_wait(q);
/* invalidate callback at index */
q->q[index & q->mask].x_callback = 0;
q->q[index & q->mask].x_queue_id = 0;
}
static void pdp_procqueue_callback (t_pdp_procqueue *q);
void pdp_procqueue_flush(t_pdp_procqueue *q)
{
/* wait once */
pdp_procqueue_wait(q);
do {
/* process callbacks and wait again
in case the callbacks introduced new tasks */
pdp_procqueue_callback(q);
pdp_procqueue_wait(q);
}
/* repeat if callback list is not empty */
while ((q->curr - q->head) & q->mask);
D post("pdp_procqueue_flush: done");
}
static void pdp_procqueue_signal_processor(t_pdp_procqueue *q)
{
//NOTE: uncommenting these post statements causes a libc crash
//in mutex lock in putc
//D post("pdp_procqueue_signal_processor(%x): signalling process thread", q);
pthread_mutex_lock(&q->mut);
pthread_cond_signal(&q->cond_dataready);
pthread_mutex_unlock(&q->mut);
//D post("pdp_procqueue_signal_processor(%x): signalling done", q);
}
static void pdp_procqueue_wait_for_feeder(t_pdp_procqueue *q)
{
/* only use locking when there is no data */
if(((q->curr - q->head) & q->mask) == 0){
/* signal processing done */
D post("pdp_procqueue_wait_for_feeder(%x): signalling processing is done", q);
pthread_mutex_lock(&q->mut);
pthread_cond_signal(&q->cond_processingdone);
/* wait until there is an item in the queue */
while(((q->curr - q->head) & q->mask) == 0){
pthread_cond_wait(&q->cond_dataready, &q->mut);
}
pthread_mutex_unlock(&q->mut);
D post("pdp_procqueue_wait_for_feeder(%x): waiting done", q);
}
}
int pdp_procqueue_full(t_pdp_procqueue *q)
{
return (1 == ((q->tail - q->head) & q->mask));
}
void pdp_procqueue_add(t_pdp_procqueue *q, void *owner, void *process, void *callback, int *queue_id)
{
int i;
/* if processing is in not in thread, just call the funcs */
if (!q->use_thread){
D post("pdp_procqueue_add(%q): calling processing routine directly", q);
if (queue_id) *queue_id = -1;
if (process) ((t_pdpmethod) process)(owner);
if (callback) ((t_pdpmethod) callback)(owner);
return;
}
/* if queue is full, print an error message and return */
if (pdp_procqueue_full(q)) {
post("pdp_procqueue_add: WARNING: processing queue (%x) is full.\n", q);
post("pdp_procqueue_add: WARNING: tail %08x, head %08x (%08x), mask %08x.\n", q->tail, q->head, q->head & q->mask, q->mask);
post("pdp_procqueue_add: WARNING: skipping process method, calling callback directly.\n");
if (queue_id) *queue_id = -1;
if (callback) ((t_pdpmethod) callback)(owner);
return;
//exit(1);
}
/* schedule method in thread queue */
i = q->head & q->mask;
q->q[i].x_owner = owner;
q->q[i].x_process = process;
q->q[i].x_callback = callback;
q->q[i].x_queue_id = queue_id;
if (queue_id) *queue_id = i;
//post("pdp_queue_add: added method to queue, index %d", i);
// increase the packet count
q->packets++;
// move head forward
q->head++;
pdp_procqueue_signal_processor(q);
}
/* processing thread */
static void *pdp_procqueue_thread(void *vq)
{
t_pdp_procqueue *q = (t_pdp_procqueue *)vq;
D post("pdp_procqueue_thread(%x): thread started", q);
while(1){
t_process_queue_item *p;
D post("pdp_procqueue_thread(%x): waiting for feeder", q);
/* wait until there is data available */
pdp_procqueue_wait_for_feeder(q);
D post("pdp_procqueue_thread(%x): processing %d", q, q->curr & q->mask);
/* call the process routine */
p = &q->q[q->curr & q->mask];
if (p->x_process)
(p->x_process)(p->x_owner);
/* advance */
q->curr++;
}
return 0;
}
/* call back all the callbacks */
static void pdp_procqueue_callback (t_pdp_procqueue *q)
{
/* call callbacks for finished packets */
while(0 != ((q->curr - q->tail) & q->mask))
{
int i = q->tail & q->mask;
/* invalidate queue id */
if(q->q[i].x_queue_id) *q->q[i].x_queue_id = -1;
/* call callback */
if(q->q[i].x_callback) (q->q[i].x_callback)(q->q[i].x_owner);
//else post("pdp_pq_tick: callback %d is disabled",i );
q->tail++;
}
}
/* the clock method */
static void pdp_procqueue_tick (t_pdp_procqueue *q)
{
/* do work */
//if (!(ticks % 1000)) post("pdp tick %d", ticks);
if (!q->use_thread) return;
/* call callbacks */
pdp_procqueue_callback(q);
/* increase counter */
q->ticks++;
/* set clock for next update */
clock_delay(q->pdp_clock, q->deltime);
}
void pdp_procqueue_use_thread(t_pdp_procqueue* q, int t)
{
/* if thread usage is being disabled,
wait for thread to finish processing first */
if (t == 0) {
pdp_procqueue_wait(q);
q->use_thread = 0;
pdp_procqueue_callback(q);
clock_unset(q->pdp_clock);
}
else {
clock_unset(q->pdp_clock);
clock_delay(q->pdp_clock, q->deltime);
q->use_thread = 1;
}
}
void pdp_procqueue_init(t_pdp_procqueue *q, double milliseconds, int logsize)
{
pthread_attr_t attr;
int size = 1 << logsize;
/* setup pdp queue processor object */
q->ticks = 0;
q->deltime = milliseconds;
/* setup queue data */
q->mask = size - 1;
q->head = 0;
q->tail = 0;
q->curr = 0;
q->q = pdp_alloc(size * sizeof(t_process_queue_item));
memset(q->q, 0, size * sizeof(t_process_queue_item));
/* enable threads */
q->use_thread = 1;
/* setup synchro stuff */
pthread_mutex_init(&q->mut, NULL);
pthread_cond_init(&q->cond_dataready, NULL);
pthread_cond_init(&q->cond_processingdone, NULL);
/* allocate the clock */
q->pdp_clock = clock_new(q, (t_method)pdp_procqueue_tick);
/* set the clock */
clock_delay(q->pdp_clock, 0);
/* start processing thread */
/* glibc doc says SCHED_OTHER is default,
but it seems not to be when initiated from a RT thread
so we explicitly set it here */
pthread_attr_init (&attr);
//pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
D post("pdp_procqueue_init(%x): starting thread", q);
pthread_create(&q->thread_id, &attr, pdp_procqueue_thread, (void *)q);
D post("pdp_procqueue_init(%x): back in pd thread", q);
/* wait for processing thread to finish */
//pdp_procqueue_wait(q);
/* set default disable/enable thread here */
//post("pdp_queue: THREAD PROCESSING ON BY DEFAULT!!");
pdp_procqueue_use_thread(q,0);
}
/* the (static) pdp queue object */
static t_pdp_procqueue pdp_queue;
/* get the default queue */
t_pdp_procqueue *pdp_queue_get_queue(void){return &pdp_queue;}
#if 1
/* default pdp queue shortcut methods */
void pdp_queue_wait() {pdp_procqueue_wait(&pdp_queue);}
void pdp_queue_finish(int index) { pdp_procqueue_finish(&pdp_queue, index);}
void pdp_queue_add(void *owner, void *process, void *callback, int *queue_id) {
pdp_procqueue_add(&pdp_queue, owner, process, callback, queue_id);
}
void pdp_queue_use_thread(int t) {pdp_procqueue_use_thread(&pdp_queue, t);}
void pdp_queue_setup(void){
pdp_procqueue_init(&pdp_queue, PDP_QUEUE_DELTIME, PDP_QUEUE_LOGSIZE);
pdp_procqueue_use_thread(&pdp_queue,0);
}
#endif
#ifdef __cplusplus
}
#endif
--- NEW FILE: pdp_base.c ---
/*
* Pure Data Packet base class implementation.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
This file contains the pdp base class object.
This is really nothing more than an attempt to stay away from c++
as far as possible, while having some kind of base class functionality
for pdp (tucking away the communication & thread protocol).
*/
#include "pdp_base.h"
#include <stdarg.h>
static void pdp_base_debug(t_pdp_base *b, t_floatarg f)
{
int i;
post("debug");
post("inlets: %d", b->b_inlets);
post("\tpacket\tnext_packet");
for (i=0; i<b->b_inlets; i++)
post("\t%d\t%d", b->b_packet[i], b->b_packet_next[i]);
//post("outlets: %d", b->b_inlets);
}
static void pdp_base_thread(t_pdp_base *b, t_floatarg f)
{
int i = (int)f;
if ((i == 0) || (i == 1)) b->b_thread_enabled = i;
}
static void pdp_base_process(t_pdp_base *b)
{
if (b->b_process_method)
(*b->b_process_method)(b);
}
/* this method is called after the thread has finished processing */
static void pdp_base_postprocess(t_pdp_base *b)
{
/* call the derived class postproc callback if there is any */
if (b->b_postproc_method)
(*b->b_postproc_method)(b);
/* unregister (mark unused) packet and propagate if packet is valid */
if (b->b_outlet[0])
pdp_pass_if_valid(b->b_outlet[0], &b->b_packet[0]);
}
/* move the passive packets in place */
void pdp_base_movepassive(void *x)
{
t_pdp_base *b = (t_pdp_base *)x;
int i;
/* if a cold packet was received in the meantime
swap it in, else keep the old one */
for (i=1; i<b->b_inlets; i++){
pdp_replace_if_valid(&b->b_packet[i], &b->b_packet_next[i]);
}
}
/* the standard bang method */
void pdp_base_bang(void *x)
{
t_pdp_base *b = (t_pdp_base *)x;
int i;
/* if pdp thread is still processing, do nothing */
if (-1 != b->b_queue_id) return;
/* move packets in place */
pdp_base_movepassive(x);
/* if there is a preproc method defined, call it inside
the pd thread. (mainly for allocations) */
if (b->b_preproc_method)
(*b->b_preproc_method)(b);
/* check if we need to use pdp queue */
if (b->b_thread_enabled){
/* add the process method and callback to the process queue */
pdp_procqueue_add(b->b_q, b, pdp_base_process, pdp_base_postprocess, &b->b_queue_id);
}
else{
/* call both methods directly */
pdp_base_process(b);
pdp_base_postprocess(b);
}
}
/* hot packet input handler */
void pdp_base_input_hot(t_pdp_base *b, t_symbol *s, t_floatarg f)
{
int p = (int)f;
/* dont register if active inlet is disabled */
if (!b->b_active_inlet_enabled) return;
/* register the packet (readonly or read/write)
or drop it if we have an active packet
if type template is not null, packet will be converted */
if (b->b_active_inlet_readonly){
if (s == S_REGISTER_RO){
if (b->b_type_template[0]){
pdp_packet_convert_ro_or_drop(&b->b_packet[0], p, b->b_type_template[0]);
}
else{
pdp_packet_copy_ro_or_drop(&b->b_packet[0], p);
}
}
}
else{
if (s == S_REGISTER_RW) {
if (b->b_type_template[0]){
pdp_packet_convert_rw_or_drop(&b->b_packet[0], p, b->b_type_template[0]);
}
else{
pdp_packet_copy_rw_or_drop(&b->b_packet[0], p);
}
}
}
/* start processing if there is an active packet to process
and the processing method is not active */
if ((s == S_PROCESS) && (-1 != b->b_packet[0]) && (-1 == b->b_queue_id)){
pdp_base_bang(b);
}
//if ((pdp_sym_prc() == s) && (-1 != b->b_packet[0]) && (!b->b_dropped)) pdp_base_bang(b);
}
/* cold packet input handlers */
void pdp_base_input_cold(t_pdp_base *b, t_symbol *s, int ac, t_atom *av)
{
int p;
int i;
char msg[] = "pdp1";
char *c;
int inlet;
//post("pdp_base_input_cold: got packet");
/* do cheap tests first */
if (ac != 2) return;
if (av[0].a_type != A_SYMBOL) return;
if (av[0].a_w.w_symbol != S_REGISTER_RO) return;
if (av[1].a_type != A_FLOAT) return;
p = (int)av[1].a_w.w_float;
/* check if it's a pdp message
and determine inlet */
for (i=1; i<MAX_NB_PDP_BASE_INLETS; i++){
if (s == gensym(msg)){
inlet = i;
goto found;
}
else{
msg[3]++;
}
}
return;
found:
/* store the packet and trow away
the old one, if there is any */
pdp_packet_copy_ro_or_drop(&b->b_packet_next[inlet], p);
}
void pdp_base_set_process_method(void *x, t_pdp_method m)
{
t_pdp_base *b = (t_pdp_base *)x;
b->b_process_method = m;
}
void pdp_base_set_preproc_method(void *x, t_pdp_method m)
{
t_pdp_base *b = (t_pdp_base *)x;
b->b_preproc_method = m;
}
void pdp_base_set_postproc_method(void *x, t_pdp_method m)
{
t_pdp_base *b = (t_pdp_base *)x;
b->b_postproc_method = m;
}
void pdp_base_queue_wait(void *x)
{
t_pdp_base *b = (t_pdp_base *)x;
pdp_procqueue_wait(b->b_q);
}
void pdp_base_set_queue(void *x, t_pdp_procqueue *q)
{
t_pdp_base *b = (t_pdp_base *)x;
pdp_base_queue_wait(x);
b->b_q = q;
}
t_pdp_procqueue *pdp_base_get_queue(void *x)
{
t_pdp_base *b = (t_pdp_base *)x;
return b->b_q;
}
void pdp_base_setup(t_class *c)
{
/* add pdp base class methods */
class_addmethod(c, (t_method)pdp_base_thread, gensym("thread"), A_FLOAT, A_NULL);
class_addmethod(c, (t_method)pdp_base_debug, gensym("debug"), A_NULL);
/* hot packet handler */
class_addmethod(c, (t_method)pdp_base_input_hot, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
/* cold packet handler */
class_addanything(c, (t_method)pdp_base_input_cold);
}
/* pdp base instance constructor */
void pdp_base_init(void *x)
{
int i;
t_pdp_base *b = (t_pdp_base *)x;
b->b_channel_mask = -1;
for(i=0; i<MAX_NB_PDP_BASE_INLETS; i++){
b->b_packet[i] = -1;
b->b_packet_next[i] = -1;
b->b_type_template[i] = 0;
}
b->b_queue_id = -1;
//b->b_dropped = 0;
b->b_process_method = 0;
b->b_preproc_method = 0;
b->b_inlets = 1;
b->b_outlets = 0;
b->b_active_inlet_enabled = 1;
b->b_active_inlet_readonly = 0;
b->b_thread_enabled = 1;
// default queue is pdp queue
b->b_q = pdp_queue_get_queue();
}
/* base instance destructor */
void pdp_base_free(void *x)
{
int i;
t_pdp_base *b = (t_pdp_base *)x;
/* remove process method from queue before deleting data */
pdp_procqueue_finish(b->b_q, b->b_queue_id);
/* delete stuff */
for(i=0; i<MAX_NB_PDP_BASE_INLETS; i++){
pdp_packet_mark_unused(b->b_packet[i]);
pdp_packet_mark_unused(b->b_packet_next[i]);
}
}
void pdp_base_readonly_active_inlet(void *x)
{
t_pdp_base *b = (t_pdp_base *)x;
b->b_active_inlet_readonly = 1;
}
void pdp_base_disable_active_inlet(void *x)
{
t_pdp_base *b = (t_pdp_base *)x;
b->b_active_inlet_enabled = 0;
}
/* add an inlet */
void pdp_base_add_pdp_inlet(void *x)
{
t_pdp_base *b = (t_pdp_base *)x;
char s[] = "pdp0";
s[3] += b->b_inlets;
if (b->b_inlets < MAX_NB_PDP_BASE_INLETS){
inlet_new(&b->x_obj, &b->x_obj.ob_pd, gensym("pdp"), gensym(s));
b->b_inlets++;
}
else {
post("pdp_base_add_pdp_inlet: only %d pdp inlets allowed. ignoring.", MAX_NB_PDP_BASE_INLETS);
}
}
/* add an outlet: only one allowed */
t_outlet *pdp_base_add_pdp_outlet(void *x)
{
t_pdp_base *b = (t_pdp_base *)x;
t_outlet *outlet = outlet_new(&b->x_obj, &s_anything);
if (b->b_outlets < MAX_NB_PDP_BASE_OUTLETS){
b->b_outlet[b->b_outlets] = outlet;
b->b_outlets++;
}
return outlet;
}
void pdp_base_set_packet(void *x, int inlet, int packet)
{
t_pdp_base *b = (t_pdp_base *)x;
if (inlet < b->b_inlets){
//post("%d %d", b->b_packet[inlet], b->b_packet_next[inlet]);
pdp_packet_mark_unused(b->b_packet[inlet]);
b->b_packet[inlet] = packet;
}
}
int pdp_base_get_packet(void *x, int inlet)
{
t_pdp_base *b = (t_pdp_base *)x;
if (inlet < b->b_inlets){
//post("%d %d", b->b_packet[inlet], b->b_packet_next[inlet]);
return (b->b_packet[inlet]);
}
return -1;
}
int pdp_base_move_packet(void *x, int inlet)
{
t_pdp_base *b = (t_pdp_base *)x;
int p;
if (inlet < b->b_inlets){
p = b->b_packet[inlet];
b->b_packet[inlet] = -1;
return (p);
}
return -1;
}
t_object *pdp_base_get_object(void *x)
{
return (t_object *)x;
}
void pdp_base_add_gen_inlet(void *x, t_symbol *from, t_symbol *to)
{
t_object *o = (t_object *)x;
inlet_new(o, &o->ob_pd, from, to);
}
void pdp_base_disable_thread(void *x)
{
t_pdp_base *b = (t_pdp_base *)x;
b->b_thread_enabled = 0;
}
void pdp_base_set_type_template(void *x, int inlet, t_pdp_symbol *type_template)
{
t_pdp_base *b = (t_pdp_base *)x;
if (inlet < b->b_inlets){
b->b_type_template[inlet] = type_template;
}
}
Update of /cvsroot/pure-data/externals/pdp/opengl/include
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6756/opengl/include
Added Files:
Makefile pdp_3Dcontext.h pdp_3dp_base.h pdp_mesh.h
pdp_opengl.h pdp_texture.h
Log Message:
checking in pdp 0.12.4 from http://zwizwa.fartit.com/pd/pdp/pdp-0.12.4.tar.gz
--- NEW FILE: pdp_mesh.h ---
/*
* Pure Data Packet module. mesh object specification
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/* a very naive approach to triangular meshes */
#ifndef PDP_MESH_H
#define PDP_MESH_H
#include "pdp_list.h"
/* VERTEX type
a vertex has a coordinate and normal vector
a list of triangles it is connected to
and a list of vertexes it is connected to (these count as links) */
typedef struct _vertex
{
float c[3]; // coordinates
float n[3]; // normal (or force vector)
t_pdp_list *trilist;
t_pdp_list *vertlist;
} t_vertex;
/* TRIANGLE type:
a triangle consist of
- 3 vertices
- 3 optional median vertices (subdivision intermediates) */
typedef struct _triangle
{
t_vertex *v[3]; // vertices
t_vertex *m[3]; // median vertices
float n[3]; //triangle normal
} t_triangle;
/* MESH type:
a mesh is a list of vertices
and a list of triangles (connections) */
typedef struct _mesh
{
t_pdp_list *triangles;
t_pdp_list *vertices;
int normal_type;
int refine_type;
} t_mesh;
/* object configuratie */
#define MESH_NORMAL_SPHERE 1 // normal = origin -> vertex
#define MESH_NORMAL_PRISM 2 // normal = center of gravity of prism base -> vertex
#define MESH_NORMAL_RANDOM 3 // normal = random vector
#define MESH_NORMAL_AVERAGE 4 // normal = average of surrounding triangles
/* refinement method */
#define MESH_REFINE_THREE 1 // triangle -> 3 triangles connecting center of gravity
#define MESH_REFINE_FOUR 2 // triangle -> 4 triangles connecting link medians
// vector utility stuff
// fixed size iterators for the lazy
#define I3(i) for(i=0; i<3; i++)
#define I4(i) for(i=0; i<4; i++)
static inline float _vector3_dot(float *v0, float *v1)
{
float d;
d = v0[0] * v1[0];
d += v0[1] * v1[1];
d += v0[2] * v1[2];
return d;
}
static inline void _vector3_scale(float *v, float s)
{
int k;
I3(k) v[k] *= s;
}
static inline float _vector3_normalize(float *v)
{
float length = 0;
float scale = 0;
int k;
length = sqrt(_vector3_dot(v,v));
scale = 1.0f / length;
_vector3_scale(v, scale);
return length;
}
static inline void _vector3_cross(float *a, float *b, float *r)
{
r[0] = a[1]*b[2] - a[2]*b[1];
r[1] = a[2]*b[0] - a[0]*b[2];
r[2] = a[0]*b[1] - a[1]*b[0];
}
static inline float _rand(void)
{
long int r = random();
float f;
r -= (RAND_MAX >> 1);
f = (float)r;
f *= (2.0f / (float)RAND_MAX);
return f;
}
/* VERTEX methods */
void vertex_add_triangle(t_vertex *v, t_triangle *t);
void vertex_remove_triangle(t_vertex *v, t_triangle *t);
void vertex_add_neighbour(t_vertex *v, t_vertex *neighbour);
/* constructor/destructors are "private"
they may only be called by the mesh object to ensure
the vector list stays sound (i.e. without duplicates) */
void _vertex_free(t_vertex *v);
t_vertex *_vertex_new(float *c, float *n);
void vertex_compute_normal_random(t_vertex *v);
void vertex_compute_normal_sphere(t_vertex *v);
void vertex_compute_normal_prism(t_vertex *v);
float vertex_normalize(t_vertex *v);
/* TRIANGLE methods */
/* create triangle (a connection between 3 vertices):
counterclockwize with facing front
this method is "private"
you can only create triangles as part of a mesh */
t_triangle *_triangle_new(t_vertex *v0, t_vertex *v1, t_vertex *v2);
/* delete a triangle, disconnecting the vertices */
void _triangle_free(t_triangle *t);
/* get triangle that shares the link between v0 and v1 */
t_triangle *triangle_neighbour(t_triangle *t, t_vertex *v0, t_vertex *v1);
/* add a median vector to a link in a triangle
note: vertices must be in triangle, or behaviour is undefined */
void triangle_add_median(t_triangle *t, t_vertex *v0, t_vertex *v1, t_vertex *median);
/* MESH methods */
/* add and remove methods for vertices and triangles */
t_vertex *mesh_vertex_add(t_mesh *m, float *c, float *n);
void mesh_vertex_remove(t_mesh *m, t_vertex *v);
t_triangle *mesh_triangle_add(t_mesh *m, t_vertex *v0, t_vertex *v1, t_vertex *v2);
void mesh_triangle_remove(t_mesh *m, t_triangle *t);
/* calculate normals */
void mesh_calculate_normals(t_mesh *m);
/* split a triangle in 4, using the intermedia median vertex storage */
void mesh_split_four(t_mesh *m, t_triangle *old_t);
/* split a triangle in 3 */
void mesh_split_three(t_mesh *m, t_triangle *old_t);
void mesh_split_all_four(t_mesh *m);
void mesh_split_all_three(t_mesh *m);
void mesh_split_random_three(t_mesh *m);
void mesh_free(t_mesh *m);
t_mesh *_mesh_new(void);
/* new tetra */
t_mesh *mesh_new_tetra(void);
void _mesh_relax_compute_resultant_spring(t_mesh *m, float *center, float d0, float r0);
void _mesh_relax_apply_force(t_mesh *m, float k);
void mesh_compute_center(t_mesh *m, float *c);
void mesh_translate(t_mesh *m, float *c);
/* relax a mesh (move toward equal link length) */
void mesh_relax(t_mesh *m, float step, float d0, float r0);
/* print some debug information */
void mesh_debug(t_mesh *m);
#endif
--- NEW FILE: Makefile ---
all:
clean:
rm -rf *~
--- NEW FILE: pdp_3dp_base.h ---
#include "pdp_opengl.h"
#include "pdp_dpd_base.h"
typedef struct _pdp_3dp_base
{
t_pdp_dpd_base b_base;
} t_pdp_3dp_base;
/* destructor */
void pdp_3dp_base_free(void *x);
/* init method */
void pdp_3dp_base_init(void *x);
/* class setup method */
void pdp_3dp_base_setup(t_class *class);
/* base class methods */
#define pdp_3dp_base_get_context_packet pdp_dpd_base_get_context_packet
#define pdp_3dp_base_set_context_packet pdp_dpd_base_set_context_packet
#define pdp_3dp_base_add_outlet pdp_dpd_base_add_outlet
#define pdp_3dp_base_add_cleanup pdp_dpd_base_add_cleanup
#define pdp_3dp_base_add_inspect pdp_dpd_base_add_inspect
#define pdp_3dp_base_disable_active_inlet pdp_dpd_base_disable_active_inlet
#define pdp_3dp_base_move_context_packet pdp_dpd_base_move_context_packet
#define pdp_3dp_base_bang pdp_dpd_base_bang
#define pdp_3dp_base_get_queue pdp_dpd_base_get_queue
#define pdp_3dp_base_enable_outlet pdp_dpd_base_enable_outlet
#define pdp_3dp_base_register_complete_notify pdp_dpd_base_register_complete_notify
#define pdp_3dp_base_register_get_command_object pdp_dpd_base_register_get_command_object
#define pdp_3dp_base_queue_wait pdp_dpd_base_queue_wait
#define pdp_3dp_base_queue_command pdp_dpd_base_queue_command
--- NEW FILE: pdp_opengl.h ---
/*
* OpenGL Extension Module for pdp - Main header file
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef PDP_OPENGL_H
#define PDP_OPENGL_H
#include "pdp.h"
#include "pdp_texture.h"
#include "pdp_3Dcontext.h"
t_pdp_procqueue* pdp_opengl_get_queue(void);
#endif
--- NEW FILE: pdp_3Dcontext.h ---
/*
* pdp system module - 3d render context packet type
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/* the 3d render context packet: platform independent data structure
and method prototypes */
#ifndef PDP_3DCONTEXT_H
#define PDP_3DCONTEXT_H
#include "pdp.h"
typedef struct _3dcontext
{
u32 encoding; /* the kind of render context */
u32 width; /* context width */
u32 height; /* context height */
u32 sub_width; /* portion that is currently used */
u32 sub_height;
void *drawable; /* context's drawable (i.e. Window, GLXPbuffer, ...) */
void *context; /* context's context object */
} t_3Dcontext;
#define PDP_3DCONTEXT 5 /* 3d context packet id */
#define PDP_3DCONTEXT_WINDOW 1 /* window context packet id */
#define PDP_3DCONTEXT_PBUFFER 2 /* pbuf context packet id */
/* all symbols are C-style */
#ifdef __cplusplus
extern "C"
{
#endif
/* info methods */
u32 pdp_packet_3Dcontext_width(int packet);
u32 pdp_packet_3Dcontext_subwidth(int packet);
u32 pdp_packet_3Dcontext_height(int packet);
u32 pdp_packet_3Dcontext_subheight(int packet);
float pdp_packet_3Dcontext_subaspect(int packet);
int pdp_packet_3Dcontext_isvalid(int packet);
t_3Dcontext *pdp_packet_3Dcontext_info(int packet);
/* setters */
void pdp_packet_3Dcontext_set_subwidth(int packet, u32 w);
void pdp_packet_3Dcontext_set_subheight(int packet, u32 h);
/* render context activation and initialization */
void pdp_packet_3Dcontext_set_rendering_context(int packet);
void pdp_packet_3Dcontext_unset_rendering_context(int packet);
void pdp_packet_3Dcontext_setup_3d_context(int p);
void pdp_packet_3Dcontext_setup_2d_context(int p);
/* constructors */
int pdp_packet_new_3Dcontext_pbuf(u32 width, u32 height, u32 depth);
int pdp_packet_new_3Dcontext_win(void);
/* window specific methods */
void pdp_packet_3Dcontext_win_resize(int packet, int width, int height);
t_pdp_list *pdp_packet_3Dcontext_win_get_eventlist(int packet);
void pdp_packet_3Dcontext_win_cursor(int packet, bool toggle);
void pdp_packet_3Dcontext_win_swapbuffers(int packet);
/* converters */
int pdp_packet_3Dcontext_snap_to_bitmap(int packet, int w, int h);
#ifdef __cplusplus
}
#endif
#endif
--- NEW FILE: pdp_texture.h ---
/*
* pdp system module - texture packet type
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef PDP_TEXTURE_H
#define PDP_TEXTURE_H
//#include <GL/gl.h>
//#include <GL/glu.h>
//#include <GL/glx.h>
//#include <GL/glut.h>
#include "pdp.h"
/* TEXTURE PACKET */
typedef struct
{
u32 tex_obj; /* gl texture object */
s32 format; /* texture format */
u32 width; /* dims */
u32 height;
u32 sub_width; /* portion of texture used */
u32 sub_height;
} t_texture;
#define PDP_TEXTURE 4 /* opengl texture object */
/* all symbols are C-style */
#ifdef __cplusplus
extern "C"
{
#endif
/* check if valid texture packet. all other methods assume packet is valid */
bool pdp_packet_texture_isvalid(int packet);
/* returns a pointer to the packet subheader whem the packet contains a texture */
/* try not to use the header directly, use clone and copy methods instead */
t_texture *pdp_packet_texture_info(int packet);
/* texture constructors */
int pdp_packet_new_texture(u32 width, u32 height, s32 format); /* create a texture packet */
/* texture operators */
void pdp_packet_texture_make_current(int packet); /* make a texture the current texture context */
u32 pdp_packet_texture_total_width(int packet); /* width of texture */
u32 pdp_packet_texture_total_height(int packet); /* get heigth of texture */
u32 pdp_packet_texture_sub_width(int packet); /* width of subtexture */
u32 pdp_packet_texture_sub_height(int packet); /* heigth of subtexture */
float pdp_packet_texture_fracx(int packet); /* x fraction */
float pdp_packet_texture_fracy(int packet); /* y fraction */
float pdp_packet_texture_sub_aspect(int packet);
/* some utility methods */
void pdp_packet_texture_make_current_enable(int packet); /* make current & enable with default texture settings (for the lazy)*/
void pdp_packet_texture_setup_2d_context(int packet); /* set up 2d context (viewport, projection, modelview) from texture dims */
#ifdef __cplusplus
}
#endif
#endif //PDP_TEXTURE_H
Update of /cvsroot/pure-data/externals/pdp/opengl/modules
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6756/opengl/modules
Added Files:
Makefile README pdp_3d_color.c pdp_3d_context.c pdp_3d_dlist.c
pdp_3d_draw.c pdp_3d_drawmesh.c pdp_3d_for.c pdp_3d_light.c
pdp_3d_push.c pdp_3d_snap.c pdp_3d_state.c pdp_3d_subcontext.c
pdp_3d_view.c pdp_3d_windowcontext.c
Log Message:
checking in pdp 0.12.4 from http://zwizwa.fartit.com/pd/pdp/pdp-0.12.4.tar.gz
--- NEW FILE: pdp_3d_color.c ---
/*
* Pure Data Packet module.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <GL/gl.h>
#include "pdp_3dp_base.h"
#include "pdp_opengl.h"
typedef struct _color_command
{
t_pdp_dpd_command x_base;
int x_context;
float x_newcolor[4];
float x_oldcolor[4];
} t_color_command;
typedef struct _pdp_3d_color
{
t_pdp_3dp_base x_base;
t_pdp_dpd_commandfactory x_cfact;
float x_red;
float x_green;
float x_blue;
float x_alpha;
} t_pdp_3d_color;
/* COMMAND METHODS */
static void pdp_3d_color_process_right(t_color_command *x)
{
int p = x->x_context;
if (pdp_packet_3Dcontext_isvalid(p)){
pdp_packet_3Dcontext_set_rendering_context(p);
/* save old color*/
glGetFloatv(GL_CURRENT_COLOR, x->x_oldcolor);
/* set new color */
glColor4fv(x->x_newcolor);
}
}
static void pdp_3d_color_process_left(t_color_command *x)
{
int p = x->x_context;
if (pdp_packet_3Dcontext_isvalid(p)){
pdp_packet_3Dcontext_set_rendering_context(p);
/* restore old color */
glColor4fv(x->x_oldcolor);
//glColor4f(1,1,1,1);
}
/* kill self */
pdp_dpd_command_suicide(x);
}
/* PD OBJECT METHODS */
static void *pdp_3d_color_get_new_command(t_pdp_3d_color *x)
{
t_color_command *c = (t_color_command *)pdp_dpd_commandfactory_get_new_command(&x->x_cfact);
c->x_newcolor[0] = x->x_red;
c->x_newcolor[1] = x->x_green;
c->x_newcolor[2] = x->x_blue;
c->x_newcolor[3] = x->x_alpha;
c->x_context = pdp_3dp_base_get_context_packet(x);
return (void *)c;
}
static void pdp_3d_color_set_r(t_pdp_3d_color *x, t_floatarg f) {x->x_red = f;}
static void pdp_3d_color_set_g(t_pdp_3d_color *x, t_floatarg f) {x->x_green = f;}
static void pdp_3d_color_set_b(t_pdp_3d_color *x, t_floatarg f) {x->x_blue = f;}
static void pdp_3d_color_set_a(t_pdp_3d_color *x, t_floatarg f) {x->x_alpha = f;}
t_class *pdp_3d_color_class;
void pdp_3d_color_free(t_pdp_3d_color *x)
{
pdp_3dp_base_free(x);
}
void *pdp_3d_color_new(t_floatarg r, t_floatarg g, t_floatarg b, t_floatarg a)
{
t_pdp_3d_color *x = (t_pdp_3d_color *)pd_new(pdp_3d_color_class);
/* super init */
pdp_3dp_base_init(x);
/* input */
pdp_base_add_gen_inlet(x, gensym("float"), gensym("r"));
pdp_base_add_gen_inlet(x, gensym("float"), gensym("g"));
pdp_base_add_gen_inlet(x, gensym("float"), gensym("b"));
pdp_base_add_gen_inlet(x, gensym("float"), gensym("a"));
/* output */
pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_color_process_left, 0);
pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_color_process_right, 0);
x->x_red = r;
x->x_green = g;
x->x_blue = b;
x->x_alpha = a;
/* init factory */
pdp_dpd_commandfactory_init(&x->x_cfact, sizeof(t_color_command));
/* register command factory method */
pdp_dpd_base_register_command_factory_method(x, (t_pdp_newmethod)pdp_3d_color_get_new_command);
return (void *)x;
}
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_3d_color_setup(void)
{
pdp_3d_color_class = class_new(gensym("3dp_color"), (t_newmethod)pdp_3d_color_new,
(t_method)pdp_3d_color_free, sizeof(t_pdp_3d_color), 0,
A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
pdp_3dp_base_setup(pdp_3d_color_class);
class_addmethod(pdp_3d_color_class, (t_method)pdp_3d_color_set_r, gensym("r"), A_FLOAT, A_NULL);
class_addmethod(pdp_3d_color_class, (t_method)pdp_3d_color_set_g, gensym("g"), A_FLOAT, A_NULL);
class_addmethod(pdp_3d_color_class, (t_method)pdp_3d_color_set_b, gensym("b"), A_FLOAT, A_NULL);
class_addmethod(pdp_3d_color_class, (t_method)pdp_3d_color_set_a, gensym("a"), A_FLOAT, A_NULL);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: pdp_3d_drawmesh.c ---
/*
* Pure Data Packet module.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/* a very naive approach to triangular meshes */
// $$TODO: some serious memory corruption in this file our the list implementation
#include "GL/gl.h"
#include <math.h>
//#include <GL/glut.h>
#include "pdp_opengl.h"
#include "pdp_3dp_base.h"
#include "pdp_mesh.h"
/* PD OBJECT */
typedef struct _pdp_3d_drawmesh
{
t_pdp_3dp_base x_base;
t_pdp_dpd_commandfactory x_clist;
t_mesh *x_mesh;
int x_wireframe;
int x_flatshading;
} t_pdp_3d_drawmesh;
/* MESHCOMMAND OBJECT */
typedef struct _meshcommand
{
t_pdp_dpd_command x_head;
int x_context_packet;
int x_texture_packet;
t_pdp_3d_drawmesh *x_mother;
t_pdp_method x_method;
int x_wireframe;
int x_flatshading;
float x_step;
float x_d0;
float x_r0;
int x_normal_type;
} t_meshcommand;
/* MESHCOMMAND METHODS */
/* draw the mesh */
static void meshcommand_draw(t_meshcommand *x)
{
int i = 0;
t_pdp_atom *it;
t_pdp_list *tl = x->x_mother->x_mesh->triangles;
t_triangle *t;
GLenum mode = (x->x_wireframe) ? GL_LINE_LOOP : GL_TRIANGLES;
//glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
glLineWidth(5);
glBegin(mode);
if (x->x_flatshading){
PDP_POINTER_IN(tl, it, t){
glNormal3fv(t->n);
for (i=0; i<3; i++){
glVertex3fv(t->v[i]->c);
}
}
}
else{
PDP_POINTER_IN(tl, it, t){
for (i=0; i<3; i++){
glNormal3fv(t->v[i]->n);
glVertex3fv(t->v[i]->c);
}
}
}
glEnd();
}
static void meshcommand_relax(t_meshcommand *x)
{
mesh_relax(x->x_mother->x_mesh, x->x_step, x->x_d0, x->x_r0);
}
/* the main subcommand dispatcher */
static void meshcommand_execute(t_meshcommand *x)
{
int p = x->x_context_packet;
/* check if it's a valid buffer we can draw in */
if (pdp_packet_3Dcontext_isvalid(p)){
/* setup rendering context */
pdp_packet_3Dcontext_set_rendering_context(p);
/* call the command method */
if (x->x_method) (x->x_method)(x);
}
/* you know the drill: command done, sword in belly. */
pdp_dpd_command_suicide(x);
}
static void meshcommand_split_all_four(t_meshcommand *x)
{
mesh_split_all_four(x->x_mother->x_mesh);
}
static void meshcommand_split_all_three(t_meshcommand *x){
mesh_split_all_three(x->x_mother->x_mesh);
}
static void meshcommand_split_random_three(t_meshcommand *x){
mesh_split_random_three(x->x_mother->x_mesh);
}
static void meshcommand_reset(t_meshcommand *x)
{
mesh_free(x->x_mother->x_mesh);
x->x_mother->x_mesh = mesh_new_tetra();
}
static void meshcommand_debug(t_meshcommand *x)
{
mesh_debug(x->x_mother->x_mesh);
}
static void meshcommand_calculate_normals(t_meshcommand *x)
{
x->x_mother->x_mesh->normal_type = x->x_normal_type;
mesh_calculate_normals(x->x_mother->x_mesh);
}
/* PD OBJECT METHODS */
/* return a new command object */
void *pdp_3d_drawmesh_get_command_object(t_pdp_3d_drawmesh *x)
{
t_meshcommand *c = (t_meshcommand *)pdp_dpd_commandfactory_get_new_command(&x->x_clist);
c->x_context_packet = pdp_3dp_base_get_context_packet(x);
c->x_mother = x;
c->x_method = (t_pdp_method)meshcommand_draw; //default command is draw
c->x_wireframe = x->x_wireframe;
c->x_flatshading = x->x_flatshading;
return c;
}
/* schedule a command */
static void pdp_3d_drawmesh_queue_command(t_pdp_3d_drawmesh *x, t_meshcommand *c)
{
pdp_3dp_base_queue_command(x, c, (t_pdp_method)meshcommand_execute, 0, 0);
}
static void pdp_3d_drawmesh_queue_simple_command(t_pdp_3d_drawmesh *x, t_pdp_method method)
{
t_meshcommand *c = (t_meshcommand *)pdp_3d_drawmesh_get_command_object(x);
c->x_method = method;
pdp_3dp_base_queue_command(x, c, (t_pdp_method)meshcommand_execute, 0, 0);
}
//NOTE: only the meshcommands are entitled to use the mesh (thread issues)
//therefore all mesh manipulations must be queued as a command
static void pdp_3d_drawmesh_debug(t_pdp_3d_drawmesh *x)
{
pdp_3d_drawmesh_queue_simple_command(x, (t_pdp_method)meshcommand_debug);
}
static void pdp_3d_drawmesh_relax(t_pdp_3d_drawmesh *x, t_floatarg step,
t_floatarg d0, t_floatarg r0)
{
t_meshcommand *c = (t_meshcommand *)pdp_3d_drawmesh_get_command_object(x);
c->x_step = step;
c->x_d0 = d0;
c->x_r0 = r0;
c->x_method = (t_pdp_method)meshcommand_relax;
pdp_3d_drawmesh_queue_command(x, c);
}
void pdp_3d_drawmesh_normal(t_pdp_3d_drawmesh *x, t_symbol *s)
{
t_meshcommand *c = (t_meshcommand *)pdp_3d_drawmesh_get_command_object(x);
if (gensym("sphere") == s) c->x_normal_type = MESH_NORMAL_SPHERE;
else if (gensym("prism") == s) c->x_normal_type = MESH_NORMAL_PRISM;
else if (gensym("random") == s) c->x_normal_type = MESH_NORMAL_RANDOM;
else if (gensym("average") == s) c->x_normal_type = MESH_NORMAL_AVERAGE;
c->x_method = (t_pdp_method)meshcommand_calculate_normals;
pdp_3d_drawmesh_queue_command(x, c);
}
/* this is used by the standard drawing routine, so doesn't need to be scheduled */
void pdp_3d_drawmesh_wireframe(t_pdp_3d_drawmesh *x, t_float f)
{
x->x_wireframe = (f != 0.0f);
}
void pdp_3d_drawmesh_flatshading(t_pdp_3d_drawmesh *x, t_float f)
{
x->x_flatshading = (f != 0.0f);
}
static void pdp_3d_drawmesh_split_all_four(t_pdp_3d_drawmesh *x)
{
pdp_3d_drawmesh_queue_simple_command(x, (t_pdp_method)meshcommand_split_all_four);
}
static void pdp_3d_drawmesh_split_all_three(t_pdp_3d_drawmesh *x)
{
pdp_3d_drawmesh_queue_simple_command(x, (t_pdp_method)meshcommand_split_all_three);
}
static void pdp_3d_drawmesh_split_random_three(t_pdp_3d_drawmesh *x)
{
pdp_3d_drawmesh_queue_simple_command(x, (t_pdp_method)meshcommand_split_random_three);
}
static void pdp_3d_drawmesh_reset(t_pdp_3d_drawmesh *x)
{
pdp_3d_drawmesh_queue_simple_command(x, (t_pdp_method)meshcommand_reset);
}
t_class *pdp_3d_drawmesh_class;
void pdp_3d_drawmesh_free(t_pdp_3d_drawmesh *x)
{
/* queue needs to finish before mesh is deleted */
pdp_3dp_base_queue_wait(x);
mesh_free(x->x_mesh);
pdp_3dp_base_free(x);
pdp_dpd_commandfactory_free(&x->x_clist);
}
void *pdp_3d_drawmesh_new(t_symbol *s, t_floatarg p0, t_floatarg p1, t_floatarg p2, t_floatarg p3)
{
t_pdp_3d_drawmesh *x = (t_pdp_3d_drawmesh *)pd_new(pdp_3d_drawmesh_class);
/* super init */
pdp_3dp_base_init(x);
/* create dpd outlet */
pdp_3dp_base_add_outlet(x, (t_pdp_method)meshcommand_execute, 0);
/* init command list */
pdp_dpd_commandfactory_init(&x->x_clist, sizeof(t_meshcommand));
/* register command factory method */
pdp_dpd_base_register_command_factory_method(x, (t_pdp_newmethod)pdp_3d_drawmesh_get_command_object);
/* initialize triangular mesh with a simply connected manifold */
x->x_mesh = mesh_new_tetra();
x->x_wireframe = 0;
x->x_flatshading = 0;
return (void *)x;
}
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_3d_drawmesh_setup(void)
{
pdp_3d_drawmesh_class = class_new(gensym("3dp_drawmesh"), (t_newmethod)pdp_3d_drawmesh_new,
(t_method)pdp_3d_drawmesh_free, sizeof(t_pdp_3d_drawmesh), 0, A_DEFSYMBOL,
A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
pdp_3dp_base_setup(pdp_3d_drawmesh_class);
class_addmethod(pdp_3d_drawmesh_class, (t_method)pdp_3d_drawmesh_split_random_three, gensym("split3random"), A_NULL);
class_addmethod(pdp_3d_drawmesh_class, (t_method)pdp_3d_drawmesh_split_all_three, gensym("split3"), A_NULL);
class_addmethod(pdp_3d_drawmesh_class, (t_method)pdp_3d_drawmesh_split_all_four, gensym("split4"), A_NULL);
class_addmethod(pdp_3d_drawmesh_class, (t_method)pdp_3d_drawmesh_reset, gensym("reset"), A_NULL);
class_addmethod(pdp_3d_drawmesh_class, (t_method)pdp_3d_drawmesh_normal, gensym("normal"), A_SYMBOL, A_NULL);
class_addmethod(pdp_3d_drawmesh_class, (t_method)pdp_3d_drawmesh_relax, gensym("springrelax"),
A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
class_addmethod(pdp_3d_drawmesh_class, (t_method)pdp_3d_drawmesh_debug, gensym("info"), A_NULL);
class_addmethod(pdp_3d_drawmesh_class, (t_method)pdp_3d_drawmesh_wireframe, gensym("wireframe"), A_FLOAT, A_NULL);
class_addmethod(pdp_3d_drawmesh_class, (t_method)pdp_3d_drawmesh_flatshading, gensym("flatshading"), A_FLOAT, A_NULL);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: pdp_3d_state.c ---
/*
* Pure Data Packet module.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/* change binary opengl state variables. all defaults (flag = 0) should be set
in the render context init.
right outlet has the thing enabled (or disabled, depending on toggle)
left outlet has the thing disabled (better: it should push it)
simple version: does not permit reentry (yet) */
#include <GL/gl.h>
#include "pdp_opengl.h"
#include "pdp_3dp_base.h"
typedef struct pdp_3d_state_struct
{
t_pdp_3dp_base x_base;
GLboolean x_flag;
GLboolean x_prev_flag;
GLenum x_thing;
void (*x_setup)(void);
} t_pdp_3d_state;
static void _setflag(GLenum thing, GLboolean flag)
{
if (flag) glEnable(thing);
else glDisable(thing);
}
static void pdp_3d_state_process_right(t_pdp_3d_state *x)
{
int p;
if (-1 != (p = pdp_3dp_base_get_context_packet(x))){
/* store previous flag */
pdp_packet_3Dcontext_set_rendering_context(p);
glGetBooleanv(x->x_thing, &x->x_prev_flag);
_setflag(x->x_thing, x->x_flag);
if (x->x_setup) x->x_setup();
}
}
static void pdp_3d_state_process_left(t_pdp_3d_state *x)
{
int p;
/* allways run left method (reset) */
if (-1 != (p = pdp_3dp_base_get_context_packet(x))){
pdp_packet_3Dcontext_set_rendering_context(p);
_setflag(x->x_thing, x->x_prev_flag);
}
}
static void pdp_3d_state_flag(t_pdp_3d_state *x, t_floatarg f)
{
x->x_flag = (f == 0.0f) ? GL_FALSE : GL_TRUE;
}
static void _blend(void) {glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);}
static void _blend_add(void) {glBlendFunc(GL_SRC_ALPHA, GL_ONE);}
t_class *pdp_3d_state_class;
void pdp_3d_state_free(t_pdp_3d_state *x){pdp_3dp_base_free(x);}
void *pdp_3d_state_new(t_symbol *s, t_floatarg f)
{
t_pdp_3d_state *x = (t_pdp_3d_state *)pd_new(pdp_3d_state_class);
/* super init */
pdp_3dp_base_init(x);
pdp_3d_state_flag(x,f);
if (s == gensym("blend_mix")) {x->x_setup = _blend; x->x_thing = GL_BLEND;}
else if (s == gensym("blend_add")) {x->x_setup = _blend_add; x->x_thing = GL_BLEND;}
else if (s == gensym("depth_test")) {x->x_setup = 0; x->x_thing = GL_DEPTH_TEST;}
/* unkown command: do nothing */
else {
post ("3dp_state: unknown flag %s", s->s_name);
pd_free((void *)x);
return 0;
}
/* create additional inlet */
pdp_base_add_gen_inlet(x, gensym("float"), gensym("flag"));
/* create dpd outlets */
pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_state_process_left, 0);
pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_state_process_right, 0);
return (void *)x;
}
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_3d_state_setup(void)
{
pdp_3d_state_class = class_new(gensym("3dp_toggle"), (t_newmethod)pdp_3d_state_new,
(t_method)pdp_3d_state_free, sizeof(t_pdp_3d_state), 0, A_SYMBOL, A_DEFFLOAT, A_NULL);
pdp_3dp_base_setup(pdp_3d_state_class);
class_addmethod(pdp_3d_state_class, (t_method)pdp_3d_state_flag, gensym("flag"), A_FLOAT, A_NULL);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: Makefile ---
include ../Makefile.config
all: pdp_3d_windowcontext.o pdp_3d_draw.o pdp_3d_view.o \
pdp_3d_push.o pdp_3d_light.o pdp_3d_dlist.o pdp_3d_color.o \
pdp_3d_snap.o pdp_3d_drawmesh.o pdp_3d_for.o pdp_3d_state.o \
pdp_3d_subcontext.o
clean:
rm -rf *~ *.o
--- NEW FILE: README ---
This directory contains opengl modules for the pdp_opengl library.
--- NEW FILE: pdp_3d_dlist.c ---
/*
* Pure Data Packet module.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <GL/gl.h>
#include "pdp_opengl.h"
#include "pdp_3dp_base.h"
/* gl display list compilation & execution */
typedef struct pdp_3d_dlist_struct
{
t_pdp_3dp_base x_base;
GLuint x_dlist;
int x_compile;
} t_pdp_3d_dlist;
static void pdp_3d_dlist_complete_notify(t_pdp_3d_dlist *x)
{
/* disable the second outlet */
pdp_3dp_base_enable_outlet(x, 0, 0);
}
static void pdp_3d_dlist_compile(t_pdp_3d_dlist *x)
{
//x->x_compile = 1;
/* enable the second outlet */
pdp_3dp_base_enable_outlet(x, 0, 1);
}
static void pdp_3d_dlist_process_start(t_pdp_3d_dlist *x)
{
int p = pdp_3dp_base_get_context_packet(x);
if (-1 != p){
/* check if pbuf */
if (pdp_packet_3Dcontext_isvalid(p)){
/* set context */
//pdp_pbuf_set_rendering_context(p);
/* display list needs to be created in the correct context
if we don't have one yet, create it */
if (!x->x_dlist) x->x_dlist = glGenLists(1);
/* start the list */ /* $$$TODO: error checking for recursion */
x->x_compile = 1;
glNewList(x->x_dlist, GL_COMPILE_AND_EXECUTE);
//glNewList(x->x_dlist, GL_COMPILE);
//post("compiling");
}
}
}
static void pdp_3d_dlist_process_cleanup(t_pdp_3d_dlist *x)
{
int p = pdp_3dp_base_get_context_packet(x);
if (-1 != p){
/* check if pbuf */
if (pdp_packet_3Dcontext_isvalid(p)){
/* end list if we're compiling */
if (x->x_compile){
/* end the list */
glEndList();
/* use the list next time */
x->x_compile = 0;
//post("ending compile");
}
/* or execute the old one */
else {
if (x->x_dlist) {
//post("calling dlist %d", x->x_dlist);
glCallList(x->x_dlist);
}
}
}
}
}
t_class *pdp_3d_dlist_class;
void pdp_3d_dlist_free(t_pdp_3d_dlist *x)
{
pdp_3dp_base_free(x);
if (x->x_dlist) glDeleteLists(x->x_dlist, 1);
}
void *pdp_3d_dlist_new(t_symbol *s)
{
t_pdp_3d_dlist *x = (t_pdp_3d_dlist *)pd_new(pdp_3d_dlist_class);
/* super init */
pdp_3dp_base_init(x);
/* io & callbacks */
pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_dlist_process_start, 0);
pdp_3dp_base_add_cleanup(x, (t_pdp_method)pdp_3d_dlist_process_cleanup, 0);
pdp_3dp_base_register_complete_notify(x, (t_pdp_method)pdp_3d_dlist_complete_notify);
/* disable the second outlet */
pdp_3dp_base_enable_outlet(x, 1, 0);
/* create dlist */
x->x_dlist = 0;
x->x_compile = 0;
/* compile the first packet */
pdp_3d_dlist_compile(x);
return (void *)x;
}
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_3d_dlist_setup(void)
{
pdp_3d_dlist_class = class_new(gensym("pdp_3d_dlist"), (t_newmethod)pdp_3d_dlist_new,
(t_method)pdp_3d_dlist_free, sizeof(t_pdp_3d_dlist), 0, A_DEFSYMBOL, A_NULL);
class_addcreator((t_newmethod)pdp_3d_dlist_new, gensym("3dp_dlist"), A_DEFSYMBOL, A_NULL);
pdp_3dp_base_setup(pdp_3d_dlist_class);
class_addmethod(pdp_3d_dlist_class, (t_method)pdp_3d_dlist_compile, gensym("compile"), A_NULL);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: pdp_3d_snap.c ---
/*
* Pure Data Packet module.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <GL/gl.h>
#include "pdp.h"
#include "pdp_3dp_base.h"
#include "pdp_opengl.h"
typedef struct _pdp_3d_snap
{
t_pdp_3dp_base x_base;
t_pdp_dpd_commandfactory x_cfact;
t_outlet *x_result_outlet;
t_pdp_symbol *x_dest_template;
int x_is_texture;
u32 x_width;
u32 x_height;
int x_auto_snap;
int x_pending_snap;
} t_pdp_3d_snap;
typedef struct _snap_command
{
t_pdp_dpd_command x_base;
t_pdp_3d_snap *x_mother;
int x_context_packet;
int x_result_packet;
int x_active;
} t_snap_command;
/* COMAND METHODS */
static void snap_texture_process(t_snap_command *x)
{
int pt = -1;
int p = x->x_context_packet;
int i;
u32 w,h;
if (x->x_active && pdp_packet_3Dcontext_isvalid(p)){
/* get dest texture sub dims */
w = (x->x_mother->x_width) ? x->x_mother->x_width : pdp_packet_3Dcontext_subwidth(p);
h = (x->x_mother->x_height) ? x->x_mother->x_height : pdp_packet_3Dcontext_subheight(p);
/* texture is a special case */
if (x->x_mother->x_is_texture){
/* create a new texture packet */
pt = pdp_packet_new_texture(w,h,GL_RGB);
if (-1 != pt) {
/* set rendering context */
pdp_packet_3Dcontext_set_rendering_context(p);
/* copy pbuf to new texture */
pdp_packet_texture_make_current(pt);
//glReadBuffer(GL_FRONT); //this is for weird feedback stuff..
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w, h);
x->x_result_packet = pt;
}
}
/* other type: snap to bitmap first, then convert */
else{
//nvidia driver 4191 bug workaround (w -> multiple of 4)
w &= -4;
pt = pdp_packet_3Dcontext_snap_to_bitmap(p, w, h);
//pt = pdp_packet_new_bitmap_rgb(w, h);
//pdp_packet_print_debug(pt);
x->x_result_packet = pdp_packet_convert_ro(pt, x->x_mother->x_dest_template);
pdp_packet_mark_unused(pt);
}
}
}
static void snap_callback(t_snap_command *x)
{
/* send packet to outlet */
pdp_packet_pass_if_valid(x->x_mother->x_result_outlet, &x->x_result_packet);
pdp_dpd_command_suicide(x);
}
/* PD OBJECT METHODS */
static void pdp_3d_snap_snap(t_pdp_3d_snap *x)
{
x->x_pending_snap = 1;
}
static void pdp_3d_snap_autosnap(t_pdp_3d_snap *x, t_floatarg f)
{
if (f){
x->x_auto_snap = 1;
x->x_pending_snap = 1;
}
else{
x->x_auto_snap = 0;
x->x_pending_snap = 0;
}
}
static void *pdp_3d_snap_get_new_command(t_pdp_3d_snap *x)
{
t_snap_command *c = (t_snap_command *)pdp_dpd_commandfactory_get_new_command(&x->x_cfact);
c->x_mother = x;
c->x_context_packet = pdp_3dp_base_get_context_packet(x);
c->x_result_packet = -1;
c->x_active = x->x_pending_snap;
if (!x->x_auto_snap) x->x_pending_snap = 0;
return (void *)c;
}
t_class *pdp_3d_snap_class;
void pdp_3d_snap_free(t_pdp_3d_snap *x)
{
//pdp_dpd_base_queue_wait(x);
pdp_3dp_base_free(x);
}
void *pdp_3d_snap_new(t_symbol *s, t_floatarg w, t_floatarg h)
{
t_pdp_3d_snap *x = (t_pdp_3d_snap *)pd_new(pdp_3d_snap_class);
/* super init */
pdp_3dp_base_init(x);
/* get destination template */
x->x_dest_template = (s == gensym("")) ? pdp_gensym("texture/*/*") : pdp_gensym(s->s_name);
x->x_is_texture = pdp_type_description_match(x->x_dest_template, pdp_gensym("texture/*/*"));
w = (w < 0) ? 0 : w;
h = (h < 0) ? 0 : h;
x->x_width = w;
x->x_height = h;
x->x_auto_snap = 1;
x->x_pending_snap = 1;
/* issue warning */
if (!x->x_is_texture && !(x->x_width && x->x_height)){
//post("WARNING: 3dp_snap: target is not a texture and dimensions are not set.");
//post("WARNING: using default image size 320x240.");
//x->x_width = 320;
//x->x_height = 240;
}
/* create outlets */
pdp_3dp_base_add_outlet(x, (t_pdp_method)snap_texture_process, (t_pdp_method)snap_callback);
x->x_result_outlet = outlet_new((t_object *)x, &s_anything);
/* init command list */
pdp_dpd_commandfactory_init(&x->x_cfact, sizeof(t_snap_command));
/* register command factory method */
pdp_dpd_base_register_command_factory_method(x, (t_pdp_newmethod)pdp_3d_snap_get_new_command);
return (void *)x;
}
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_3d_snap_setup(void)
{
pdp_3d_snap_class = class_new(gensym("3dp_snap"), (t_newmethod)pdp_3d_snap_new,
(t_method)pdp_3d_snap_free, sizeof(t_pdp_3d_snap), 0, A_DEFSYMBOL, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
pdp_3dp_base_setup(pdp_3d_snap_class);
class_addmethod(pdp_3d_snap_class, (t_method)pdp_3d_snap_snap, gensym("bang"), A_NULL);
class_addmethod(pdp_3d_snap_class, (t_method)pdp_3d_snap_autosnap, gensym("autosnap"), A_FLOAT, A_NULL);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: pdp_3d_context.c ---
/*
* Pure Data Packet module.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "pdp.h"
#include "pdp_base.h"
#include "pdp_opengl.h"
typedef struct pdp_3d_context_struct
{
t_pdp_base x_base;
t_outlet *x_outlet0;
int x_packet0;
t_symbol *x_type;
unsigned int x_width;
unsigned int x_height;
void *x_constant;
} t_pdp_3d_context;
static void pdp_3d_context_preproc(t_pdp_3d_context *x)
{
int p;
int i;
/* create new packet */
p = pdp_packet_new_pbuf(x->x_width, x->x_height, 0);
x->x_packet0 = p;
if (-1 == p) return;
pdp_pbuf_set_rendering_context(p);
pdp_pbuf_setup_3d_context(p);
/* clear buffer */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
glShadeModel(GL_SMOOTH);
/* disable everything that is enabled in other modules */
glDisable(GL_LIGHTING);
for (i=0; i<8; i++) glDisable(GL_LIGHT0 + i);
glDisable(GL_COLOR_MATERIAL);
}
static void pdp_3d_context_process(t_pdp_3d_context *x)
{
}
static void pdp_3d_context_postproc(t_pdp_3d_context *x)
{
pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
}
static void pdp_3d_context_bang(t_pdp_3d_context *x)
{
pdp_base_bang(x);
}
static void pdp_3d_context_dim(t_pdp_3d_context *x, t_floatarg w, t_floatarg h)
{
x->x_width = pdp_imageproc_legalwidth((int)w);
x->x_height = pdp_imageproc_legalheight((int)h);
//post("dims %d %d", x->x_width, x->x_height);
}
static void pdp_3d_context_free(t_pdp_3d_context *x)
{
pdp_base_free(x);
pdp_packet_mark_unused(x->x_packet0);
}
t_class *pdp_3d_context_class;
void *pdp_3d_context_new(void)
{
int i;
t_pdp_3d_context *x = (t_pdp_3d_context *)pd_new(pdp_3d_context_class);
/* super init */
pdp_base_init(x);
/* in/out*/
x->x_outlet0 = pdp_base_add_pdp_outlet(x);
/* base callbacks */
pdp_base_disable_active_inlet(x);
pdp_base_set_process_method(x, (t_pdp_method)pdp_3d_context_process);
pdp_base_set_preproc_method(x, (t_pdp_method)pdp_3d_context_preproc);
pdp_base_set_postproc_method(x, (t_pdp_method)pdp_3d_context_postproc);
/* data init */
x->x_packet0 = -1;
pdp_3d_context_dim(x, 320, 240);
return (void *)x;
}
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_3d_context_setup(void)
{
pdp_3d_context_class = class_new(gensym("pdp_3d_context"), (t_newmethod)pdp_3d_context_new,
(t_method)pdp_3d_context_free, sizeof(t_pdp_3d_context), 0, A_NULL);
class_addcreator((t_newmethod)pdp_3d_context_new, gensym("3dp_context"), A_NULL);
pdp_base_setup(pdp_3d_context_class);
class_addmethod(pdp_3d_context_class, (t_method)pdp_3d_context_dim, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL);
class_addmethod(pdp_3d_context_class, (t_method)pdp_3d_context_bang, gensym("bang"), A_NULL);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: pdp_3d_subcontext.c ---
/*
* Pure Data Packet module.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <GL/gl.h>
#include "pdp_opengl.h"
#include "pdp_3dp_base.h"
typedef struct pdp_3d_subcontext_struct
{
t_pdp_3dp_base x_base;
int x_width;
int x_height;
} t_pdp_3d_subcontext;
static void pdp_3d_subcontext_process_right(t_pdp_3d_subcontext *x)
{
int p = pdp_3dp_base_get_context_packet(x);
if (-1 != p){
/* set subdims */
pdp_packet_3Dcontext_set_subwidth(p, x->x_width);
pdp_packet_3Dcontext_set_subheight(p, x->x_height);
/* reinit everything */
pdp_packet_3Dcontext_set_rendering_context(p);
pdp_packet_3Dcontext_setup_3d_context(p);
}
}
static void pdp_3d_subcontext_process_left(t_pdp_3d_subcontext *x)
{
int p = pdp_3dp_base_get_context_packet(x);
if (-1 != p){
/* restore subdims */
pdp_packet_3Dcontext_set_subwidth(p, pdp_packet_3Dcontext_width(p));
pdp_packet_3Dcontext_set_subheight(p, pdp_packet_3Dcontext_height(p));
/* re-init everything */
pdp_packet_3Dcontext_set_rendering_context(p);
pdp_packet_3Dcontext_setup_3d_context(p);
}
}
t_class *pdp_3d_subcontext_class;
void pdp_3d_subcontext_free(t_pdp_3d_subcontext *x)
{
pdp_3dp_base_free(x);
}
void *pdp_3d_subcontext_new(t_floatarg w, t_floatarg h)
{
t_pdp_3d_subcontext *x = (t_pdp_3d_subcontext *)pd_new(pdp_3d_subcontext_class);
/* super init */
pdp_3dp_base_init(x);
/* create dpd outlets */
pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_subcontext_process_left, 0);
pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_subcontext_process_right, 0);
x->x_width = (w < 0) ? 64 : w;
x->x_height = (h < 0) ? 64 : h;
return (void *)x;
}
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_3d_subcontext_setup(void)
{
pdp_3d_subcontext_class = class_new(gensym("3dp_subcontext"), (t_newmethod)pdp_3d_subcontext_new,
(t_method)pdp_3d_subcontext_free, sizeof(t_pdp_3d_subcontext), 0, A_FLOAT, A_FLOAT, A_NULL);
pdp_3dp_base_setup(pdp_3d_subcontext_class);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: pdp_3d_windowcontext.c ---
/*
* Pure Data Packet module.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <GL/gl.h>
#include "pdp_opengl.h"
#include "pdp_3dp_base.h"
typedef struct pdp_3d_windowcontext_struct
{
t_pdp_3dp_base x_base;
int x_width;
int x_height;
t_outlet *x_eventout;
int x_finish_queue_id[2];
int x_finish_queue_id_current;
} t_pdp_3d_windowcontext;
static void pdp_3d_windowcontext_sendfinish(t_pdp_3d_windowcontext *x)
{
PDP_ASSERT(x);
PDP_ASSERT(x->x_eventout);
outlet_symbol(x->x_eventout, gensym("done"));
}
/* outlet methods */
/* called before the context is propagated */
static void pdp_3d_windowcontext_clearbuffer(t_pdp_3d_windowcontext *x)
{
int p = pdp_3dp_base_get_context_packet(x);
//post("setting up render buffer");
// for multipass rendering
//pdp_packet_3Dcontext_set_subwidth(p, 320);
//pdp_packet_3Dcontext_set_subheight(p, 240);
pdp_packet_3Dcontext_set_rendering_context(p);
pdp_packet_3Dcontext_setup_3d_context(p);
/* clear buffer */
//glScissor(0,0,
// pdp_packet_3Dcontext_subwidth(p),
// pdp_packet_3Dcontext_subheight(p));
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
/* called after context is propagated */
static void pdp_3d_windowcontext_swapbuffer(t_pdp_3d_windowcontext *x)
{
int p = pdp_3dp_base_get_context_packet(x);
//post("displaying render buffer");
//pdp_packet_3Dcontext_set_rendering_context(p);
pdp_packet_3Dcontext_win_swapbuffers(p);
//pdp_packet_3Dcontext_unset_rendering_context(p);
}
void pdp_3d_windowcontext_resize(t_pdp_3d_windowcontext *x, t_floatarg width, t_floatarg height)
{
int w = (int)width;
int h = (int)height;
int p = pdp_3dp_base_get_context_packet(x);
if ((w>0) && (h>0)){
pdp_packet_3Dcontext_win_resize(p, w, h);
x->x_width = w;
x->x_height = h;
}
}
void pdp_3d_windowcontext_open(t_pdp_3d_windowcontext *x)
{
int p = pdp_3dp_base_get_context_packet(x);
if (-1 == p){
p = pdp_packet_new_3Dcontext_win();
pdp_3d_windowcontext_resize(x, x->x_width, x->x_height);
pdp_3dp_base_set_context_packet(x, p);
}
}
void pdp_3d_windowcontext_close(t_pdp_3d_windowcontext *x)
{
t_pdp_procqueue *q = pdp_3dp_base_get_queue(x);
/* flush all pending tasks in the queue */
//post("preflush");
pdp_procqueue_flush(q);
//post("postflush");
/* now it is safe to delete the context packet */
pdp_packet_delete(pdp_3dp_base_move_context_packet(x));
//post("deleted");
}
void pdp_3d_windowcontext_cursor(t_pdp_3d_windowcontext *x, t_floatarg f)
{
int p = pdp_3dp_base_get_context_packet(x);
bool toggle = (f != 0.0f);
pdp_packet_3Dcontext_win_cursor(p, toggle);
}
static void pdp_3d_windowcontext_bang(t_pdp_3d_windowcontext *x)
{
int p;
int cur = x->x_finish_queue_id_current;
t_pdp_list *eventlist;
/* check if at least recent processing chain is done (two chains busy = max pipeline depth) */
if (-1 != x->x_finish_queue_id[cur]){
//post("pdp_3d_windowcontext_bang: bang ignored (previous rendering not finished)");
return;
}
/* create a window context if needed */
pdp_3d_windowcontext_open(x);
/* get events and send to outlet */
p = pdp_3dp_base_get_context_packet(x);
eventlist = pdp_packet_3Dcontext_win_get_eventlist(p);
if (eventlist){
t_pdp_atom *a;
for (a=eventlist->first; a; a=a->next){
outlet_pdp_list(x->x_eventout, a->w.w_list);
}
pdp_tree_free(eventlist);
}
/* bang base */
pdp_3dp_base_bang(x);
/* add a dummy process to the queue for synchro */
pdp_procqueue_add(pdp_3dp_base_get_queue(x), x, 0, 0, &x->x_finish_queue_id[cur]);
x->x_finish_queue_id_current = !cur;
}
static void pdp_3d_windowcontext_free(t_pdp_3d_windowcontext *x)
{
pdp_3d_windowcontext_close(x);
pdp_3dp_base_free(x);
}
t_class *pdp_3d_windowcontext_class;
void *pdp_3d_windowcontext_new(void)
{
/* allocate */
t_pdp_3d_windowcontext *x = (t_pdp_3d_windowcontext *)pd_new(pdp_3d_windowcontext_class);
x->x_width = 320;
x->x_height = 240;
x->x_finish_queue_id[0] = -1;
x->x_finish_queue_id[1] = -1;
x->x_finish_queue_id_current =0;
/* init super: this is mandatory */
pdp_3dp_base_init(x);
pdp_3dp_base_disable_active_inlet(x);
/* set the dpd processing methods & outlets */
pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_windowcontext_clearbuffer, 0);
pdp_3dp_base_add_cleanup(x, (t_pdp_method)pdp_3d_windowcontext_swapbuffer, (t_pdp_method)pdp_3d_windowcontext_sendfinish);
/* add event outlet */
x->x_eventout = outlet_new((t_object *)x, &s_anything);
return (void *)x;
}
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_3d_windowcontext_setup(void)
{
/* create a standard pd class */
pdp_3d_windowcontext_class = class_new(gensym("3dp_windowcontext"), (t_newmethod)pdp_3d_windowcontext_new,
(t_method)pdp_3d_windowcontext_free, sizeof(t_pdp_3d_windowcontext), 0, A_NULL);
/* inherit pdp base class methods */
pdp_3dp_base_setup(pdp_3d_windowcontext_class);
/* register methods */
class_addbang(pdp_3d_windowcontext_class, pdp_3d_windowcontext_bang);
class_addmethod(pdp_3d_windowcontext_class, (t_method)pdp_3d_windowcontext_open, gensym("open"), A_NULL);
class_addmethod(pdp_3d_windowcontext_class, (t_method)pdp_3d_windowcontext_close, gensym("close"), A_NULL);
class_addmethod(pdp_3d_windowcontext_class, (t_method)pdp_3d_windowcontext_resize, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL);
class_addmethod(pdp_3d_windowcontext_class, (t_method)pdp_3d_windowcontext_resize, gensym("size"), A_FLOAT, A_FLOAT, A_NULL);
class_addmethod(pdp_3d_windowcontext_class, (t_method)pdp_3d_windowcontext_cursor, gensym("cursor"), A_FLOAT, A_NULL);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: pdp_3d_draw.c ---
/*
* Pure Data Packet module.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
//#include "GL/gl.h"
#include <GL/glut.h>
#include <math.h>
#include "pdp_opengl.h"
#include "pdp_3dp_base.h"
typedef struct _drawcommand
{
t_pdp_dpd_command x_head;
int x_context_packet;
int x_texture_packet;
float x_p0;
float x_p1;
float x_p2;
float x_p3;
t_pdp_method x_method;
GLUquadric* x_quadric;
int x_have_texture; /* is there a valid texture ? */
} t_drawcommand;
typedef struct _pdp_3d_draw
{
t_pdp_3dp_base x_base;
t_pdp_dpd_commandfactory x_clist;
int x_inlets;
float x_p0;
float x_p1;
float x_p2;
float x_p3;
t_pdp_method x_method;
int x_tex_in; /* the number of texture inlets */
GLUquadric* x_quadric;
} t_pdp_3d_draw;
void pdp_3d_draw_delete_texture(t_pdp_3d_draw *x)
{
pdp_base_move_packet(x, 1);
}
/* return a new command object */
void *pdp_3d_draw_get_command_object(t_pdp_3d_draw *x)
{
t_drawcommand *c = (t_drawcommand *)pdp_dpd_commandfactory_get_new_command(&x->x_clist);
c->x_p0 = x->x_p0;
c->x_p1 = x->x_p1;
c->x_p2 = x->x_p2;
c->x_p3 = x->x_p3;
c->x_context_packet = pdp_3dp_base_get_context_packet(x);
c->x_texture_packet = pdp_packet_copy_ro(pdp_base_get_packet(x, 1));
c->x_quadric = x->x_quadric; /* $$$TODO: this assumes quadric doesn't change */
c->x_method = x->x_method;
//post("o: %x, vc %x, n %d, u %d", x, c, x->x_clist.nb_commands, c->x_head.used);
return c;
}
/* object drawing methods */
static void draw_clear(t_drawcommand *x)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
static void draw_square(t_drawcommand *x)
{
float f = x->x_p0 * 0.5f;
float z = x->x_p1 * 0.5f;
/* draw a square */
glBegin(GL_QUADS);
glNormal3f(0.0f, 0.0f, 1.0f);
glTexCoord2f(1, 0);
glVertex3f(f,-f, z);
glTexCoord2f(1, 1);
glVertex3f(f, f, z);
glTexCoord2f(0, 1);
glVertex3f(-f, f, z);
glTexCoord2f(0, 0);
glVertex3f(-f,-f, z);
glEnd();
}
static void draw_wsquare(t_drawcommand *x)
{
float f = x->x_p0;
float z = x->x_p1;
/* draw a square */
glBegin(GL_LINE_LOOP);
glVertex3f(f,-f, z);
glVertex3f(f, f, z);
glVertex3f(-f, f, z);
glVertex3f(-f,-f, z);
glEnd();
}
static void draw_triangle(t_drawcommand *x)
{
float f = x->x_p0 * 0.5f;
float f2 = f * 0.5f;
float f3 = f * (sqrt(3.0f) / 2.0f);
float z = x->x_p1 * 0.5f;
/* draw a triangle */
glBegin(GL_TRIANGLES);
glNormal3f(0.0f, 0.0f, 1.0f);
glTexCoord2f(0.5f, 1.0f);
glVertex3f(0, f, z);
glTexCoord2f(0.5f * (1.0f - sqrt(3.0f)/2.0f), 0.25f);
glVertex3f(-f3, -f2, z);
glTexCoord2f(0.5f * (1.0f + sqrt(3.0f)/2.0f), 0.25f);
glVertex3f(f3, -f2, z);
glEnd();
}
static void draw_wtriangle(t_drawcommand *x)
{
float f = x->x_p0 * 0.5f;
float f2 = f * 0.5f;
float f3 = f * (sqrt(3.0f) / 2.0f);
float z = x->x_p1 * 0.5f;
/* draw a wire triangle */
glBegin(GL_LINE_LOOP);
glNormal3f(0.0f, 0.0f, 1.0f);
glVertex3f(0, f, z);
glVertex3f(-f3, -f2, z);
glVertex3f(f3, -f2, z);
glEnd();
}
static void draw_wcube(t_drawcommand *x)
{
glutWireCube(x->x_p0);
}
static void draw_cube(t_drawcommand *x)
{
x->x_p1 = x->x_p0; // set square z coord;
//glutSolidCube(x->x_p0);
//glMatrixMode(GL_MODELVIEW);
glPushMatrix();
draw_square(x);
glRotatef(90, 0,1,0);
draw_square(x);
glRotatef(90, 0,1,0);
draw_square(x);
glRotatef(90, 0,1,0);
draw_square(x);
glPopMatrix();
glPushMatrix();
glRotatef(90, 1, 0, 0);
draw_square(x);
glRotatef(180, 1, 0, 0);
draw_square(x);
glPopMatrix();
}
static void draw_wtorus(t_drawcommand *x)
{
float ri = x->x_p0;
float ro = x->x_p1;
int n = (int)x->x_p2;
int m = (int)x->x_p3;
if (n < 1) n = 20;
if (m < 1) m = n;
glutWireTorus(ri, ro, n, m);
}
static void draw_torus(t_drawcommand *x)
{
float ri = x->x_p0;
float ro = x->x_p1;
int n = (int)x->x_p2;
int m = (int)x->x_p3;
if (n < 1) n = 20;
if (m < 1) m = n;
glutSolidTorus(ri, ro, n, m);
}
static void draw_cone(t_drawcommand *x)
{
float base = x->x_p0;
float height = x->x_p1;
int n = (int)x->x_p2;
int m = (int)x->x_p3;
if (n < 1) n = 20;
if (m < 1) m = n;
glutSolidCone(base, height, n, m);
}
static void draw_wcone(t_drawcommand *x)
{
float base = x->x_p0;
float height = x->x_p1;
int n = (int)x->x_p2;
int m = (int)x->x_p3;
if (n < 1) n = 20;
if (m < 1) m = n;
glutWireCone(base, height, n, m);
}
static void draw_wteapot(t_drawcommand *x)
{
float f = x->x_p0;
glutWireTeapot(f);
}
static void draw_teapot(t_drawcommand *x)
{
float f = x->x_p0;
glutSolidTeapot(f);
}
static void draw_wsphere(t_drawcommand *x)
{
float f = x->x_p0;
int n = (int)x->x_p1;
int m = (int)x->x_p2;
if (n < 1) n = 20;
if (m < 1) m = n;
glutWireSphere(f, n, m);
}
static void draw_sphere(t_drawcommand *x)
{
float f = x->x_p0;
int n = (int)x->x_p1;
int m = (int)x->x_p2;
if (n < 1) n = 20;
if (m < 1) m = n;
gluSphere(x->x_quadric, f, n, m);
//glutSolidSphere(f, n, m);
}
static void draw_dodeca(t_drawcommand *x){glutSolidDodecahedron();}
static void draw_octa(t_drawcommand *x) {glutSolidOctahedron();}
static void draw_tetra(t_drawcommand *x) {glutSolidTetrahedron();}
static void draw_icosa(t_drawcommand *x) {glutSolidIcosahedron();}
static void draw_wdodeca(t_drawcommand *x){glutWireDodecahedron();}
static void draw_wocta(t_drawcommand *x) {glutWireOctahedron();}
static void draw_wtetra(t_drawcommand *x) {glutWireTetrahedron();}
static void draw_wicosa(t_drawcommand *x) {glutWireIcosahedron();}
/* the actual (registered) draw method */
/* when this is finished, the drawcommand object should commit suicide */
static void draw_process(t_drawcommand *x)
{
int p = x->x_context_packet;
int pt = x->x_texture_packet;
float fx=1;
float fy=1;
x->x_have_texture = pdp_packet_texture_isvalid(pt);
//post("pdp_3d_draw: context = %d, texture = %d", p, pt);
/* check if it's a valid buffer we can draw in */
if (pdp_packet_3Dcontext_isvalid(p)){
/* setup rendering context */
pdp_packet_3Dcontext_set_rendering_context(p);
/* enable texture */
if (x->x_have_texture){
fx = pdp_packet_texture_fracx(pt);
fy = pdp_packet_texture_fracy(pt);
glEnable(GL_TEXTURE_2D);
pdp_packet_texture_make_current(pt);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
/* scale texture matrix to reflect subtexture's coords */
glMatrixMode(GL_TEXTURE);
//glLoadIdentity();
glPushMatrix();
glScalef(fx, fy, 1);
glMatrixMode(GL_MODELVIEW);
gluQuadricTexture(x->x_quadric, 1);
}
/* call the generating method */
if (x->x_method) (*x->x_method)(x);
/* disable texture */
if (x->x_have_texture){
glMatrixMode(GL_TEXTURE);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glDisable(GL_TEXTURE_2D);
gluQuadricTexture(x->x_quadric, 0);
}
}
/* you know the drill: command done, sword in belly. */
pdp_packet_mark_unused(x->x_texture_packet);
pdp_dpd_command_suicide(x);
}
static void pdp_3d_draw_p0(t_pdp_3d_draw *x, t_floatarg f){x->x_p0 = f;}
static void pdp_3d_draw_p1(t_pdp_3d_draw *x, t_floatarg f){x->x_p1 = f;}
static void pdp_3d_draw_p2(t_pdp_3d_draw *x, t_floatarg f){x->x_p2 = f;}
static void pdp_3d_draw_p3(t_pdp_3d_draw *x, t_floatarg f){x->x_p3 = f;}
t_class *pdp_3d_draw_class;
void pdp_3d_draw_free(t_pdp_3d_draw *x)
{
pdp_3dp_base_free(x);
gluDeleteQuadric(x->x_quadric);
pdp_dpd_commandfactory_free(&x->x_clist);
}
void pdp_3d_draw_object(t_pdp_3d_draw *x, t_symbol *s)
{
/* find out if it is a buffer operation */
if (s == gensym("clear")) {x->x_method = (t_pdp_method)draw_clear; x->x_inlets = 0;}
/* if not, find out which object we need to draw */
else if (s == gensym("triangle")) {x->x_method = (t_pdp_method)draw_triangle; x->x_inlets = 1;}
else if (s == gensym("wtriangle")) {x->x_method = (t_pdp_method)draw_wtriangle; x->x_inlets = 1;}
else if (s == gensym("square")) {x->x_method = (t_pdp_method)draw_square; x->x_inlets = 1;}
else if (s == gensym("wsquare")) {x->x_method = (t_pdp_method)draw_wsquare; x->x_inlets = 1;}
else if (s == gensym("cube")) {x->x_method = (t_pdp_method)draw_cube; x->x_inlets = 1;}
else if (s == gensym("wcube")) {x->x_method = (t_pdp_method)draw_wcube; x->x_inlets = 1;}
else if (s == gensym("sphere")) {x->x_method = (t_pdp_method)draw_sphere; x->x_inlets = 3;}
else if (s == gensym("wsphere")) {x->x_method = (t_pdp_method)draw_wsphere; x->x_inlets = 3;}
else if (s == gensym("torus")) {x->x_method = (t_pdp_method)draw_torus; x->x_inlets = 4;}
else if (s == gensym("wtorus")) {x->x_method = (t_pdp_method)draw_wtorus; x->x_inlets = 4;}
else if (s == gensym("cone")) {x->x_method = (t_pdp_method)draw_cone; x->x_inlets = 4;}
else if (s == gensym("wcone")) {x->x_method = (t_pdp_method)draw_wcone; x->x_inlets = 4;}
else if (s == gensym("teapot")) {x->x_method = (t_pdp_method)draw_teapot; x->x_inlets = 1;}
else if (s == gensym("wteapot")) {x->x_method = (t_pdp_method)draw_wteapot; x->x_inlets = 1;}
else if (s == gensym("dodeca")) {x->x_method = (t_pdp_method)draw_dodeca; x->x_inlets = 0;}
else if (s == gensym("icosa")) {x->x_method = (t_pdp_method)draw_icosa; x->x_inlets = 0;}
else if (s == gensym("octa")) {x->x_method = (t_pdp_method)draw_octa; x->x_inlets = 0;}
else if (s == gensym("tetra")) {x->x_method = (t_pdp_method)draw_tetra; x->x_inlets = 0;}
else if (s == gensym("wdodeca")) {x->x_method = (t_pdp_method)draw_wdodeca; x->x_inlets = 0;}
else if (s == gensym("wicosa")) {x->x_method = (t_pdp_method)draw_wicosa; x->x_inlets = 0;}
else if (s == gensym("wocta")) {x->x_method = (t_pdp_method)draw_wocta; x->x_inlets = 0;}
else if (s == gensym("wtetra")) {x->x_method = (t_pdp_method)draw_wtetra; x->x_inlets = 0;}
else {
post("pdp_3d_draw: object %s not found", s->s_name);
x->x_method = 0;
x->x_inlets = 0;
}
// the number of texture inlets
x->x_tex_in = 1;
}
void *pdp_3d_draw_new(t_symbol *s, t_floatarg p0, t_floatarg p1, t_floatarg p2, t_floatarg p3)
{
t_pdp_3d_draw *x = (t_pdp_3d_draw *)pd_new(pdp_3d_draw_class);
char param[] = "p0";
int i;
/* super init */
pdp_3dp_base_init(x);
x->x_p0 = p0;
x->x_p1 = p1;
x->x_p2 = p2;
x->x_p3 = p3;
/* set the object & number of inlets */
pdp_3d_draw_object(x, s);
/* create texture inlets */
for(i=0; i<x->x_tex_in; i++){
pdp_base_add_pdp_inlet(x);
}
/* create additional inlets */
for(i=0; i<x->x_inlets; i++){
pdp_base_add_gen_inlet(x, gensym("float"), gensym(param));
param[1]++;
}
/* create dpd outlet */
pdp_3dp_base_add_outlet(x, (t_pdp_method)draw_process, 0);
/* setup quadric */
x->x_quadric = gluNewQuadric();
/* init command list */
pdp_dpd_commandfactory_init(&x->x_clist, sizeof(t_drawcommand));
/* register command factory method */
pdp_dpd_base_register_command_factory_method(x, (t_pdp_newmethod)pdp_3d_draw_get_command_object);
return (void *)x;
}
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_3d_draw_setup(void)
{
pdp_3d_draw_class = class_new(gensym("3dp_draw"), (t_newmethod)pdp_3d_draw_new,
(t_method)pdp_3d_draw_free, sizeof(t_pdp_3d_draw), 0, A_SYMBOL,
A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
pdp_3dp_base_setup(pdp_3d_draw_class);
class_addmethod(pdp_3d_draw_class, (t_method)pdp_3d_draw_p0, gensym("p0"), A_DEFFLOAT, A_NULL);
class_addmethod(pdp_3d_draw_class, (t_method)pdp_3d_draw_p1, gensym("p1"), A_DEFFLOAT, A_NULL);
class_addmethod(pdp_3d_draw_class, (t_method)pdp_3d_draw_p2, gensym("p2"), A_DEFFLOAT, A_NULL);
class_addmethod(pdp_3d_draw_class, (t_method)pdp_3d_draw_p3, gensym("p3"), A_DEFFLOAT, A_NULL);
class_addmethod(pdp_3d_draw_class, (t_method)pdp_3d_draw_delete_texture, gensym("delete_texture"), A_DEFFLOAT, A_NULL);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: pdp_3d_light.c ---
/*
* Pure Data Packet module.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <GL/gl.h>
#include "pdp_opengl.h"
#include "pdp_3dp_base.h"
typedef struct pdp_3d_light_struct
{
t_pdp_3dp_base x_base;
//float x_centerx;
//float x_centery;
//float x_centerz;
int x_index;
} t_pdp_3d_light;
static void pdp_3d_light_process(t_pdp_3d_light *x)
{
int p = pdp_3dp_base_get_context_packet(x);
int i;
GLfloat ambient[] = {.7,.7,.7,1};
GLfloat diffuse[] = {.6,.6,.6,1};
GLfloat specular[] = {1, 1, 1, 1};
GLfloat shininess[] = {50};
GLfloat position[] = {0,0,1,1};
GLfloat intensity[] = {1,1,1,0};
int light = GL_LIGHT0 + x->x_index;
/* check if it's a valid buffer we can draw in */
if (pdp_packet_3Dcontext_isvalid(p)){
position[0] = 0; //x->x_centerx;
position[1] = 0; //x->x_centery;
position[2] = 0; //x->x_centerz;
/* set rendering context */
//pdp_packet_3Dcontext_set_rendering_context(p);
/* setup lighting */
glEnable(GL_LIGHTING);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
//glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
glMaterialfv(GL_FRONT, GL_SHININESS, shininess);
glLightfv(light, GL_POSITION, position);
//glLightfv(light, GL_DIFFUSE, intensity);
glEnable(light);
/* ALPHA HACK */
//glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
//glEnable(GL_BLEND);
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//glBlendFunc(GL_SRC_ALPHA, GL_ONE);
//glEnable(GL_ALPHA_TEST);
//glAlphaFunc(GL_GREATER, 0.f);
}
}
//static void pdp_3d_light_centerx(t_pdp_3d_light *x, t_floatarg f){x->x_centerx = f;}
//static void pdp_3d_light_centery(t_pdp_3d_light *x, t_floatarg f){x->x_centery = f;}
//static void pdp_3d_light_centerz(t_pdp_3d_light *x, t_floatarg f){x->x_centerz = f;}
t_class *pdp_3d_light_class;
void pdp_3d_light_free(t_pdp_3d_light *x)
{
pdp_3dp_base_free(x);
}
void *pdp_3d_light_new(t_floatarg fi, t_floatarg cx, t_floatarg cy, t_floatarg cz)
{
t_pdp_3d_light *x = (t_pdp_3d_light *)pd_new(pdp_3d_light_class);
/* super init */
pdp_3dp_base_init(x);
if (fi < 0) fi = 0;
x->x_index = (int)fi;
//x->x_centerx = cx;
//x->x_centery = cy;
//x->x_centerz = cz;
/* io */
//pdp_base_add_gen_inlet(x, gensym("float"), gensym("centerx"));
//pdp_base_add_gen_inlet(x, gensym("float"), gensym("centery"));
//pdp_base_add_gen_inlet(x, gensym("float"), gensym("centerz"));
/* add dpd outlet */
pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_light_process, 0);
return (void *)x;
}
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_3d_light_setup(void)
{
pdp_3d_light_class = class_new(gensym("3dp_light"), (t_newmethod)pdp_3d_light_new,
(t_method)pdp_3d_light_free, sizeof(t_pdp_3d_light), 0,
A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
pdp_3dp_base_setup(pdp_3d_light_class);
//class_addmethod(pdp_3d_light_class, (t_method)pdp_3d_light_centerx, gensym("centerx"), A_DEFFLOAT, A_NULL);
//class_addmethod(pdp_3d_light_class, (t_method)pdp_3d_light_centery, gensym("centery"), A_DEFFLOAT, A_NULL);
//class_addmethod(pdp_3d_light_class, (t_method)pdp_3d_light_centerz, gensym("centerz"), A_DEFFLOAT, A_NULL);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: pdp_3d_push.c ---
/*
* Pure Data Packet module.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <GL/gl.h>
#include "pdp_opengl.h"
#include "pdp_3dp_base.h"
typedef struct pdp_3d_push_struct
{
t_pdp_3dp_base x_base;
GLenum x_matrix;
int x_change_mode;
} t_pdp_3d_push;
static void pdp_3d_push_process_right(t_pdp_3d_push *x)
{
int p = pdp_3dp_base_get_context_packet(x);
if (-1 != p){
/* push one of the matrices */
glMatrixMode(x->x_matrix);
glPushMatrix();
/* set default matrix to modelview */
if (!x->x_change_mode) glMatrixMode(GL_MODELVIEW);
}
}
static void pdp_3d_push_process_left(t_pdp_3d_push *x)
{
int p = pdp_3dp_base_get_context_packet(x);
if (-1 != p){
/* restore the saved matrix */
glMatrixMode(x->x_matrix);
glPopMatrix();
/* set default matrix back to modelview */
glMatrixMode(GL_MODELVIEW);
}
}
static void pdp_3d_mode_process_right(t_pdp_3d_push *x)
{
int p = pdp_3dp_base_get_context_packet(x);
if (-1 != p){
/* change matrix mode */
glMatrixMode(x->x_matrix);
}
}
static void pdp_3d_mode_process_left(t_pdp_3d_push *x)
{
int p = pdp_3dp_base_get_context_packet(x);
if (-1 != p){
/* restore default matrix to modelview */
glMatrixMode(GL_MODELVIEW);
}
}
static void pdp_3d_push_setmatrix(t_pdp_3d_push *x, t_symbol *s)
{
GLenum m;
/* find out which matrix to push */
if (s == gensym("projection")) m = GL_PROJECTION;
else if (s == gensym("modelview")) m = GL_MODELVIEW;
else if (s == gensym("texture")) m = GL_TEXTURE;
else if (s == gensym("color")) m = GL_COLOR;
/* default is modelview */
else m = GL_MODELVIEW;
x->x_matrix = m;
}
t_class *pdp_3d_push_class;
void pdp_3d_push_free(t_pdp_3d_push *x)
{
pdp_3dp_base_free(x);
}
void *pdp_3d_push_mode_new(t_symbol *s)
{
t_pdp_3d_push *x = (t_pdp_3d_push *)pd_new(pdp_3d_push_class);
/* super init */
pdp_3dp_base_init(x);
/* setup which matrix we are talking about */
pdp_3d_push_setmatrix(x, s);
x->x_change_mode = 0;
return (void *)x;
}
void *pdp_3d_push_new(t_symbol *s, t_floatarg f)
{
t_pdp_3d_push *x = (t_pdp_3d_push *)pdp_3d_push_mode_new(s);
/* create dpd outlets */
pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_push_process_left, 0);
pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_push_process_right, 0);
x->x_change_mode = (f != 0.0f);
return (void *)x;
}
void *pdp_3d_mode_new(t_symbol *s)
{
t_pdp_3d_push *x = (t_pdp_3d_push *)pdp_3d_push_mode_new(s);
/* create dpd outlets */
pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_mode_process_left, 0);
pdp_3dp_base_add_outlet(x, (t_pdp_method)pdp_3d_mode_process_right, 0);
return (void *)x;
}
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_3d_push_setup(void)
{
pdp_3d_push_class = class_new(gensym("3dp_push"), (t_newmethod)pdp_3d_push_new,
(t_method)pdp_3d_push_free, sizeof(t_pdp_3d_push), 0, A_DEFSYMBOL, A_NULL);
class_addcreator((t_newmethod)pdp_3d_mode_new, gensym("3dp_mode"), A_DEFSYMBOL, A_NULL);
pdp_3dp_base_setup(pdp_3d_push_class);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: pdp_3d_view.c ---
/*
* Pure Data Packet module.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <GL/gl.h>
#include "pdp_opengl.h"
#include "pdp_3dp_base.h"
/* PD OBJECT */
typedef struct _pdp_3d_view
{
t_pdp_3dp_base x_base;
t_pdp_dpd_commandfactory x_clist;
float x_p0;
float x_p1;
float x_p2;
float x_p3;
t_pdp_method x_method;
int x_inlets;
} t_pdp_3d_view;
/* COMMAND OBJECT */
typedef struct _viewcommand
{
t_pdp_dpd_command x_head; // viewcommand base
t_pdp_3d_view *x_x; // command owner
int x_context_packet;
float x_p0;
float x_p1;
float x_p2;
float x_p3;
} t_viewcommand;
/* COMMAND OBJECT METHODS */
/* rotate about the negative z axis */
static void view_rot2d(t_viewcommand *x) {glRotatef(x->x_p0, 0, 0, -1);}
/* rotate about the positive x,y,z axis */
static void view_rotx(t_viewcommand *x) {glRotatef(x->x_p0, 1, 0, 0);}
static void view_roty(t_viewcommand *x) {glRotatef(x->x_p0, 0, 1, 0);}
static void view_rotz(t_viewcommand *x) {glRotatef(x->x_p0, 0, 0, 1);}
static void view_rota(t_viewcommand *x) {glRotatef(x->x_p3, x->x_p0, x->x_p1, x->x_p2);}
/* translate along an axis */
static void view_transx(t_viewcommand *x) {glTranslatef(x->x_p0, 0, 0);}
static void view_transy(t_viewcommand *x) {glTranslatef(0, x->x_p0, 0);}
static void view_transz(t_viewcommand *x) {glTranslatef(0, 0, x->x_p0);}
static void view_transxyz(t_viewcommand *x) {glTranslatef(x->x_p0, x->x_p1, x->x_p2);}
/* rotate about the positive x,y,z axis */
static void view_scalex(t_viewcommand *x) {glScalef(x->x_p0, 1, 1);}
static void view_scaley(t_viewcommand *x) {glScalef(1, x->x_p0, 1);}
static void view_scalez(t_viewcommand *x) {glScalef(1, 1, x->x_p0);}
static void view_scale(t_viewcommand *x) {glScalef(x->x_p0, x->x_p0, x->x_p0);}
/* specials */
static void view_reset_3d(t_viewcommand *x) {pdp_packet_3Dcontext_setup_3d_context(x->x_context_packet);}
static void view_scale_aspect(t_viewcommand *x) {glScalef(pdp_packet_3Dcontext_subaspect(x->x_context_packet),1,1);}
/* process command */
static void view_process(t_viewcommand *x)
{
int p = x->x_context_packet;
/* check if it's a valid context buffer we can draw in */
if (pdp_packet_3Dcontext_isvalid(p)){
/* setup rendering context */
pdp_packet_3Dcontext_set_rendering_context(p);
/* call the generating method */
if (x->x_x->x_method) (*x->x_x->x_method)(x);
}
/* suicide */
pdp_dpd_command_suicide(x);
}
/* command object factory method */
void *pdp_3d_view_get_command_object(t_pdp_3d_view *x)
{
t_viewcommand *c = (t_viewcommand *)pdp_dpd_commandfactory_get_new_command(&x->x_clist);
c->x_p0 = x->x_p0;
c->x_p1 = x->x_p1;
c->x_p2 = x->x_p2;
c->x_p3 = x->x_p3;
c->x_context_packet = pdp_3dp_base_get_context_packet(x);
c->x_x = x;
return c;
}
/* PD OBJECT METHODS */
static void pdp_3d_view_p0(t_pdp_3d_view *x, t_floatarg f){x->x_p0 = f;}
static void pdp_3d_view_p1(t_pdp_3d_view *x, t_floatarg f){x->x_p1 = f;}
static void pdp_3d_view_p2(t_pdp_3d_view *x, t_floatarg f){x->x_p2 = f;}
static void pdp_3d_view_p3(t_pdp_3d_view *x, t_floatarg f){x->x_p3 = f;}
t_class *pdp_3d_view_class;
void pdp_3d_view_free(t_pdp_3d_view *x)
{
pdp_dpd_commandfactory_free(&x->x_clist);
pdp_3dp_base_free(x);
}
void *pdp_3d_view_new(t_symbol *s, t_floatarg p0, t_floatarg p1, t_floatarg p2, t_floatarg p3)
{
t_pdp_3d_view *x = (t_pdp_3d_view *)pd_new(pdp_3d_view_class);
char param[] = "p0";
int i;
/* super init */
pdp_3dp_base_init(x);
x->x_p0 = p0;
x->x_p1 = p1;
x->x_p2 = p2;
x->x_p3 = p3;
/* find out which transform we need to apply */
if (s == gensym("rot2d")) {x->x_method = (t_pdp_method)view_rot2d; x->x_inlets = 1;}
else if (s == gensym("rotx")) {x->x_method = (t_pdp_method)view_rotx; x->x_inlets = 1;}
else if (s == gensym("roty")) {x->x_method = (t_pdp_method)view_roty; x->x_inlets = 1;}
else if (s == gensym("rotz")) {x->x_method = (t_pdp_method)view_rotz; x->x_inlets = 1;}
else if (s == gensym("rota")) {x->x_method = (t_pdp_method)view_rota; x->x_inlets = 4;}
else if (s == gensym("transx")) {x->x_method = (t_pdp_method)view_transx; x->x_inlets = 1;}
else if (s == gensym("transy")) {x->x_method = (t_pdp_method)view_transy; x->x_inlets = 1;}
else if (s == gensym("transz")) {x->x_method = (t_pdp_method)view_transz; x->x_inlets = 1;}
else if (s == gensym("transxyz")) {x->x_method = (t_pdp_method)view_transxyz; x->x_inlets = 3;}
else if (s == gensym("scalex")) {x->x_method = (t_pdp_method)view_scalex; x->x_inlets = 1;}
else if (s == gensym("scaley")) {x->x_method = (t_pdp_method)view_scaley; x->x_inlets = 1;}
else if (s == gensym("scalez")) {x->x_method = (t_pdp_method)view_scalez; x->x_inlets = 1;}
else if (s == gensym("scale")) {x->x_method = (t_pdp_method)view_scale; x->x_inlets = 1;}
else if (s == gensym("scale_aspect")) {x->x_method = (t_pdp_method)view_scale_aspect; x->x_inlets = 0;}
else if (s == gensym("reset")) {x->x_method = (t_pdp_method)view_reset_3d; x->x_inlets = 0;}
else {
post("pdp_view: view transformation %s not found", s->s_name);
x->x_method = 0;
x->x_inlets = 0;
}
/* create additional inlets */
for(i=0; i<x->x_inlets; i++){
pdp_base_add_gen_inlet(x, gensym("float"), gensym(param));
param[1]++;
}
/* create dpd outlet */
pdp_3dp_base_add_outlet(x, (t_pdp_method)view_process, 0);
/* init command factory */
pdp_dpd_commandfactory_init(&x->x_clist, sizeof(t_viewcommand));
/* register command factory method */
pdp_dpd_base_register_command_factory_method(x, (t_pdp_newmethod)pdp_3d_view_get_command_object);
return (void *)x;
}
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_3d_view_setup(void)
{
pdp_3d_view_class = class_new(gensym("3dp_view"), (t_newmethod)pdp_3d_view_new,
(t_method)pdp_3d_view_free, sizeof(t_pdp_3d_view), 0, A_SYMBOL,
A_DEFFLOAT,A_DEFFLOAT,A_DEFFLOAT,A_DEFFLOAT, A_NULL);
pdp_3dp_base_setup(pdp_3d_view_class);
class_addmethod(pdp_3d_view_class, (t_method)pdp_3d_view_p0, gensym("p0"), A_DEFFLOAT, A_NULL);
class_addmethod(pdp_3d_view_class, (t_method)pdp_3d_view_p1, gensym("p1"), A_DEFFLOAT, A_NULL);
class_addmethod(pdp_3d_view_class, (t_method)pdp_3d_view_p2, gensym("p2"), A_DEFFLOAT, A_NULL);
class_addmethod(pdp_3d_view_class, (t_method)pdp_3d_view_p3, gensym("p3"), A_DEFFLOAT, A_NULL);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: pdp_3d_for.c ---
/*
* Pure Data Packet module.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/* a for loop for 3dp packets
this can later be adapted to a for loop for dpd packets. */
#include "pdp_opengl.h"
#include "pdp_internals.h"
typedef struct pdp_3d_for_struct
{
t_object x_obj;
t_int x_count;
t_outlet *x_outlet_dpd;
t_outlet *x_outlet_float;
} t_pdp_3d_for;
static void pdp_3d_for_input_0(t_pdp_3d_for *x, t_symbol *s, t_floatarg f)
{
int i;
/* trigger on "accumulate" */
if (s == gensym("accumulate")){
for (i=0; i<x->x_count; i++){
outlet_float(x->x_outlet_float, (float)i);
outlet_dpd(x->x_outlet_dpd, (int)f);
}
}
}
static void pdp_3d_for_count(t_pdp_3d_for *x, t_floatarg f)
{
int count = (int)f;
if (count >= 0) x->x_count = count;
}
static void pdp_3d_for_free(t_pdp_3d_for *x)
{
}
t_class *pdp_3d_for_class;
void *pdp_3d_for_new(t_floatarg f)
{
int count = (int)f;
t_pdp_3d_for *x = (t_pdp_3d_for *)pd_new(pdp_3d_for_class);
inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("count"));
x->x_outlet_dpd = outlet_new(&x->x_obj, &s_anything);
x->x_outlet_float = outlet_new(&x->x_obj, &s_float);
x->x_count = (count > 0) ? count : 1;
return (void *)x;
}
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_3d_for_setup(void)
{
pdp_3d_for_class = class_new(gensym("3dp_for"), (t_newmethod)pdp_3d_for_new,
(t_method)pdp_3d_for_free, sizeof(t_pdp_3d_for), 0, A_DEFFLOAT, A_NULL);
class_addmethod(pdp_3d_for_class, (t_method)pdp_3d_for_input_0, gensym("dpd"), A_SYMBOL, A_DEFFLOAT, A_NULL);
class_addmethod(pdp_3d_for_class, (t_method)pdp_3d_for_count, gensym("count"), A_FLOAT, A_NULL);
}
#ifdef __cplusplus
}
#endif
Update of /cvsroot/pure-data/externals/pdp/opengl
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6756/opengl
Added Files:
Makefile Makefile.config README TODO
Log Message:
checking in pdp 0.12.4 from http://zwizwa.fartit.com/pd/pdp/pdp-0.12.4.tar.gz
--- NEW FILE: README ---
pdp_opengl (3dp): opengl extensions for pdp
warning: this is still experimental and incomplete
this library extends pdp with texture and render context packets,
to use some of the power of current video hardware.
it is very much like gem (sort of a redesign, filled with my own
idiosyncrasies). gem, like it is now, is not very suited for interaction
with pdp image processing because of its hardcoded window centric rendering,
so i thought i'd write some gem like stuff on top of pdp myself. (3dp right
now only supports window centric rendering itself, but adding pbuffer
or pixmap rendering is easy enough, though it requires a rather new glx
library)
so, 3dp is an experimental gem clone with tight pdp integration. unless
you like experiments, use gem, since it is better supported, has more
features and runs on linux, windows and mac osx.
requires glx (opengl on x window).
building:
edit Makefile.config to reflect your system and run make. the library is
pdp_opengl.pd_linux
some of the examples use the abstractions in opengl/abstractions. best to
add this to your pd path.
there are some fatal X bugs floating around, so be careful with resizing
windows and closing patches. there are a lot of other, non-fatal bugs
or badly implemented features. if you have remarks, just let me know.
i'll move to autoconf once i no longer consider it experimental.
TIPS & TRICKS
* the 3dp_windowcontext creates a window to draw in. the window packet
will be be output to the left outlet when a bang is received. control
flow for context is right to left, this means if a 3dp object has 2
context outlets, the rightmost will be propagated before the leftmost.
there is no fanout. all operations are accumulative, including the
geometric transformations. if you need to branch use a 3dp_push object.
* geometric transformations can be done using the 3dp_view object.
the first argument is the kind of transformation: scale, scalex,
scaley, scalez, rotx, roty, rotz, rota, transx, transy, transz,
transxyz.
repectively this scales the object, the x, y, z axis, rotates
around the x, y, z axis, rotates around an arbitrary axis, translates
in the x, y, z directions and translates along a vector. the initial
parameters can be specified as creation arguments, i.e.:
[3dp_view rota 1 1 1 90] rotates by 90 degrees around axis (1,1,1).
* some simple objects can be drawn using the pdp_draw object. the
first argument is the object: square, cube, sphere, torus, cone,
teapot, dodeca, icosa, octa, tetra. prepending the names with a w
draws the wireframe version. (i.e. wcube is a wireframe cube). the
first inlet of the object is a texture inlet. not all objects support
this, but cube, square and sphere do. other inlets set some parameters
like size, nb of segments for sphere, etc.. they can be specified
by creation arguments too.
* saving a (matrix) state can be accomplished by the 3dp_push object.
the default matrix is the modelview matrix. it works as follows: both
the right and the left outlet propagate the same matrix state as the
input. so in short you can use 3dp_push to split your rendering tree
into parallel branches. the matrix types that can be pushed are:
modelview, texture, color, projection.
* setting a current matrix can be done using the 3dp_mode object.
i.e. [3dp_mode texture] will map all geometric transforms to the
texture matrix, for texture coordinate animation. the left outlet
restores the current matrix back to the modelview matrix.
* it is possible to send a render context trough a drawing/view
transforming object multiple times. the easy way is to use 3dp_for,
but other ways are legal too. this can be done to draw different
versions of the same object. have a look at example01 how this can
be done.
it is also possible to send multiple render contexts trought the same
rendering tree (i.e. multiple windows). if you use different viewing
transformations on the top of the rendering chain, you can view a scene
trough different angles.
* light sources can be introduces using 3dp_light. they can be moved
with oridinary 3dp_view objects.
* 3dp_color changes the current color. right outlet is new color,
left outlet is the previous color.
* 3dp_toggle toggles a boolean opengl switch. enabled now are:
depth_test, blend_add, blend_mix. more to come later.
* couping 3dp and pdp can be done using 3dp_snap and pdp_convert.
the correct way to do it is to put 3dp_snap in a rendering
chain and give it arguments like this:
[3dp_snap image/*/* 320 240]
if you specify the subtype to be image/multi/*, the packet
will not be colour space converted: it will stay rgb.
if you want to make a snapshot to store as a high quality
png image, snap to bitmap/rgb/* and store it in pdp_reg to save.
to convert an image back to a texture, use
[pdp_convert texture/*/*]
if you snap to a texture (which is the default)
the dimensions don't need to be specified. a texture will be
allocated that can contain the entire screen. this is because
texture coordinates are relative and data is always interpolated.
snapping only works correctly when the window is not covered
by other windows.
* textures can have any dimensions, but only those which have
dimensions that are integral powers of two will be tiled correctly.
i.e. by using pdp_mode to change to texture mode and doing some
coordinate transforms using pdp_view (see example06: this
uses a tilable animated cellular automata texture)
* multipass rendering is supported trough the objects
3dp_subcontext, "3dp_draw clear" and "3dp_view reset". the idea
is as follows: before rendering the final scene, you use
(a part of) the drawing buffer to render some things and store
them in a texture to be used in your final drawing pass. have
a look at examples 11, 12 and 13. in theory you could build a
"texture processing" framework on top of 3dp, by using the window
buffer as an accumulator and using textures as auxilary registers,
and drawing your final texture result using i.e.
3dp_display_texture. while this can be much faster than ordinary
pdp image processing, it also requires you to do more bookkeping
yourself, since you can only use a "serial" approach because
you can't modify textures directly, only trough the use of the
render buffer.
* 3dp has it's own thread, which is enabled by default. you
can enable/disable this by sending a "3dthread 0/1" message
to pdp_control. in most cases there's no reason to disable
the thread processing, except when you are doing a lot of
pdp<->3dp conversions. in that case the delay introduced by
the thread processing might become problematic. (the same
goes for pdp btw. feedback and threads don't mix too well).
it's a tradeoff. thread processing gives priority to the audio,
so you can obtain low latency, and you don't have to care
about locking up pd by doing too much processing. (instead
frames will be dropped). the drawback is of course that video
timing becomes unpredictable because it is governed by the system
scheduler. so sometimes it can be useful to disable threads
and increase the audio latency, so you can have snappy audio
and video at the same time. getting this to work well usually
requires some experimenting.
* if you have an nvidia card, you can set the environment
variable __GL_SYNC_TO_VBLANK to 1 to prevent tearing, until
3dp has default support for it. i.e.:
export __GL_SYNC_TO_VBLANK=1
enjoy,
tom
---
some political ranting: gem vs. pdp/3dp
first a disclaimer. i'm not into dissing people. i respect and appreciate
all the work that has gone into gem, but at the same time i'm not too happy
with what gem has become. not so much the functionality, but the way it is
built. the original design as a 3d processing extension is not flexible enough
to incorporate what's in there now and what could be added in the future..
instead of complaining about it, i decided to be pragmatic and write something
from scratch. i think, sometimes this has to be done. for me writing pdp/3dp
has been an extremely interesting learning experience. i think i understand
the trade-offs better now, and i know now it's not too easy to get it all
to work. maybe these remarks can be useful...
opengl is not a pure dataflow language. it operates on a global machine
state next to the obvious drawing buffer that is passed around.
representing opengl code with a graphic tree view has some advantages,
though it has a different "feel" than normal pd patches. the fact that
opengl transforms object coordinates to screen coordinates, and not vice
versa, gives graphicly represented opengl code an "upside down" feel.
one of the things i don't like about gem is that it has both the opengl
"upside down drawing and coordinate transformation tree" and the pix
"data flow image processing tree" in the same network, which i find
counterintuitive. it is too monolytic to be truly flexible. in pdp/3dp
i try to separate the two explicitly: dataflow where possible (image
processing), and serial context based processing where needed (opengl).
another disadvantage of gem is its window centric context. by building
3dp around explicit context passing, with explicit context creation objects,
i try to avoid this. an advantage of this is the possibility to send
multiple contexts trough a rendering tree, i.e. to have 2 different views
of the same scene.
pdp has implicit fanout for all packets. i think that is its great
strength. it enables you to use any kind of media packet like you would
use floats. it is very intuitive. however, 3d rendering does not fit
this shoe. at least not when you just wrap opengl in the most straightforward
way. 3dp is a test case for pdp's "accumulation packets", which is a formal
abstraction of a context. pdp processors are nothing more than serial programs
working on a context, so in fact it's nothing special. in fact, i'm still
in doubt if it is useful besides being able to support opengl..
so, the idea was to improve upon gem a bit, from different angles. i did
not succeed in my primary goal: making 3dp more intuitive than gem. it seems
this is only possible if you limit some of the flexibility. just wrapping
opengl keeps a lot of flexibility, but get's infected with the opengl
paradigm. by separating pdp (image processing) and 3dp (drawing and geometry
processing) as much as possible i think i've solved some intuition problems,
but 3dp itself is still basicly gem, with imho a better overall design,
but due to its more low level approach, maybe harder to understand. it seems
to me that knowing how opengl works is rather necessary to use 3dp. the same
is true for gem.
one last philo remark: to me it seems the biggest drawback of gem's design is
the processor centric aproach: the only objects are processors, the data is
implicit and seemingly global. in pdp/3dp processors and objects are 2 separate
entities. i tried to unify them in one object model, but to me it seems the two
should really be treated as different complementary entities, to stay close to
the dataflow paradigm which makes pd such an intuitive tool.
--- NEW FILE: Makefile ---
include Makefile.config
all: $(TARGET)
linux: pdp_opengl.pd_linux
darwin: pdp_opengl.pd_darwin
subdirs:
make -C system
make -C modules
make -C include
clean:
make -C system clean
make -C modules clean
make -C include clean
rm -f pdp_opengl.pd_linux
rm -f *~
pdp_opengl.pd_linux: subdirs
rm -f pdp_opengl.pd_linux
$(CC) -export_dynamic -shared -o pdp_opengl.pd_linux modules/*.o system/*.o $(LDFLAGS) -g
pdp_opengl.pd_darwin: subdirs
rm -f pdp_opengl.pd_linux
$(CC) -o pdp_opengl.pd_pd_darwin modules/*.o system/*.o $(LDFLAGS) -g -bundle -bundle_loader $(PD_EXECUTABLE)
--- NEW FILE: TODO ---
bugs: WARNING: there are still quite a few fatal bugs lurking around.
* segfault when combining 3dp_windowcontext and pdp_xv. probably a mistake
in the teture<->image conversion or window event handling.
* 3dp is not robust against running out of video card resources. if you
manage to crash it please consider sending a bug report.
* 3dp_dlist triggered a segfault in pdp_mutex(un?)lock. can't reproduce.
this also happens on some other occasions where a post() statement is involved:
crash in pdp_mutex_lock, called by putc() -> happens in pdp too when calling post from
thread (like in pdp_netsend/receive)
* pd hangs on save? what happens during save?? -> 0.35 prob? 0.36 seems to work fine.
* segfaults when deleting 3dp objects. very unpredictable.
todo:
* fix flow control for texture conversion
* finish mesh object
general:
* prevent display list recursion: add some state data to the context packet to solve this.
redesign:
* unify pbuf & window contexts (postponed pbufs because of subcontexts)
* cube mapping
* bubble object (model + wave equation)
* finish 3dp light
performance:
* why is texture upload so slow? and is there a way to work around it?
* (why) is context switching slow? and how to introduce the render context differently. (direct to window?)
DESIGN NOTES
3dp is basicly my idea of gem on top of pdp. it is a simple layer around opengl.
3dp_* render and transform objects accept a reference to a rendering context and pass this along.
3dp_* objects DO NOT SUPPORT FANOUT. they do support fanin. multiple contexts can be sent to an object, which
will result in drawing in (or other manipulations of) the respective contexts.
texture packets can be used to pass bitmap data around. 3dp_tdraw accepts a texture on its
second inlet. 3dp_snap dumps the current state of the buffer into a texture packet.
object classes:
-drawing objects
[3dp_draw cube] [3dp_draw sphere] ..
-manipulation objects
[3dp_view rot2d]
-opengl stack objects
[3dp_push color view texture]
3dp vs pdp design:
a context packet is an accumulation packet, and the order of operations on it (serial) is important. it has
elements from a readonly packet (only one instance is passed around) and from a rw packet (it is legal to change it's
state and pass it on).
opengl in dataflow formulation seems to be read bottom to top. i first thought
this was a big drawback of gem, but now that i finally understand how opengl works i think it is
ok. it suddenly dawned on me, usually the number of eyes is much smaller than the number of objects
in a scene, so it is much more straghtforward to start at the eye instead of the objects. since a
simple serial stack mechanism can be used.
so opengl is really serial, while pd "looks" parallel, but is serial too. i still think this
is a good thing, since it keeps things simple, but for some reason the "upside down & serial"
thing about opengl in pd is rather strange..
once you get used to it, and think about rendering a set as a tree rooted at the "context source"
like is done in gem,it seems to work out..
i think i'm going to stick to the depth first backtracking a tree serial rendering
way of looking at it. since i don't see a way of making this more intuitive without complicating
it too much. so no legal fanout of a context packet.
------------------
accumulation packets (buckets) & backtracking
buckets add support for "context based" single threaded programs. it
basicly allows you to construct data processors represented as a control
flow tree. i.e. function calls can be represented by branches in a tree,
with each branch rooted at an object's outlet, executed from right to
left. a "context packet" (or accumulation packet or bucket) is passed
along and acted upon.
* fanout is illegal for bucket processors (at least, if they are non
cummutative, as is usually the case). this is not explicitly prohibited,
since it is hard to check in pd and it allows some hacks. the reason for
this is obvious: if you do not know which branch of a tree is executed
first, results are undefined.
* a new communication protocol needs to be introduced, incompatible
with the existing 3 phase protocol:
(1) register_ro
(2) register_rw
(3) process
the new dpd (bucket / accumulation packet) protocol is 2 phase:
(1) inspect
(2) accumulate
(1) is only present to give priority to bucket inspectors over
accumulators (processors)
an accumulation packet will be owned by its creator all the time.
accumulation processors do not increase the reference count. only ro
inspectors will.
note: it is legal for a packet to have a broken register_rw (missing
copy constructor, i.e. if a copy is too expensive or impossible. this
must be set in the pdp packet header flags by the packet constructor)
--- NEW FILE: Makefile.config ---
PD_DIR = /home/tom/pd/distro/pd/src
PDP_DIR = /home/tom/pd/packet/include
PDP_OGL_DIR = /home/tom/pd/packet/opengl/include
CFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer -ffast-math \
-Wall -W -Wstrict-prototypes -Werror \
-Wno-unused -Wno-parentheses -Wno-switch -g
CPPFLAGS = -I$(PD_DIR) -I$(PDP_DIR) -I$(PDP_OGL_DIR) -I/usr/X11R6/include
LDFLAGS = -lGL -lglut
TARGET=linux
#uncomment these for darwin:
#TARGET=darwin
#CPPFLAGS+=-I/sw/include
#PD_EXECUTABLE=/usr/local/bin/pd
#LDFLAGS = -lGL -lGLU -lglut -lX11 -L/sw/lib -L/usr/X11R6/lib
.c.o:
$(CC) $(CFLAGS) $(CPPFLAGS) -o $*.o -c $*.c
Update of /cvsroot/pure-data/externals/pdp/modules/test
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6756/modules/test
Added Files:
Makefile README pdp_dpd_test.c
Log Message:
checking in pdp 0.12.4 from http://zwizwa.fartit.com/pd/pdp/pdp-0.12.4.tar.gz
--- NEW FILE: README ---
This directory contains test modules.
--- NEW FILE: Makefile ---
#current: all_modules
current: clean
include ../../Makefile.config
all_modules: pdp_forthtest.o
# build test modules
# all_modules: $(PDP_MOD)
clean:
rm -f *~
rm -f *.o
--- NEW FILE: pdp_dpd_test.c ---
/*
* Pure Data Packet module.
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "pdp.h"
#include "pdp_dpd_base.h"
typedef struct pdp_dpd_test_struct
{
t_pdp_dpd_base x_base;
} t_pdp_dpd_test;
/* outlet methods */
static void pdp_dpd_test_1(t_pdp_dpd_test *x){post("%x: one", x);}
static void pdp_dpd_test_2(t_pdp_dpd_test *x){post("%x: two", x);}
static void pdp_dpd_test_3(t_pdp_dpd_test *x){post("%x: three", x);}
static void pdp_dpd_test_cleanup(t_pdp_dpd_test *x){post("%x: cleanup", x);}
static void pdp_dpd_test_inspect(t_pdp_dpd_test *x){post("%x: inspect", x);}
static void pdp_dpd_test_bang(t_pdp_dpd_test *x)
{
/* store a dummy packet */
pdp_dpd_base_set_context_packet(x, pdp_packet_new(PDP_IMAGE, 4096));
/* bang base */
pdp_dpd_base_bang(x);
}
static void pdp_dpd_test_free(t_pdp_dpd_test *x)
{
pdp_dpd_base_free(x);
}
t_class *pdp_dpd_test_class;
void *pdp_dpd_test_new(void)
{
/* allocate */
t_pdp_dpd_test *x = (t_pdp_dpd_test *)pd_new(pdp_dpd_test_class);
/* init super: this is mandatory */
pdp_dpd_base_init(x);
/* set the dpd processing methods & outlets */
pdp_dpd_base_add_outlet(x, (t_pdp_method)pdp_dpd_test_1);
pdp_dpd_base_add_outlet(x, (t_pdp_method)pdp_dpd_test_2);
pdp_dpd_base_add_outlet(x, (t_pdp_method)pdp_dpd_test_3);
pdp_dpd_base_add_cleanup(x, (t_pdp_method)pdp_dpd_test_cleanup);
pdp_dpd_base_add_inspector(x, (t_pdp_method)pdp_dpd_test_inspect);
return (void *)x;
}
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_dpd_test_setup(void)
{
/* create a standard pd class */
pdp_dpd_test_class = class_new(gensym("pdp_dpd_test"), (t_newmethod)pdp_dpd_test_new,
(t_method)pdp_dpd_test_free, sizeof(t_pdp_dpd_test), 0, A_NULL);
/* inherit pdp base class methods */
pdp_dpd_base_setup(pdp_dpd_test_class);
/* add bang method */
class_addbang(pdp_dpd_test_class, pdp_dpd_test_bang);
}
#ifdef __cplusplus
}
#endif