/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #include #include #include "render.h" /* * Gather the translucent triangles from a field */ #define SKIP (xf->tile.skip && (rand()&((xf->tile.skip-1)<<8))) /* * Parameters */ #define PARAMETER(parm, name, type, get) { \ type p; \ Object a; \ a = DXGetAttribute(o, name); \ if (a) { \ if (!get(a, &p)) \ DXErrorReturn(ERROR_BAD_PARAMETER, "invalid " name " parameter"); \ new->parm = p; \ } \ } #define MULTIPLIER(parm, name, type, get) { \ type p; \ Object a; \ a = DXGetAttribute(o, name); \ if (a) { \ if (!get(a, &p)) \ DXErrorReturn(ERROR_BAD_PARAMETER, "invalid " name " parameter"); \ new->parm *= p; \ } \ } static Error parameters(Object o, struct tile *new, struct tile *old) { *new = *old; if (!old->ignore) { PARAMETER(fast_exp, "fast exp", int, DXExtractInteger); PARAMETER(flat_x, "flat x", int, DXExtractInteger); PARAMETER(flat_y, "flat y", int, DXExtractInteger); PARAMETER(flat_z, "flat z", int, DXExtractInteger); PARAMETER(skip, "skip", int, DXExtractInteger); PARAMETER(patch_size, "patch size", int, DXExtractInteger); MULTIPLIER(color_multiplier,"color multiplier",float,DXExtractFloat); MULTIPLIER(opacity_multiplier,"opacity multiplier",float,DXExtractFloat); } if (!_dxf_approx(o, &new->approx)) return ERROR; return OK; } /* * macros to add things to the sort array * * The size of the elements that go into the sort array depends on such * factors as the element type (triangle, quad etc.); for faces derived * from connection-dependent volume elements, there is an additional word * naming the element that the face came from to identify the color. This * size appears in SIZE macro in shade.c, the INFO macro in gather.c, * and the ADVANCE macro in volume.c, and these must be kept in sync. */ #define ADD(p,n) \ ((int *)((long)s + sizeof(struct sort)))[n] = p #define INFO(t, n, surf) { \ s->field = field; \ s->type = t; \ s->surface = surf; \ s = (struct sort *) ((long)s + sizeof(struct sort) + n * sizeof(int)); \ gather->nthings++; \ } /* * */ #define CULLPOINT(pt, p, min, max) (cull && ( \ pt[p].xmax.x || pt[p].ymax.y)) #define CULLLINE(pt, p, q, min, max) (cull && ( \ (pt[p].xmax.x && pt[q].x>max.x) \ || (pt[p].ymax.y && pt[q].y>max.y))) #define CULLTRIP(pt, p, q, r, min, max) (cull && ( \ (pt[p].xmax.x && pt[q].x>max.x && pt[r].x>max.x) \ || (pt[p].ymax.y && pt[q].y>max.y && pt[r].y>max.y))) #define CULLTRI(pt, tri, min, max) \ CULLTRIP(pt, tri.p, tri.q, tri.r, min, max) #define CULLQUADP(pt, p, q, r, s, min, max) (cull && ( \ (pt[p].xmax.x && pt[q].x>max.x && pt[r].x>max.x && pt[s].x>max.x) \ || (pt[p].ymax.y && pt[q].y>max.y && pt[r].y>max.y && pt[s].y>max.y))) #define CULLQUAD(pt, quad, min, max) \ CULLQUADP(pt, quad.p, quad.q, quad.r, quad.s, min, max) /* * */ #define POINT(i) { \ if (!CULLPOINT(xf->positions, i, min, max)) { \ ADD(i,0); \ INFO(SORT_POINT, 1, 0); \ } \ } #define LINE(i) { \ line = xf->c.lines[i]; \ if (!CULLLINE(xf->positions, line.p, line.q, min, max)) { \ ADD(i,0); \ INFO(SORT_LINE, 1, 0); \ } \ } #define POLYLINE(i) \ { \ int j, start, end; \ start = xf->polylines[i]; \ if (i == xf->nconnections-1) \ end = xf->nedges - 1; \ else \ end = xf->polylines[i+1] - 1; \ for (j = start; j < end; j++) { \ int p = xf->edges[j], q = xf->edges[j+1]; \ if (!CULLLINE(xf->positions, p, q, min, max)) { \ ADD(i,0); \ ADD(j,1); \ INFO(SORT_POLYLINE, 2, 0); \ } \ } \ } #define TRI(i, surf) { \ tri = xf->c.triangles[i]; \ if (!CULLTRI(xf->positions, tri, min, max)) { \ ADD(i,0); \ INFO(SORT_TRI, 1, surf); \ } \ } #define QUAD(i, surf) { \ quad = xf->c.quads[i]; \ if (!CULLQUAD(xf->positions, quad, min, max)) { \ ADD(i,0); \ INFO(SORT_QUAD, 1, surf); \ } \ } #define TRI_PTS(p, q, r, surf) { \ if (!CULLTRIP(xf->positions, p, q, r, min, max)) { \ ADD(p,0), ADD(q,1), ADD(r,2); \ INFO(SORT_TRI_PTS, 3, surf); \ } \ } #define TRI_FLAT(p, q, r, col, surf) { \ if (!CULLTRIP(xf->positions, p, q, r, min, max)) { \ ADD(p,0), ADD(q,1), ADD(r,2), ADD(col,3); \ INFO(SORT_TRI_FLAT, 4, surf); \ } \ } #define QUAD_PTS(p, q, r, s, surf) { \ if (!CULLQUADP(xf->positions, p, q, r, s, min, max)) { \ ADD(p,0), ADD(q,1), ADD(r,2), ADD(s,3); \ INFO(SORT_QUAD_PTS, 4, surf); \ } \ } #define QUAD_FLAT(p, q, r, s, col, surf) { \ if (!CULLQUADP(xf->positions, p, q, r, s, min, max)) { \ ADD(p,0), ADD(q,1), ADD(r,2), ADD(s,3), ADD(col,4); \ INFO(SORT_QUAD_FLAT, 5, surf); \ } \ } #define QF(a,b,c, d,e,f, g,h,i, j,k,l, sf,SF) { \ quad.p = ((a)*Y+(b))*Z+(c); \ quad.q = ((d)*Y+(e))*Z+(f); \ quad.r = ((g)*Y+(h))*Z+(i); \ quad.s = ((j)*Y+(k))*Z+(l); \ QUAD_FLAT(quad.p, quad.q, quad.r, quad.s, col, (sf==0||sf==SF)); \ } #define Q(a,b,c, d,e,f, g,h,i, j,k,l, sf,SF) { \ quad.p = ((a)*Y+(b))*Z+(c); \ quad.q = ((d)*Y+(e))*Z+(f); \ quad.r = ((g)*Y+(h))*Z+(i); \ quad.s = ((j)*Y+(k))*Z+(l); \ QUAD_PTS(quad.p, quad.q, quad.r, quad.s, (sf==0||sf==SF)); \ } #define TRI_PTS_INVALID(p, q, r, surf) { \ if (!CULLTRIP(xf->positions, p, q, r, min, max)) { \ ADD(p,0), ADD(q,1), ADD(r,2); \ INFO(SORT_INV_TRI_PTS, 3, surf); \ } \ } #define TRI_FLAT_INVALID(p, q, r, col, surf) { \ if (!CULLTRIP(xf->positions, p, q, r, min, max)) { \ ADD(p,0), ADD(q,1), ADD(r,2), ADD(col,3); \ INFO(SORT_INV_TRI_FLAT, 4, surf); \ } \ } #define QUAD_PTS_INVALID(p, q, r, s, surf) { \ if (!CULLQUADP(xf->positions, p, q, r, s, min, max)) { \ ADD(p,0), ADD(q,1), ADD(r,2), ADD(s,3); \ INFO(SORT_INV_QUAD_PTS, 4, surf); \ } \ } #define QUAD_FLAT_INVALID(p, q, r, s, col, surf) { \ if (!CULLQUADP(xf->positions, p, q, r, s, min, max)) { \ ADD(p,0), ADD(q,1), ADD(r,2), ADD(s,3), ADD(col,4); \ INFO(SORT_INV_QUAD_FLAT, 5, surf); \ } \ } #define Q_INVALID(a,b,c, d,e,f, g,h,i, j,k,l, sf,SF) { \ quad.p = ((a)*Y+(b))*Z+(c); \ quad.q = ((d)*Y+(e))*Z+(f); \ quad.r = ((g)*Y+(h))*Z+(i); \ quad.s = ((j)*Y+(k))*Z+(l); \ QUAD_PTS_INVALID(quad.p, quad.q, quad.r, quad.s, (sf==0||sf==SF)); \ } #define QF_INVALID(a,b,c, d,e,f, g,h,i, j,k,l, sf,SF) { \ quad.p = ((a)*Y+(b))*Z+(c); \ quad.q = ((d)*Y+(e))*Z+(f); \ quad.r = ((g)*Y+(h))*Z+(i); \ quad.s = ((j)*Y+(k))*Z+(l); \ QUAD_FLAT_INVALID(quad.p, quad.q, quad.r, quad.s, col, (sf==0||sf==SF)); \ } Object _dxfField_Gather(Field f, struct gather *gather, struct tile *tile) { Point min, max; Line line; Triangle tri; Quadrilateral quad; int col, i, j, k, n, field, cull; struct sort *s; struct xfield *xf; InvalidComponentHandle ich = NULL; /* get the info we need */ field = gather->nfields; xf = gather->fields + field; cull = gather->cull; if (DXEmptyField(f)) return (Object) f; _dxf_XZero(xf); if (!_dxf_XPositions(f, xf, XR_REQUIRED, XD_NONE)) return NULL; if (!_dxf_XBox(f, xf, XR_REQUIRED, XD_GLOBAL)) return NULL; min.x = gather->min.x - .5 /* for lines */; min.y = gather->min.y - .5 /* for lines */; max.x = gather->max.x + .5 /* for lines */; max.y = gather->max.y + .5 /* for lines */; if (CULLBOX(xf->box, min, max)) return (Object) f; /* store parameters and get new ones */ if (!parameters((Object)f, &xf->tile, tile)) return NULL; /* get box for near plane for perspective clipping */ /* XXX - should do culling against near plane */ /* NB - this has to come after parameters() call */ if (xf->tile.perspective) xf->nearPlane = xf->box[0].z; if (!_dxf_XColors(f, xf, XR_REQUIRED, XD_GLOBAL)) return NULL; if (xf->tile.approx!=approx_dots) { if (!_dxf_XOpacities(f, xf, XR_OPTIONAL, XD_GLOBAL)) return NULL; if (!_dxf_XConnections(f, xf, XR_OPTIONAL)) return NULL; if (!_dxf_XPolylines(f, xf, XR_OPTIONAL, XD_GLOBAL)) return NULL; } if (!xf->opacities_array && !xf->volume) return (Object) f; if (xf->connections_array && xf->nconnections==0) /* to match _Count */ return (Object) f; if (!_dxf_XNeighbors(f, xf, XR_REQUIRED, XD_GLOBAL)) return NULL; /* sanity check for fcolors = bcolors for volumes */ /* and for position-dependent */ /* XXX - xf->volume? */ if (xf->ct==ct_cubes || xf->ct==ct_tetrahedra) if (xf->fcolors_array != xf->bcolors_array) DXErrorReturn(ERROR_INVALID_DATA, "use colors and not front/back colors for volumes"); /* Get lighting parameters if they are present */ if (! _dxf_XLighting(f, xf)) return NULL; /* * In regular case, sort is null, but we still gather the field * NB - Gather__Clipped depends on this to determine whether a * translucent or volume object was clipped */ gather->nfields += 1; DXDebug("G", " is included (lt %g rt %g bt %g tp %g)", xf->box[0].x, xf->box[7].x, xf->box[0].y, xf->box[7].y); if (xf->ct == ct_none) { if (! _dxf_XInvalidPositions(f, xf)) return NULL; } else { if (! _dxf_XInvalidConnections(f, xf)) return NULL; if (! _dxf_XInvalidPolylines(f, xf)) return NULL; } /* * Everything from here down is assumed to require an expanded * positions list because a sort array is involved. If a sort * array is not involved, i.e. one of the regular cases, we would * not have expanded the positions (XD_NONE above), and it is up * to the regular volume rendering code to handle the compact array. */ if (!gather->sort) return (Object) f; xf->positions = (Point *) DXGetArrayData(xf->positions_array); if (!xf->positions) return NULL; /* where to start */ s = gather->current; /* translucent points */ if (xf->ct==ct_none) { if (!_dxf_XInvalidPositions(f, xf)) return NULL; ich = xf->iPts; for (i=0; inpositions; i++) if (!ich || DXIsElementValid(ich, i)) POINT(i); } /* translucent lines */ else if (xf->ct==ct_lines) { if (!_dxf_XInvalidConnections(f, xf)) return NULL; ich = xf->iElts; for (i=0; inconnections; i++) if (!ich || DXIsElementValid(ich, i)) LINE(i); } else if (xf->ct == ct_polylines) { if (!_dxf_XInvalidPolylines(f, xf)) return NULL; for (i=0; i < xf->nconnections; i++) { POLYLINE(i); } } /* translucent triangles */ else if (xf->ct==ct_triangles) { if (!_dxf_XInvalidConnections(f, xf)) return NULL; ich = xf->iElts; for (i=0; inconnections; i++) if (!ich || DXIsElementValid(ich, i)) TRI(i, 0); } /* translucent quads */ else if (xf->ct==ct_quads) { if (!_dxf_XInvalidConnections(f, xf)) return NULL; ich = xf->iElts; /* XXX - local? */ xf->c.quads = (Quadrilateral *) DXGetArrayData/*Local*/(xf->connections_array); if (!xf->c.quads) return NULL; for (i=0; inconnections; i++) if (!ich || DXIsElementValid(ich, i)) QUAD(i, 0); DXFreeArrayDataLocal(xf->connections_array, (Pointer)xf->c.quads); } /* tetrahedra dep positions */ else if (xf->ct==ct_tetrahedra && xf->colors_dep==dep_positions) { if (!_dxf_XInvalidConnections(f, xf)) return NULL; ich = xf->iElts; for (i=0; inconnections; i++) { int *neighbors = ((int(*)[4])(xf->neighbors))[i]; int valid = !ich || DXIsElementValid(ich, i); /* for each face of tetra */ for (j=0; j<4; j++) { /* include triangles on boundary */ /* and triangles we haven't done before */ if (neighbors[j]<0 || neighbors[j]c.tetrahedra[i])))[(k+j+1)%4]; if (valid) TRI_PTS(tri.p, tri.q, tri.r, neighbors[j]<0) else TRI_PTS_INVALID(tri.p, tri.q, tri.r, neighbors[j]<0) } } } } /* tetrahedra dep connections */ else if (xf->ct==ct_tetrahedra && xf->colors_dep==dep_connections) { if (!_dxf_XInvalidConnections(f, xf)) return NULL; ich = xf->iElts; for (i=0; inconnections; i++) { int *neighbors = ((int(*)[4])(xf->neighbors))[i]; int valid = !ich || DXIsElementValid(ich, i); /* for each face of tetra */ for (j=0; j<4; j++) { /* include triangles on boundary */ /* and triangles we haven't done before */ if (neighbors[j]<0 || neighbors[j]c.tetrahedra[i])))[(k+j+1)%4]; if (valid) TRI_FLAT(tri.p, tri.q, tri.r, i, neighbors[j]<0) else TRI_FLAT_INVALID(tri.p, tri.q, tri.r, i, neighbors[j]<0) } } } } /* three-dimensional regular connections cube faces dep positions */ else if (xf->ct==ct_cubes && xf->colors_dep==dep_positions) { if (!_dxf_XInvalidConnections(f, xf)) return NULL; ich = xf->iElts; if (!xf->neighbors_array) { if (! ich) { int X = xf->k[0], Y = xf->k[1], Z = xf->k[2], x, y, z; for (x=0; xk[0], Y = xf->k[1], Z = xf->k[2]; int x, y, z, colx, coly, colz; for (x=0; xc.cubes = (Cube *)DXGetArrayData(xf->connections_array); if (!xf->c.cubes) return ERROR; /* cubes dep positions */ for (i=0; inconnections; i++) { int *nbrs = ((int(*)[6])(xf->neighbors))[i]; int *cube = (int *)&(xf->c.cubes[i]); int valid = !ich || DXIsElementValid(ich, i); if (valid) { if (nbrs[0]<0 || nbrs[0]ct==ct_cubes && xf->colors_dep==dep_connections) { if (!_dxf_XInvalidConnections(f, xf)) return NULL; ich = xf->iElts; if (!xf->neighbors_array) { int X = xf->k[0], Y = xf->k[1], Z = xf->k[2]; int x, y, z, colx, coly, colz; for (x=0; xc.cubes = (Cube *)DXGetArrayData(xf->connections_array); if (!xf->c.cubes) return ERROR; /* cubes dep positions */ for (i=0; inconnections; i++) { int *nbrs = ((int(*)[6])(xf->neighbors))[i]; int *cube = (int *)&(xf->c.cubes[i]); int valid = !ich || DXIsElementValid(ich, i); if (valid) { if (nbrs[0]<0 || nbrs[0]current = s; return (Object) f; } /* * Gather the translucent "triangles" from a group */ Object _dxfGroup_Gather(Group g, struct gather *gather, struct tile *tile) { Object o; int i; struct tile new; if (!parameters((Object)g, &new, tile)) return NULL; if (DXGetObjectClass((Object)g)==CLASS_COMPOSITEFIELD) new.ignore = 1; for (i=0; o=DXGetEnumeratedMember(g, i, NULL); i++) { DXDebug("G", "member %d", i); if (!_dxfGather(o, gather, &new)) return NULL; } return (Object) g; } /* * No faces in a Light * XXX - if Shade() removed lights, this would not be necessary */ Object _dxfLight_Gather(Light l, struct gather *gather, struct tile *tile) { return (Object) l; } Object _dxfXform_Gather(Xform x, struct gather *gather, struct tile *tile) { Object o; struct tile new; if (!parameters((Object)x, &new, tile)) return NULL; if (!DXGetXformInfo(x, &o, NULL)) return NULL; return _dxfGather(o, gather, &new); } Object _dxfScreen_Gather(Screen s, struct gather *gather, struct tile *tile) { Object o; struct tile new; if (!parameters((Object)s, &new, tile)) return NULL; new.perspective = 0; if (!DXGetScreenInfo(s, &o, NULL, NULL)) return NULL; return _dxfGather(o, gather, &new); } Object _dxfClipped_Gather(Clipped clipped, struct gather *gather, struct tile *tile) { Object render, clipping; int n = gather->nfields; struct tile new; DXGetClippedInfo(clipped, &render, &clipping); if (!parameters((Object)clipped, &new, tile)) return NULL; if (!_dxfGather(render, gather, &new)) return NULL; /* translucent faces clipped by this surface? */ if (n!=gather->nfields) { if (gather->clipping && gather->clipping!=clipping) DXErrorReturn(ERROR_BAD_PARAMETER, "only one clipping object allowed for all translucent objects"); gather->clipping = clipping; } return (Object) clipped; }