/***********************************************************************/ /* 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 "render.h" /* * The following is a kludge relating to to whether or not the * z-buffer is updated when a translucent surface is rendered. * When we render two transparent objects, we want the closer to * overlay the farther, which itself overlays still farther surfaces. * A centroid sort is used to approximately prioritize the transparent * surfaces. If it is incorrect at a given pixel, then (in the absense * of any other information) they are overlaid in the incorrect order. * Which, if the transparency of the front-most (and rendered first) * transparent surface is low, is an OK approximation. If, however, the * frontmost surface is relatively opaque, then this approximation * becomes less accurate. In this case it is better to forget about * the second transparent surface (which would erroneously be laid over * it). So when the surface is relatively opaque, we update the z-buffer * to eliminate subsequent farther surfaces. * * Note that this appears in triangles.h also. */ #define OPACITY_THRESHOLD 0.5 #define ABS(x) ((x)<0? -(x) : (x)) #define FLOOR(x) ((int)((x)+10000.0)-10000) #define ROUND(x) ((int)((x)+10000.5)-10000) /* * For translucent lines, we can assume that ->back has * already been merged into ->z; furthermore, we reuse ->back * in volume rendering, so it is incorrect to compare against * ->back here because we may be mixed in with volume faces * This also occurs in triangle.c. */ #define SCALE (1<<10) /* integer scaling */ #define MAX (1<<20) /* max coordinates before overflow */ #define CLIPZ (z>pix->z && zfront && z>pix->back) #define NOCLIPZ (z>pix->z) #define TRANSCLIPZ (z>pix->z && zfront) #define LOOP(flat,op,ztest) { \ \ for (i=0; i<=nmaj; i++) { \ if (op) { \ if (0<=x && xc.r = o*r + obar*pix->c.r; \ pix->c.g = o*g + obar*pix->c.g; \ pix->c.b = o*b + obar*pix->c.b; \ if (o > OPACITY_THRESHOLD) \ pix->z = z; \ } \ } else { \ if (0<=x && xc.r = r; \ pix->c.g = g; \ pix->c.b = b; \ pix->z = z; \ } \ } \ pix += dpix_dmaj; \ x += dx_dmaj; \ y += dy_dmaj; \ if ((frac-=min)<0) { \ frac += maj; \ pix += dpix_dmin; \ x += dx_dmin; \ y += dy_dmin; \ } \ z += dz; \ if (!flat) { \ r += dr; \ g += dg; \ b += db; \ } \ if (op) o += dop; \ } \ } #define CLIP(flat,op,clipz) { \ if (clip) \ LOOP(flat,op,clipz) \ else \ LOOP(flat,op,NOCLIPZ) \ } #define ZCLIP(p,p1, c,c1, o,o1) { \ float a = (nearPlane-p.z) / (p1.z-p.z); /* XXX */ \ float abar = 1.0-a; \ p.x = p.x*abar + p1.x*a; \ p.y = p.y*abar + p1.y*a; \ p.z = nearPlane; \ c.r = c.r*abar + c1.r*a; \ c.g = c.g*abar + c1.g*a; \ c.b = c.b*abar + c1.b*a; \ o = o*abar + o1*a; \ p.z = nearPlane; \ } #define XYCLIP(p,p1, c,c1, o,o1, x,y, dx,dy, op, mm) { \ float m = mm; \ if (p.x op m) { \ float d = (m - p.x) / dx; \ if (d<.5) { \ p.y += d * dy; \ p.z += d * (p1.z - p.z); \ c.r += d * (c1.r - c.r); \ c.g += d * (c1.g - c.g); \ c.b += d * (c1.b - c.b); \ o += d * (o1 - o); \ } else { \ d = (m - p1.x) / dx; \ p.y = p1.y + d * dy; \ p.z = p1.z + d * (p1.z - p.z); \ c.r = c1.r + d * (c1.r - c.r); \ c.g = c1.g + d * (c1.g - c.g); \ c.b = c1.b + d * (c1.b - c.b); \ o = o1 + d * (o1 - o); \ } \ p.x = m; \ } \ } static Error line(struct buffer *buf, struct xfield *xf, Line l, int flat, RGBColor c, RGBColor c1, float o, float o1, int clip) { Point p, p1; float length, d, dr, dg, db, r, g, b, z; float dx, dy, dz, dop, obar, a; int maj, dpix_dmaj, dy_dmaj, dx_dmaj; int min, dpix_dmin, dy_dmin, dx_dmin; int i, nmaj, x, y, frac; int width = buf->width, height = buf->height; /* positions */ p = xf->positions[l.p]; p1 = xf->positions[l.q]; /* perspective */ if (xf->tile.perspective) { float nearPlane = xf->nearPlane; if (p.z>nearPlane && p1.z>nearPlane) return OK; if (p.z>nearPlane) { ZCLIP(p,p1, c,c1, o,o1); } else if (p1.z>nearPlane) { ZCLIP(p1,p, c1,c, o1,o); } p.z = (float)-1.0/p.z; p.x *= p.z; p.y *= p.z; p1.z = (float)-1.0/p1.z; p1.x *= p1.z; p1.y *= p1.z; } /* quick check */ if ((p.xmin.x-.5 && p1.xmin.x-.5) || (p.ymin.y-.5 && p1.ymin.y-.5) || (p.x>buf->max.x+.5 && p1.x>buf->max.x+.5) || (p.y>buf->max.y+.5 && p1.y>buf->max.y+.5)) return OK; #if 0 /* overflow check - XXX check performance impact */ if (p.x>=MAX || p.x<=-MAX || p.y>=MAX || p.y<=-MAX || p1.x>=MAX || p1.x<=-MAX || p1.y>=MAX || p1.y<=-MAX) DXErrorReturn(ERROR_BAD_PARAMETER, "camera causes numerical overflow"); #endif /* deltas */ dx = p1.x - p.x; dy = p1.y - p.y; /* octant-dependent setup */ if (ABS(dy) < ABS(dx)) { XYCLIP(p,p1, c,c1, o,o1, x,y, dx, dy, <, buf->min.x-.5); XYCLIP(p1,p, c1,c, o1,o, x,y, -dx,-dy, <, buf->min.x-.5); XYCLIP(p,p1, c,c1, o,o1, x,y, dx, dy, >, buf->max.x+.5); XYCLIP(p1,p, c1,c, o1,o, x,y, -dx,-dy, >, buf->max.x+.5); dx = p1.x - p.x; dy = p1.y - p.y; x = ROUND(p.x); d = x - p.x; a = p.y + (dx? dy/dx*d : 0); y = ROUND(a); if (dx>0) dx_dmaj = 1, length = dx, nmaj = ROUND(p1.x) - x; else dx_dmaj = -1, length = -dx, nmaj = x - ROUND(p1.x); maj = length * SCALE; frac = (a - y) * maj; if (dy>0) dy_dmin = 1, min = dy*SCALE, frac = maj/2 - frac; else dy_dmin = -1, min = -dy*SCALE, frac = maj/2 + frac; dx_dmin = 0; dy_dmaj = 0; } else { XYCLIP(p,p1, c,c1, o,o1, y,x, dy, dx, <, buf->min.y-.5); XYCLIP(p1,p, c1,c, o1,o, y,x, -dy,-dx, <, buf->min.y-.5); XYCLIP(p,p1, c,c1, o,o1, y,x, dy, dx, >, buf->max.y+.5); XYCLIP(p1,p, c1,c, o1,o, y,x, -dy,-dx, >, buf->max.y+.5); dx = p1.x - p.x; dy = p1.y - p.y; y = ROUND(p.y); d = y - p.y; a = p.x + (dy? dx/dy*d : 0); x = ROUND(a); if (dy>0) dy_dmaj = 1, length = dy, nmaj = ROUND(p1.y) - y; else dy_dmaj = -1, length = -dy, nmaj = y - ROUND(p1.y); maj = length * SCALE; frac = (a - x) * maj; if (dx>0) dx_dmin = 1, min = dx*SCALE, frac = maj/2 - frac; else dx_dmin = -1, min = -dx*SCALE, frac = maj/2 + frac; dy_dmin = 0; dx_dmaj = 0; length = ABS(dy); } /* delta z, color, taking care not to divide by 0 */ dz = length? (p1.z - p.z) / length : 0.0; if (! flat) { dop = length? (o1 - o ) / length : 0.0; dr = length? (c1.r - c.r) / length : 0.0; dg = length? (c1.g - c.g) / length : 0.0; db = length? (c1.b - c.b) / length : 0.0; r = c.r + dr * d; g = c.g + dg * d; b = c.b + db * d; o += dop * d; } else { r = c.r; g = c.g; b = c.b; } z = p.z + dz * d; /* delta pix */ dpix_dmaj = dy_dmaj*width + dx_dmaj; dpix_dmin = dy_dmin*width + dx_dmin; /* offset */ x += buf->ox; y += buf->oy; if (buf->pix_type==pix_fast) { struct fast *pix = buf->u.fast + y*width + x; ASSERT(!clip); if (flat) if (xf->opacities) LOOP(1,1, NOCLIPZ) else LOOP(1,0, NOCLIPZ) else if (xf->opacities) LOOP(0,1, NOCLIPZ) else LOOP(0,0, NOCLIPZ) } else if (buf->pix_type==pix_big) { struct big *pix = buf->u.big + y*width + x; if (flat) if (xf->opacities) CLIP(1,1, TRANSCLIPZ) else CLIP(1,0, CLIPZ) else if (xf->opacities) CLIP(0,1, TRANSCLIPZ) else CLIP(0,0, CLIPZ) } return OK; } #define COLOR(i, dst) \ { \ if (cmap) \ dst = cmap[((unsigned char *)colors)[i]]; \ else if (fbyte) \ { \ ubyte *ptr = ((ubyte *)colors + 3*i); \ dst.r = _dxd_ubyteToFloat[*ptr++]; \ dst.g = _dxd_ubyteToFloat[*ptr++]; \ dst.b = _dxd_ubyteToFloat[*ptr++]; \ } \ else \ dst = ((RGBColor *)colors)[i]; \ } #define OPACITY(i, dst) \ { \ if (opacities) { \ if (omap) \ dst = omap[((unsigned char *)opacities)[i]]; \ else if (obyte) \ dst = _dxd_ubyteToFloat[((unsigned char *)opacities)[i]]; \ else \ dst = ((float *)opacities)[i]; \ } else \ dst = 1.0; \ } Error _dxf_Line(struct buffer *b, struct xfield *xf, int n, Line *lines, int *indices, int clip, inv_stat inv) { unsigned char *colors = (unsigned char *)xf->fcolors; unsigned char *opacities = (unsigned char *)xf->opacities; RGBColor *cmap = xf->cmap; float *omap = xf->omap; int i; InvalidComponentHandle ich = xf->iElts; RGBColor cbuf[2]; char fbyte = xf->fbyte; char obyte = xf->obyte; char fcst = xf->fcst; char ocst = xf->ocst; float pop, qop; int odep = xf->colors_dep == dep_connections; if (ocst) { OPACITY(0, pop); OPACITY(0, qop); } if (fbyte || obyte) _dxf_initUbyteToFloat(); if (xf->lights) { _dxfInitApplyLights(xf->kaf, xf->kdf, xf->ksf, xf->kspf, xf->kab, xf->kdb, xf->ksb, xf->kspb, xf->fcolors, xf->bcolors, xf->cmap, xf->normals, xf->lights, xf->colors_dep, xf->normals_dep==dep_positions, cbuf, NULL, 2, xf->fcst, xf->bcst, xf->ncst, fbyte, 0); for (i=0; ip, pop); OPACITY(l->q, qop); } } if (!line(b, xf, *l, 0, cbuf[0], cbuf[1], pop, qop, clip)) return ERROR; } } else { RGBColor pColor, qColor; if (!colors) DXErrorReturn(ERROR_BAD_PARAMETER, "lines must have front colors"); if (fcst) { COLOR(0, qColor); pColor = qColor; } for (i=0; ip, pop); OPACITY(l->q, qop); } } if (! fcst) { if (odep) { COLOR(index, pColor); qColor = pColor; } else { COLOR(l->p, pColor); COLOR(l->q, qColor); } } rc = line(b, xf, *l, 0, pColor, qColor, pop, qop, clip); if (!rc) return ERROR; } } return OK; } Error _dxf_LineFlat(struct buffer *b, struct xfield *xf, int n, Line *lines, int *indices, Pointer colors, Pointer opacities, int clip, inv_stat inv) { RGBColor *cmap = xf->cmap; float *omap = xf->omap; char obyte = xf->obyte; int i; InvalidComponentHandle ich = xf->iElts; RGBColor pColor, qColor; char fcst = xf->fcst; char fbyte = xf->fbyte; char ocst = xf->ocst; float pop, qop; int odep = xf->colors_dep == dep_connections; if (ocst) { OPACITY(0, pop); OPACITY(0, qop); } if (!xf->fcolors) DXErrorReturn(ERROR_BAD_PARAMETER, "lines must have front colors"); if (fcst) { COLOR(0, pColor); qColor = pColor; } for (i=0; ip, pop); OPACITY(l->q, qop); } } if (! fcst) { if (odep) { COLOR(index, pColor); qColor = pColor; } else { COLOR(l->p, pColor); COLOR(l->q, qColor); } } rc = line(b, xf, *l, 1, pColor, qColor, pop, qop, clip); if (!rc) return ERROR; } return OK; } Error _dxf_Polyline(struct buffer *b, struct xfield *xf, int n, int *polylines, int *indices, int clip, inv_stat inv) { unsigned char *colors = (unsigned char *)xf->fcolors; unsigned char *opacities = (unsigned char *)xf->opacities; RGBColor *cmap = xf->cmap; float *omap = xf->omap; int i; InvalidComponentHandle ich = xf->iElts; char fbyte = xf->fbyte; char obyte = xf->obyte; char fcst = xf->fcst; char ocst = xf->ocst; float pop, qop; dependency cdep = xf->colors_dep; int start, last, knt, j; Line *l; RGBColor *cbuf = NULL; int cbufknt = 0; if (indices) { DXSetError(ERROR_INTERNAL, "non-null indices in PolyLine"); return ERROR; } if (ocst) { OPACITY(0, pop); OPACITY(0, qop); } if (fbyte || obyte) _dxf_initUbyteToFloat(); if (xf->lights) { for (i=0; inedges-1 : polylines[i+1]-1; knt = last - start; if (ich && DXIsElementInvalid(ich, i)) continue; if (knt+1 > cbufknt) { cbuf = (RGBColor *)DXReAllocate(cbuf, (knt+1)*sizeof(RGBColor)); if (! cbuf) goto error; cbufknt = (knt+1); } l = (Line *)(xf->edges + start); /* * As far as appliyong lights goes, we pretend that polylines * are effectively connections elements of varying numbers * of vertices */ _dxfInitApplyLights(xf->kaf, xf->kdf, xf->ksf, xf->kspf, xf->kab, xf->kdb, xf->ksb, xf->kspb, xf->fcolors, xf->bcolors, xf->cmap, xf->normals, xf->lights, xf->colors_dep, xf->normals_dep, cbuf, NULL, (knt+1), xf->fcst, xf->bcst, xf->ncst, fbyte, 0); if (! _dxfApplyLights((int *)l, &i, 1)) return ERROR; if (!ocst && cdep == dep_positions) OPACITY(l->q, qop); for (j = 0; j < knt; j++, l = (Line *)(((int *)l) + 1)) { if (!ocst && cdep == dep_positions) { pop = qop; OPACITY(l->q, qop); } if (!line(b, xf, *l, 0, cbuf[j], cbuf[j+1], pop, qop, clip)) return ERROR; } } } else { RGBColor pColor, qColor; if (!colors) DXErrorReturn(ERROR_BAD_PARAMETER, "lines must have front colors"); if (fcst) { COLOR(0, qColor); pColor = qColor; } for (i=0; inedges-1 : polylines[i+1]-1; knt = last - start; if (ich && DXIsElementInvalid(ich, i)) continue; l = (Line *)(xf->edges + start); if (!ocst) { if (cdep == dep_polylines) { OPACITY(i, pop); qop = pop; } else if (cdep == dep_positions) { OPACITY(l->p, qop); } } if (!fcst) { if (cdep == dep_polylines) { COLOR(i, pColor); qColor = pColor; } else if (cdep == dep_positions) { COLOR(l->p, qColor); } } for (j = 0; j < knt; j++, l = (Line *)(((int *)l) + 1)) { if (!ocst && cdep == dep_positions) { pop = qop; OPACITY(l->q, qop); } if (!fcst && cdep == dep_positions) { pColor = qColor; COLOR(l->q, qColor); } if (!line(b, xf, *l, 0, pColor, qColor, pop, qop, clip)) return ERROR; } } } if (cbuf) DXFree((Pointer)cbuf); return OK; error: if (cbuf) DXFree((Pointer)cbuf); return ERROR; } Error _dxf_PolylineFlat(struct buffer *b, struct xfield *xf, int n, int *polylines, int *indices, Pointer colors, Pointer opacities, int clip, inv_stat inv) { RGBColor *cmap = xf->cmap; float *omap = xf->omap; char obyte = xf->obyte; int i; InvalidComponentHandle ich = xf->iElts; RGBColor pColor, qColor; char fcst = xf->fcst; char fbyte = xf->fbyte; char ocst = xf->ocst; float pop, qop; dependency cdep = xf->colors_dep; int start, last, knt, j; Line *l; if (ocst) { OPACITY(0, pop); OPACITY(0, qop); } if (!xf->fcolors) DXErrorReturn(ERROR_BAD_PARAMETER, "polylines must have front colors"); if (fcst) { COLOR(0, pColor); qColor = pColor; } for (i=0; inedges-1 : polylines[i+1]-1; knt = last - start; if (ich && DXIsElementInvalid(ich, i)) continue; l = (Line *)(xf->edges + start); if (!ocst) { if (cdep == dep_polylines) { OPACITY(i, pop); qop = pop; } else if (cdep == dep_positions) { OPACITY(l->p, qop); } } if (!fcst) { if (cdep == dep_polylines) { COLOR(i, pColor); qColor = pColor; } else if (cdep == dep_positions) { COLOR(l->p, qColor); } } for (j = 0; j < knt; j++, l = (Line *)(((int *)l) + 1)) { if (!ocst && cdep == dep_positions) { pop = qop; OPACITY(l->q, qop); } if (!fcst && cdep == dep_positions) { pColor = qColor; COLOR(l->q, qColor); } if (! line(b, xf, *l, 1, pColor, qColor, pop, qop, clip)) return ERROR; } } return OK; }