/***********************************************************************/ /* 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" */ /***********************************************************************/ #define CEIL(x) ((int)((x)-30000.0)+30000) #ifdef PASS4 #define CAT(a,b) a##b #endif /* to avoid overflow on fp->int */ #define MAX (DXD_MAX_INT/2) /* * 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 line.c also. */ #define OPACITY_THRESHOLD 0.5 #ifdef PASS2 #define TRIANGLEX1(pst, pptr, shrgb, sho, col, face, TEST, PIXEL, LABEL, VER) {$\ $\ pst *pp, *p; $\ Pointer colors; $\ int cstcolors; $\ RGBColor cbuf1, cbuf2, cbuf3; $\ char cbyte; $\ char obyte = xf->obyte; $\ $\ /* offsets */ $\ x1+=ox, y1+=oy; $\ x2+=ox, y2+=oy; $\ x3+=ox, y3+=oy; $\ $\ /* avoid overflow - XXX check performance impact */ $\ if (x1<-MAX || x1>MAX || y1<-MAX || y1>MAX || $\ x2<-MAX || x2>MAX || y2<-MAX || y2>MAX || $\ x3<-MAX || x3>MAX || y3<-MAX || y3>MAX) $\ DXErrorReturn(ERROR_BAD_PARAMETER, $\ "camera causes numerical overflow"); $\ $\ /* x delta setup; sign of d also indicates parity */ $\ d1 = y3-y2, d2 = y1-y3, d3 = y2-y1; $\ d = x1*d1 + x2*d2 + x3*d3; $\ Qx = d? (float)1.0 / (float)d : 0.0; $\ d1 *= Qx, d2 *= Qx, d3 *= Qx; $\ $\ /* colors */ $\ if (col) { $\ if (d < 0) $\ cbyte = fbyte, colors = fcolors, cstcolors = xf->fcst; $\ else $\ cbyte = bbyte, colors = bcolors, cstcolors = xf->bcst; $\ if (!colors) goto CAT(LABEL,VER); $\ } $\ if (shrgb) { $\ if (shademe) { $\ c1 = ((RGBColor *)colors) + i1; $\ c2 = ((RGBColor *)colors) + i2; $\ c3 = ((RGBColor *)colors) + i3; $\ } else { $\ if (cmap) $\ c1= &MAPCOLS(v1), c2= &MAPCOLS(v2), c3= &MAPCOLS(v3); $\ else { $\ COLS(v1, cbuf1); COLS(v2, cbuf2); COLS(v3, cbuf3); $\ c1 = &cbuf1; c2 = &cbuf2; c3 = &cbuf3; $\ } $\ } $\ r1=c1->r, g1=c1->g, b1=c1->b; $\ r2=c2->r, g2=c2->g, b2=c2->b; $\ r3=c3->r, g3=c3->g, b3=c3->b; $\ } else if (col) { $\ if (cmap){ $\ r=MAPCOLS(index).r; g=MAPCOLS(index).g; b=MAPCOLS(index).b; $\ } else { $\ COLS(index, cbuf1); $\ r = cbuf1.r; g = cbuf1.g; b = cbuf1.b; $\ } $\ } $\ if (sho) { $\ if (omap) o1=MAPOPS(v1), o2=MAPOPS(v2), o3=MAPOPS(v3); $\ else { $\ OPS(v1, o1); OPS(v2, o2); OPS(v3, o3); $\ } $\ } else if (opacities||omap) { $\ if (omap) o=MAPOPS(index); $\ else OPS(index, o); $\ obar = 1.0-o; $\ } else $\ o = 1.0, obar = 0.0; $\ $\ /* x deltas */ $\ if (shrgb) { $\ dxr = (r1 == r2 && r1 == r3) ? 0.0 : d1*r1 + d2*r2 + d3*r3; $\ dxg = (g1 == g2 && g1 == g3) ? 0.0 : d1*g1 + d2*g2 + d3*g3; $\ dxb = (b1 == b2 && b1 == b3) ? 0.0 : d1*b1 + d2*b2 + d3*b3; $\ } $\ if (sho) dxo = (o1 == o2 && o1 == o3) ? 0.0 : d1*o1 + d2*o2 + d3*o3;$\ dxz = (z1 == z2 && z1 == z3) ? 0.0 : d1*z1 + d2*z2 + d3*z3; $\ $\ /* sort pts so 1 <= 2 <= 3, so 1 to 3 is the long edge */ $\ XCHNG(y1,y2,x1,x2,r1,r2,g1,g2,b1,b2,o1,o2,z1,z2,shrgb,sho) $\ XCHNG(y1,y3,x1,x3,r1,r3,g1,g3,b1,b3,o1,o3,z1,z3,shrgb,sho) $\ XCHNG(y2,y3,x2,x3,r2,r3,g2,g3,b2,b3,o2,o3,z2,z3,shrgb,sho) $\ $\ /* object bounds for faces */ $\ /* XXX - phooey, reusing A and B here to avoid compiler problems */ $\ if (face) { $\ A = B = x1; $\ if (x2B) B = x3; $\ if (Afmin.x) buf->fmin.x = A; $\ if (B>buf->fmax.x) buf->fmax.x = B; $\ if (y1fmin.y) buf->fmin.y = y1; $\ if (y3>buf->fmax.y) buf->fmax.y = y3; $\ } $\ $\ /* round up to get iy1, iy2, iy3*/ $\ iy1 = CEIL(y1), iy2 = CEIL(y2), iy3 = CEIL(y3); $\ if (iy1>iy2 || iy2>iy3) { $\ DXSetError(ERROR_INVALID_DATA, $\ "position number %d, %d, or %d is invalid", v1, v2, v3); $\ return NULL; $\ } $\ if (iy1==iy3) /* TIME */ $\ goto CAT(LABEL,VER); #define TRIANGLEX2(pst, pptr, shrgb, sho, col, face, TEST, PIXEL, LABEL, VER)$\ /* y deltas */ $\ d = y3 - y1; $\ Qy = d? (float)1.0 / (float)d : 0.0; $\ if (shrgb) dyr=(r3-r1)*Qy, dyg=(g3-g1)*Qy, dyb=(b3-b1)*Qy; $\ if (sho) dyo = (float)(o3-o1) * Qy; $\ dyz = (z3-z1) * Qy; $\ dyA = (float)(x3-x1) * Qy; $\ $\ /* initial values */ $\ A = x1; $\ pp = buf->pptr + iy1*width; $\ $\ /* y fractional pixel adjustment and/or y clip */ $\ d = iy1 - y1; $\ if (iy1<0) $\ d-=iy1, pp=buf->pptr; $\ A += dyA*d; $\ if (shrgb) r1+=dyr*d, g1+=dyg*d, b1+=dyb*d; $\ if (sho) o1+=dyo*d; $\ z1 += dyz*d; $\ $\ /* do the two halves of the triangle */ $\ nn = 0; $\ HALF(iy1, iy2, x1, x2, y1, y2, shrgb, sho, TEST, PIXEL) $\ HALF(iy2, iy3, x2, x3, y2, y3, shrgb, sho, TEST, PIXEL) $\ buf->pixels += nn; $\ } #define TRIANGLEV1(pst, pptr, shrgb, sho, col, face, TEST, PIXEL, LABEL, VER) {$\ $\ pst *pp, *p; $\ Pointer colors; $\ int cstcolors; $\ RGBColor cbuf1, cbuf2, cbuf3; $\ char cbyte; $\ char obyte = xf->obyte; $\ $\ /* offsets */ $\ x1+=ox, y1+=oy; $\ x2+=ox, y2+=oy; $\ x3+=ox, y3+=oy; $\ $\ /* avoid overflow - XXX check performance impact */ $\ if (x1<-MAX || x1>MAX || y1<-MAX || y1>MAX || $\ x2<-MAX || x2>MAX || y2<-MAX || y2>MAX || $\ x3<-MAX || x3>MAX || y3<-MAX || y3>MAX) $\ DXErrorReturn(ERROR_BAD_PARAMETER, $\ "camera causes numerical overflow"); $\ $\ /* x delta setup; sign of d also indicates parity */ $\ d1 = y3-y2, d2 = y1-y3, d3 = y2-y1; $\ d = x1*d1 + x2*d2 + x3*d3; $\ Qx = d? (float)1.0 / (float)d : 0.0; $\ d1 *= Qx, d2 *= Qx, d3 *= Qx; $\ $\ /* colors ONLY if valid */ $\ if (valid) { $\ if (col) { $\ if (d < 0) $\ cbyte = fbyte, colors = fcolors, cstcolors = xf->fcst; $\ else $\ cbyte = bbyte, colors = bcolors, cstcolors = xf->bcst; $\ if (!colors) goto CAT(LABEL,VER); $\ } $\ if (shrgb) { $\ if (cmap) c1= &MAPCOLS(v1), c2= &MAPCOLS(v2), c3= &MAPCOLS(v3);$\ else { $\ COLS(v1, cbuf1); COLS(v2, cbuf2); COLS(v3, cbuf3); $\ c1 = &cbuf1; c2 = &cbuf2; c3 = &cbuf3; $\ } $\ r1=c1->r, g1=c1->g, b1=c1->b; $\ r2=c2->r, g2=c2->g, b2=c2->b; $\ r3=c3->r, g3=c3->g, b3=c3->b; $\ } else if (col) { $\ if (cmap) r=MAPCOLS(i).r, g=MAPCOLS(i).g, b=MAPCOLS(i).b; $\ else { $\ COLS(i, cbuf1); $\ r = cbuf1.r; g = cbuf1.g; b = cbuf1.b; $\ } $\ } $\ if (sho) { $\ if (omap) o1=MAPOPS(v1), o2=MAPOPS(v2), o3=MAPOPS(v3); $\ else { $\ OPS(v1, o1); OPS(v2, o2); OPS(v3, o3); $\ } $\ } else if (opacities||omap) { $\ if (omap) o=MAPOPS(i); $\ else OPS(i, o); $\ obar = 1.0-o; $\ } else $\ o = 1.0, obar = 0.0; $\ $\ if (shrgb) dxr = d1*r1 + d2*r2 + d3*r3; $\ if (shrgb) dxg = d1*g1 + d2*g2 + d3*g3; $\ if (shrgb) dxb = d1*b1 + d2*b2 + d3*b3; $\ if (sho) dxo = d1*o1 + d2*o2 + d3*o3; $\ } else $\ r1 = r2 = r3 = g1 = g2 = g3 = b1 = b2 = b3 = o1 = o2 = o3 = 0.0;$\ $\ /* x deltas */ $\ dxz = d1*z1 + d2*z2 + d3*z3; $\ $\ /* sort pts so 1 <= 2 <= 3, so 1 to 3 is the long edge */ $\ XCHNG(y1,y2,x1,x2,r1,r2,g1,g2,b1,b2,o1,o2,z1,z2,shrgb,sho) $\ XCHNG(y1,y3,x1,x3,r1,r3,g1,g3,b1,b3,o1,o3,z1,z3,shrgb,sho) $\ XCHNG(y2,y3,x2,x3,r2,r3,g2,g3,b2,b3,o2,o3,z2,z3,shrgb,sho) $\ $\ /* object bounds for faces */ $\ /* XXX - phooey, reusing A and B here to avoid compiler problems */ $\ if (face) { $\ A = B = x1; $\ if (x2B) B = x3; $\ if (Afmin.x) buf->fmin.x = A; $\ if (B>buf->fmax.x) buf->fmax.x = B; $\ if (y1fmin.y) buf->fmin.y = y1; $\ if (y3>buf->fmax.y) buf->fmax.y = y3; $\ } $\ $\ /* round up to get iy1, iy2, iy3*/ $\ iy1 = CEIL(y1), iy2 = CEIL(y2), iy3 = CEIL(y3); $\ if (iy1>iy2 || iy2>iy3) { $\ DXSetError(ERROR_INVALID_DATA, $\ "position number %d, %d, or %d is invalid", v1, v2, v3); $\ return NULL; $\ } $\ if (iy1==iy3) /* TIME */ $\ goto CAT(LABEL,VER); $\ $\ /* y deltas */ $\ d = y3 - y1; $\ Qy = d? (float)1.0 / (float)d : 0.0; $\ if (valid) { $\ if (shrgb) dyr=(r3-r1)*Qy, dyg=(g3-g1)*Qy, dyb=(b3-b1)*Qy; $\ if (sho) dyo = (float)(o3-o1) * Qy; $\ } $\ dyz = (z3-z1) * Qy; $\ dyA = (float)(x3-x1) * Qy; $\ $\ /* initial values */ $\ A = x1; $\ pp = buf->pptr + iy1*width; $\ $\ /* y fractional pixel adjustment and/or y clip */ $\ d = iy1 - y1; $\ if (iy1<0) $\ d-=iy1, pp=buf->pptr; $\ A += dyA*d; #define TRIANGLEV2(pst, pptr, shrgb, sho, col, face, TEST, PIXEL, LABEL, VER)$\ $\ if (valid) { $\ if (shrgb) r1+=dyr*d, g1+=dyg*d, b1+=dyb*d; $\ if (sho) o1+=dyo*d; $\ } $\ z1 += dyz*d; $\ $\ /* do the two halves of the triangle */ $\ nn = 0; $\ if (valid) { $\ HALF(iy1, iy2, x1, x2, y1, y2, shrgb, sho, TEST, PIXEL) $\ HALF(iy2, iy3, x2, x3, y2, y3, shrgb, sho, TEST, PIXEL) $\ } else { $\ HALF(iy1, iy2, x1, x2, y1, y2, 0, 0, TEST, PIXEL) $\ HALF(iy2, iy3, x2, x3, y2, y3, 0, 0, TEST, PIXEL) $\ } $\ buf->pixels += nn; $\ } #endif #ifdef PASS3 #define X(a,b) (d=a, a=b, b=d) #define XCHNG(y1,y2,x1,x2,r1,r2,g1,g2,b1,b2,o1,o2,z1,z2,shrgb,sho) { $\ if (y2 < y1) { $\ X(y1,y2), X(x1,x2); $\ if (shrgb) X(r1,r2), X(g1,g2), X(b1,b2); $\ if (sho) X(o1,o2); $\ X(z1,z2); $\ } $\ } /* direct or mapped colors */ #define COLS(i, dst) $\ { $\ if (cbyte) $\ { $\ RGBByteColor *ptr=((RGBByteColor *)colors)+(cstcolors ? 0 : i); $\ dst.r = _dxd_ubyteToFloat[ptr->r]; $\ dst.g = _dxd_ubyteToFloat[ptr->g]; $\ dst.b = _dxd_ubyteToFloat[ptr->b]; $\ } else $\ dst = (((RGBColor *)colors)[cstcolors ? 0 : i]); $\ } #define OPS(i, dst) $\ { $\ if (obyte) $\ dst = _dxd_ubyteToFloat[((ubyte *)opacities)[xf->ocst ? 0 : i]]; $\ else $\ dst = (((float *)opacities)[xf->ocst ? 0 : i]); $\ } #define MAPCOLS(i) (cmap[((unsigned char *)colors)[cstcolors ? 0 : i]]) #define MAPOPS(i) (omap[((unsigned char *)opacities)[xf->ocst ? 0 : i]]) /* * The various per-pixel routines. We start with the opaque * cases: opaque triangles, and triangles that are part of * the faces/loops/edges stuff. We define two comparisons, * for case of render-time CSG (CLIPZ) or no render-time CSG * (NOCLIPZ). We also define a comparison for interference checking * (IFZ) that also flips the IF_OBJECT bit as appropriate. */ /* * The IFZ macro here is a conditional containing an outer condition * controlling an XOR assignment, followed by a continuation of the condition. * To get around a preprocessor limitation (commas in macro arguments) we * (Nancy and Greg) changed the inner XOR assignment to an additional * term in the condition that always evaluates TRUE. */ #define CLIPZ (z>p->z && zfront && z>p->back) #define NOCLIPZ (z>p->z) #define IFZ ((zfront) && \ (1 | (p->in^=IF_OBJECT)) && \ (z>p->z) && \ (z>p->back)) #define OPAQUE { \ p->c.r=r; p->c.g=g; p->c.b=b; p->z=z; \ } #define FACE { \ /* reuse co.o for z here; XXX-use union? */ \ p->co.r=r; p->co.g=g; p->co.b=b; p->co.o=z; \ p->in ^= IN_FACE; \ } /* * Clipping triangles just affect the front/back buffers */ #define CLIPPINGPIXEL { \ if (z > p->front) /* find frontmost surface */ \ p->front = z; /* XXX - could use orientation of face */ \ if (z < p->back) /* find backmost surface */ \ p->back = z; \ } /* * For translucent triangles, 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 line.c. */ #define TRANSCLIPZ (z>p->z && zfront) #define TRANSLUCENT { \ p->c.r=o*r+obar*p->c.r; \ p->c.g=o*g+obar*p->c.g; \ p->c.b=o*b+obar*p->c.b; \ if (o > OPACITY_THRESHOLD) \ p->z=z; \ } #define COMPOSITE { \ p->c.r=r+obar*p->c.r; \ p->c.g=g+obar*p->c.g; \ p->c.b=b+obar*p->c.b; \ } /* * We use ->back instead of ->z to keep track of the distance to * the last volume face rendered; this allows us to leave ->z alone, * which makes it possible to mix translucent surfaces clipped by * ->z with volumes. In order for this to work, we have to have * merged ->back into ->z before doing translucent surfaces and * volumes. */ #define VOLUME { \ if (p->in<=0) { \ if (z < p->front) { \ if (surface) { \ p->in++; \ if (z > p->back) \ p->back = z; \ if (valid && !xf->tile.flat_z) \ { p->co.r=r; p->co.g=g; p->co.b=b; } \ } \ } \ } else { \ if (surface) \ p->in = 0; \ if (z >= p->front) { \ p->in = -DXD_MAX_INT; \ z = p->front; \ } \ if (z > p->back) { \ float ar; float ag; float ab; float ao; \ if (valid) { /* don't affect color if not valid, just Z */ \ if (/*xf->tile.flat_z*/ 1) { \ d = (z - p->back) * cmul; \ ar = d * r; \ ag = d * g; \ ab = d * b; \ ao = d * o * omul; \ } else { \ d = 0.5 * (z - p->back) * cmul; \ ar = d * (p->co.r+r); \ ag = d * (p->co.g+g); \ ab = d * (p->co.b+b); \ ao = d * (p->co.o+r) * omul; \ p->co.r = r; \ p->co.g = g; \ p->co.b = b; \ p->co.o = o; \ } \ if (/*xf->tile.fast_exp*/ 1) { \ if ((obar=1-ao) < 0.0) \ obar = 0.0; \ } else { \ if ((obar=1-0.125*ao) < 0.0) \ obar = 0.0; \ obar = obar*obar; obar = obar*obar; obar = obar*obar;\ } \ p->c.r = p->c.r * obar + ar; \ p->c.g = p->c.g * obar + ag; \ p->c.b = p->c.b * obar + ab; \ } \ p->back = z; \ } \ } \ } /* * shade/don't shade colors/opacities * colored/uncolored surfaces */ #define NOSHRGB 0 #define SHRGB 1 #define NOSHO 0 #define SHO 1 #define UNCOL 0 #define COL 1 #define CEIL(x) ((int)((x)-30000.0)+30000) #define HALF(iy1, iy2, x1, x2, y1, y2, shrgb, sho, TEST, PIXEL) { $\ $\ if (iy2>height) $\ iy2 = height; $\ if (iy10 && iy1<=height) { $\ B = x1; $\ d = y2 - y1; $\ d = d? (float)1.0 / (float)d : 0.0; $\ dyB = (float)(x2-x1) * d; $\ if (iy1<0) iy1=0; $\ d = iy1 - y1; $\ B += d*dyB; $\ for (iy=iy1; iyiA) left=iA, right=iB; $\ else left=iB, right=iA; $\ if (left<0) left=0; $\ if (right>width) right=width; $\ n = right - left; $\ if (n>0) { $\ nn += n; $\ p = pp+left; $\ d = left - A; $\ if (shrgb) r=r1+d*dxr, g=g1+d*dxg, b=b1+d*dxb; $\ if (sho) o=o1+d*dxo, obar=1.0-o; $\ z=z1+d*dxz; $\ while (--n>=0) { $\ if (TEST) { $\ PIXEL; $\ if (shrgb) r+=dxr, g+=dxg, b+=dxb; $\ if (sho) o+=dxo, obar=1.0-o; $\ z+=dxz; $\ p++; $\ } else { $\ if (shrgb) r+=dxr, g+=dxg, b+=dxb; $\ if (sho) o+=dxo, obar=1.0-o; $\ z+=dxz; $\ p++; $\ } $\ } $\ } $\ if (shrgb) r1+=dyr, g1+=dyg, b1+=dyb; $\ if (sho) o1+=dyo; $\ z1 += dyz; $\ A+=dyA, B+=dyB; $\ pp+=width; $\ } $\ } $\ } #endif