/* pixutils.c * RasMol2 Molecular Graphics * Roger Sayle, October 1994 * Version 2.5 */ #include "rasmol.h" #ifdef IBMPC #include #include #endif #ifdef APPLEMAC #ifdef __CONDITIONALMACROS__ #include #else #include #endif #include #endif #ifdef sun386 #include #endif #include #include #define PIXUTILS #include "pixutils.h" #include "graphics.h" #include "molecule.h" #include "transfor.h" #include "render.h" #include "font.h" #ifdef INVERT #define InvertY(y) (y) #else #define InvertY(y) (-(y)) #endif /* Sutherland-Cohen Line Clipping Macros */ #define BitAbove 0x01 #define BitBelow 0x02 #define BitRight 0x04 #define BitLeft 0x08 #define BitFront 0x10 #define Reject(x,y) ((x)&(y)) #define Accept(x,y) (!((x)|(y))) #define RootSix 2.44948974278 #define SETPIXEL(dptr,fptr,d,c) if( (d) > *(dptr) ) \ { *(dptr) = (d); \ *(fptr) = (c); \ } #define MAXVERT 10 typedef struct { Real dx,dz,di; Real x,z,i; } Edge; typedef struct { int x, y, z; int inten; } Vert; typedef struct { Vert v[MAXVERT]; int count; } Poly; typedef struct { short dx,dy,dz; short inten; Long offset; } ArcEntry; /* Note: DrawCylinderCaps currently employs an * extremely crude hack to avoid stripes * appearing along cylinders. */ #define ARCSIZE 2048 static ArcEntry __far *ArcAcPtr; static ArcEntry __far *ArcDnPtr; #if defined(IBMPC) || defined(APPLEMAC) static ArcEntry __far *ArcAc; static ArcEntry __far *ArcDn; #else static ArcEntry ArcAc[ARCSIZE]; static ArcEntry ArcDn[ARCSIZE]; #endif static char FontDimen[23]; static int ClipStatus; static int OutCode(x,y,z) register int x,y,z; { register int result; result=0; if( y<0 ) { result |= BitAbove; } else if( y>=YRange ) result |= BitBelow; if( x<0 ) { result |= BitLeft; } else if( x>=XRange ) result |= BitRight; if( !ZValid(z) ) result |= BitFront; return result; } #ifndef PIXUTILS /* Unused Function */ void PlotPoint(x,y,z,col) int x,y,z,col; { register Pixel __huge *fptr; register short __huge *dptr; register Long offset; /* SETPIXEL(dptr,fptr,z,Lut[col]); */ offset = (Long)y*XRange+x; dptr = DBuffer+offset; if( z > *dptr ) { fptr = FBuffer+offset; *fptr = Lut[col]; *dptr = z; } } #endif void ClipPoint(x,y,z,col) int x,y,z,col; { register Pixel __huge *fptr; register short __huge *dptr; register Long offset; if( XValid(x) && YValid(y) && ZValid(z) ) { /* PlotPoint(x,y,z,col); */ offset = (Long)y*XRange+x; dptr = DBuffer+offset; if( z > *dptr ) { fptr = FBuffer+offset; *fptr = Lut[col]; *dptr = z; } } } void PlotDeepPoint(x,y,z,col) int x,y,z,col; { register Long offset; register Pixel __huge *fptr; register short __huge *dptr; register int inten; offset = (Long)y*XRange+x; dptr = DBuffer+offset; if( z > *dptr ) { fptr = FBuffer+offset; inten = (ColourDepth*(z+ImageRadius-ZOffset))/ImageSize; *fptr = Lut[col+inten]; *dptr = z; } } void ClipDeepPoint(x,y,z,col) int x,y,z,col; { register Long offset; register Pixel __huge *fptr; register short __huge *dptr; register int inten; if( XValid(x) && YValid(y) && ZValid(z) ) { /* PlotDeepPoint(x,y,z,col); */ offset = (Long)y*XRange+x; dptr = DBuffer+offset; if( z > *dptr ) { fptr = FBuffer+offset; inten = (ColourDepth*(z+ImageRadius-ZOffset))/ImageSize; *fptr = Lut[col+inten]; *dptr = z; } } } /* Macros for Bresenhams Line Drawing Algorithm */ #define CommonStep(s) z1 += zrate; SETPIXEL(dptr,fptr,z1,c); \ if( (zerr+=dz)>0 ) { zerr-=(s); z1+=iz; } #define XStep { if((err+=dy)>0) { fptr+=ystep; dptr+=ystep; err-=dx; } \ fptr+=ix; dptr+=ix; x1+=ix; CommonStep(dx); } #define YStep { if((err+=dx)>0) { fptr+=ix; dptr+=ix; err-=dy; } \ fptr+=ystep; dptr+=ystep; y1+=iy; CommonStep(dy); } void DrawTwinLine(x1,y1,z1,x2,y2,z2,col1,col2) int x1,y1,z1,x2,y2,z2,col1,col2; { register Long offset; register Pixel __huge *fptr; register short __huge *dptr; register int zrate, zerr; register int ystep,err; register int ix,iy,iz; register int dx,dy,dz; register int mid; register Pixel c; c = Lut[col1]; offset = (Long)y1*XRange + x1; fptr = FBuffer+offset; dptr = DBuffer+offset; SETPIXEL(dptr,fptr,z1,c); dx = x2-x1; dy = y2-y1; dz = z2-z1; if( !dx && !dy ) return; ystep = XRange; ix = iy = iz = 1; if( dy<0 ) { dy = -dy; iy = -1; ystep = -ystep; } if( dx<0 ) { dx = -dx; ix = -1; } if( dz<0 ) { dz = -dz; iz = -1; } if( dx>dy ) { zrate = dz/dx; dz -= dx*zrate; err = zerr = -(dx>>1); if( col1 != col2 ) { mid = (x1+x2)>>1; while( x1!=mid ) XStep; c = Lut[col2]; } while( x1!=x2 ) XStep; } else { zrate = dz/dy; dz -= dy*zrate; err = zerr = -(dy>>1); if( col1 != col2 ) { mid = (y1+y2)>>1; while( y1!=mid ) YStep; c = Lut[col2]; } while( y1!=y2 ) YStep; } } static void ClipLine(x1,y1,z1,x2,y2,z2,col) int x1,y1,z1,x2,y2,z2,col; { register int code1,code2; register int delta,rest; register int temp; while( True ) { code1 = OutCode(x1,y1,z2); code2 = OutCode(x2,y2,z2); if( Reject(code1,code2) ) return; if( Accept(code1,code2) ) break; if( !code1 ) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; temp=z1; z1=z2; z2=temp; code1 = code2; } if( code1 & BitAbove ) { delta = y2-y1; x1 += (int)(((Long)y1*(x1-x2))/delta); z1 += (int)(((Long)y1*(z1-z2))/delta); y1 = 0; } else if( code1 & BitLeft ) { delta = x2-x1; y1 += (int)(((Long)x1*(y1-y2))/delta); z1 += (int)(((Long)x1*(z1-z2))/delta); x1 = 0; } else if( code1 & BitRight ) { delta = x2-x1; temp=XRange-1; rest=temp-x1; y1 += (int)(((Long)rest*(y2-y1))/delta); z1 += (int)(((Long)rest*(z2-z1))/delta); x1 = temp; } else if( code1 & BitBelow ) { delta = y2-y1; temp=YRange-1; rest=temp-y1; x1 += (int)(((Long)rest*(x2-x1))/delta); z1 += (int)(((Long)rest*(z2-z1))/delta); y1 = temp; } else /* SLAB */ { delta = z2-z1; rest = SlabValue-z1; x1 += (int)(((Long)rest*(x2-x1))/delta); y1 += (int)(((Long)rest*(y2-y1))/delta); z1 = SlabValue; } } DrawTwinLine(x1,y1,z1,x2,y2,z2,col,col); } void ClipTwinLine(x1,y1,z1,x2,y2,z2,col1,col2) int x1,y1,z1,x2,y2,z2,col1,col2; { register int xmid,ymid,zmid; register int code1,code2; if( col1!=col2 ) { code1 = OutCode(x1,y1,z1); code2 = OutCode(x2,y2,z2); if( !Reject(code1,code2) ) { if( !Accept(code1,code2) ) { xmid = (x1+x2)/2; ymid = (y1+y2)/2; zmid = (z1+z2)/2; ClipLine(x1,y1,z1,xmid,ymid,zmid,col1); ClipLine(xmid,ymid,zmid,x2,y2,z2,col2); } else DrawTwinLine(x1,y1,z1,x2,y2,z2,col1,col2); } } else ClipLine(x1,y1,z1,x2,y2,z2,col1); } /* Macros for 3D Bresenhams Vector Algorithm */ #define CommonVectStep(s) z1 += zrate; c1 += crate; \ SETPIXEL(dptr,fptr,z1,Lut[col+c1]); \ if( (zerr+=dz)>0 ) { zerr -= (s); z1 += iz; } \ if( (cerr+=dc)>0 ) { cerr -= (s); c1 += iz; } #define XVectStep { if((err+=dy)>0) { fptr+=ystep; dptr+=ystep; err-=dx; } \ fptr+=ix; dptr+=ix; x1+=ix; CommonVectStep(dx); } #define YVectStep { if((err+=dx)>0) { fptr+=ix; dptr+=ix; err-=dy; } \ fptr+=ystep; dptr+=ystep; y1+=iy; CommonVectStep(dy); } void DrawTwinVector(x1,y1,z1,x2,y2,z2,col1,col2) int x1,y1,z1,x2,y2,z2,col1,col2; { register Long offset; register Pixel __huge *fptr; register short __huge *dptr; register int dx,dy,dz,dc; register int crate, cerr; register int zrate, zerr; register int ystep,err; register int ix,iy,iz; register int col, mid; register int c1, c2; c1 = (ColourDepth*(z1+ImageRadius-ZOffset))/ImageSize; c2 = (ColourDepth*(z2+ImageRadius-ZOffset))/ImageSize; offset = (Long)y1*XRange + x1; fptr = FBuffer+offset; dptr = DBuffer+offset; SETPIXEL(dptr,fptr,z1,Lut[col1+c1]); dx = x2 - x1; dy = y2 - y1; dz = z2 - z1; dc = c2 - c1; if( !dx && !dy ) return; if( dy<0 ) { ystep = -XRange; dy = -dy; iy = -1; } else { ystep = XRange; iy = 1; } if( dx<0 ) { dx = -dx; ix = -1; } else ix = 1; iz = (dz<0)? -1 : 1; if( dx>dy ) { zrate = dz/dx; dz -= dx*zrate; crate = dc/dx; dc -= dx*crate; err = zerr = cerr = -(dx>>1); col = col1; if( dz<0 ) { dz = -dz; dc = -dc; } if( col1 != col2 ) { mid = (x1+x2)>>1; while( x1!=mid ) XVectStep; col = col2; } while( x1!=x2 ) XVectStep; } else { zrate = dz/dy; dz -= dy*zrate; crate = dc/dy; dc -= dy*crate; err = zerr = cerr = -(dy>>1); col = col1; if( dz<0 ) { dz = -dz; dc = -dc; } if( col1 != col2 ) { mid = (y1+y2)>>1; while( y1!=mid ) YVectStep; col=col2; } while( y1!=y2 ) YVectStep; } } static void ClipVector(x1,y1,z1,x2,y2,z2,col) int x1,y1,z1,x2,y2,z2,col; { register int code1,code2; register int delta,rest; register int temp; code1 = OutCode(x1,y1,z1); code2 = OutCode(x2,y2,z2); while( True ) { if( Accept(code1,code2) ) break; if( Reject(code1,code2) ) return; if( !code1 ) { code1 = code2; code2 = 0; temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; temp=z1; z1=z2; z2=temp; } if( code1 & BitAbove ) { delta = y2-y1; x1 += (int)(((Long)y1*(x1-x2))/delta); z1 += (int)(((Long)y1*(z1-z2))/delta); y1 = 0; } else if( code1 & BitLeft ) { delta = x2-x1; y1 += (int)(((Long)x1*(y1-y2))/delta); z1 += (int)(((Long)x1*(z1-z2))/delta); x1 = 0; } else if( code1 & BitRight ) { delta = x2-x1; temp=XRange-1; rest=temp-x1; y1 += (int)(((Long)rest*(y2-y1))/delta); z1 += (int)(((Long)rest*(z2-z1))/delta); x1 = temp; } else if( code1 & BitBelow ) { delta = y2-y1; temp=YRange-1; rest=temp-y1; x1 += (int)(((Long)rest*(x2-x1))/delta); z1 += (int)(((Long)rest*(z2-z1))/delta); y1 = temp; } else /* SLAB */ { delta = z2-z1; rest = (SlabValue-1)-z1; x1 += (int)(((Long)rest*(x2-x1))/delta); y1 += (int)(((Long)rest*(y2-y1))/delta); z1 = SlabValue-1; } code1 = OutCode(x1,y1,z1); } DrawTwinVector(x1,y1,z1,x2,y2,z2,col,col); } void ClipTwinVector(x1,y1,z1,x2,y2,z2,col1,col2) int x1,y1,z1,x2,y2,z2,col1,col2; { register int xmid,ymid,zmid; register int code1,code2; if( col1!=col2 ) { code1 = OutCode(x1,y1,z1); code2 = OutCode(x2,y2,z2); if( !Reject(code1,code2) ) { if( !Accept(code1,code2) ) { xmid = (x1+x2)/2; ymid = (y1+y2)/2; zmid = (z1+z2)/2; ClipVector(x1,y1,z1,xmid,ymid,zmid,col1); ClipVector(xmid,ymid,zmid,x2,y2,z2,col2); } else DrawTwinVector(x1,y1,z1,x2,y2,z2,col1,col2); } } else ClipVector(x1,y1,z1,x2,y2,z2,col1); } void ClipDashVector(x1,y1,z1,x2,y2,z2,col1,col2) int x1,y1,z1,x2,y2,z2,col1,col2; { register Long offset; register Pixel __huge *fptr; register short __huge *dptr; register int ix,iy,iz,ic; register int dx,dy,dz,dc; register int crate, cerr; register int zrate, zerr; register int ystep,err; register int col, mid; register int c1, c2; if( (x1==x2) && (y1==y2) ) return; if( Reject(OutCode(x1,y1,z1),OutCode(x2,y2,z2)) ) return; c1 = (ColourDepth*(z1+ImageRadius-ZOffset))/ImageSize; c2 = (ColourDepth*(z2+ImageRadius-ZOffset))/ImageSize; dz = (z2 - z1)<<1; dc = (c2 - c1)<<1; dx = x2 - x1; dy = y2 - y1; offset = (Long)y1*XRange + x1; fptr = FBuffer+offset; dptr = DBuffer+offset; ystep = XRange; ix = iy = iz = ic = 1; if( dy<0 ) { dy = -dy; iy = -1; ystep = -ystep; } if( dx<0 ) { dx = -dx; ix = -1; } if( dz<0 ) { dz = -dz; iz = -1; } if( dc<0 ) { dc = -dc; ic = -1; } if( dx>dy ) { if( x2>1); mid = (x1+x2)/2; while( x1!=x2 ) { if( XValid(x1) && YValid(y1) && ZValid(z1) ) { col = (x10 ) if( (err-=dx)>0 ) { err-=dx; fptr+=ystep+ystep; dptr+=ystep+ystep; y1+=iy+iy; } else { fptr+=ystep; dptr+=ystep; y1+=iy; } if( (zerr+=dz)>0 ) if( (zerr-=dx)>0 ) { zerr -= dx; z1 += iz+iz; } else z1 += iz; if( (cerr+=dc)>0 ) if( (cerr-=dx)>0 ) { cerr -= dx; c1 += ic+ic; } else c1 += ic; fptr+=ix+ix; dptr+=ix+ix; x1+=ix+ix; z1 += zrate; c1 += crate; } } else { if( y1>y2 ) { mid = col1; col1 = col2; col2 = mid; } zrate = dz/dy; dz -= dy*zrate; crate = dc/dy; dc -= dy*crate; err = zerr = cerr = -(dy>>1); mid = (y1+y2)/2; while( y1!=y2 ) { if( XValid(x1) && YValid(y1) && ZValid(z1) ) { col = (y10 ) if( (err-=dy)>0 ) { err-=dy; fptr+=ix+ix; dptr+=ix+ix; x1+=ix+ix; } else { fptr+=ix; dptr+=ix; x1+=ix; } if( (zerr+=dz)>0 ) if( (zerr-=dy)>0 ) { zerr -= dy; z1 += iz+iz; } else z1 += iz; if( (cerr+=dc)>0 ) if( (cerr-=dy)>0 ) { cerr -= dy; c1 += ic+ic; } else c1 += ic; fptr+=ystep+ystep; dptr+=ystep+ystep; y1+=iy+iy; z1 += zrate; c1 += crate; } } } /* SplineCount is either 1, 2, 3, 4, 5 or 9! */ void StrandRibbon( src, dst, col1, col2 ) Knot __far *src, __far *dst; int col1, col2; { register int hsx, hsy, hsz; register int hdx, hdy, hdz; register int qsx, qsy, qsz; register int qdx, qdy, qdz; register int col; if( SplineCount != 4 ) { if( SplineCount == 1 ) { ClipVector( src->px, src->py, src->pz, dst->px, dst->py, dst->pz, col2 ); return; } else if( SplineCount != 2 ) ClipVector( src->px, src->py, src->pz, dst->px, dst->py, dst->pz, col1 ); ClipVector( src->px+src->wx, src->py+src->wy, src->pz+src->wz, dst->px+dst->wx, dst->py+dst->wy, dst->pz+dst->wz, col2 ); ClipVector( src->px-src->wx, src->py-src->wy, src->pz-src->wz, dst->px-dst->wx, dst->py-dst->wy, dst->pz-dst->wz, col2 ); if( SplineCount<=3 ) return; hsx = src->wx/2; hsy = src->wy/2; hsz = src->wz/2; hdx = dst->wx/2; hdy = dst->wy/2; hdz = dst->wz/2; ClipVector( src->px+hsx, src->py+hsy, src->pz+hsz, dst->px+hdx, dst->py+hdy, dst->pz+hdz, col1 ); ClipVector( src->px-hsx, src->py-hsy, src->pz-hsz, dst->px-hdx, dst->py-hdy, dst->pz-hdz, col1 ); if( SplineCount==5 ) return; col = col1; } else /* SplineCount == 4 */ { hsx = src->wx/2; hsy = src->wy/2; hsz = src->wz/2; hdx = dst->wx/2; hdy = dst->wy/2; hdz = dst->wz/2; col = col2; } qsx = hsx/2; qsy = hsy/2; qsz = hsz/2; qdx = hdx/2; qdy = hdy/2; qdz = hdz/2; ClipVector( src->px+hsx+qsx, src->py+hsy+qsy, src->pz+hsz+qsz, dst->px+hdx+qdx, dst->py+hdy+qdy, dst->pz+hdz+qdz, col ); ClipVector( src->px+hsx-qsx, src->py+hsy-qsy, src->pz+hsz-qsz, dst->px+hdx-qdx, dst->py+hdy-qdy, dst->pz+hdz-qdz, col1 ); ClipVector( src->px-hsx+qsx, src->py-hsy+qsy, src->pz-hsz+qsz, dst->px-hdx+qdx, dst->py-hdy+qdy, dst->pz-hdz+qdz, col1 ); ClipVector( src->px-hsx-qsx, src->py-hsy-qsy, src->pz-hsz-qsz, dst->px-hdx-qdx, dst->py-hdy-qdy, dst->pz-hdz-qdz, col ); } #ifndef PIXUTILS /* Unused Function */ static void OutLinePolygon( p ) Poly *p; { register int i; for( i=0; icount-1; i++ ) ClipLine( p->v[i].x, p->v[i].y, p->v[i].z, p->v[i+1].x, p->v[i+1].y, p->v[i+1].z, p->v[i].inten); ClipLine( p->v[i].x, p->v[i].y, p->v[i].z, p->v[0].x, p->v[0].y, p->v[0].z, p->v[i].inten); } #endif static void RenderPolygon( p ) Poly *p; { static Edge lft, rgt; register Edge *pmin, *pmax; register Pixel __huge *fbase; register Pixel __huge *fptr; register short __huge *dbase; register short __huge *dptr; register Long offset; register Real z,inten; register Real dy,dz,di; register int ri,li,ry,ly; register int xmin,xmax; register int ymin; register int top,rem; register int x,y,i; /* Reject Clip Polygon */ if( UseSlabPlane ) for( i=0; icount; i++ ) if( p->v[i].z >= SlabValue ) return; /* Find top vertex */ top = 0; ymin = p->v[0].y; for( i=1; icount; i++ ) if( p->v[i].y < ymin ) { ymin = p->v[i].y; top = i; } rem = p->count; ly = ry = y = ymin; li = ri = top; if( y<0 ) { rem--; while( ly<=0 && rem ) { i = li-1; if( i<0 ) i=p->count-1; if( p->v[i].y > 0 ) { dy = 1.0/(p->v[i].y - ly); lft.di = dy*(p->v[i].inten - p->v[li].inten); lft.dx = dy*(p->v[i].x - p->v[li].x); lft.dz = dy*(p->v[i].z - p->v[li].z); lft.i = p->v[li].inten - ly*lft.di; lft.x = p->v[li].x - ly*lft.dx; lft.z = p->v[li].z - ly*lft.dz; } else rem--; ly = p->v[i].y; li = i; } while( ry<=0 && rem ) { i = ri+1; if( i>=p->count ) i = 0; if( p->v[i].y > 0 ) { dy = 1.0/(p->v[i].y - ry); rgt.di = dy*(p->v[i].inten - p->v[ri].inten); rgt.dx = dy*(p->v[i].x - p->v[ri].x); rgt.dz = dy*(p->v[i].z - p->v[ri].z); rgt.i = p->v[ri].inten - ry*rgt.di; rgt.x = p->v[ri].x - ry*rgt.dx; rgt.z = p->v[ri].z - ry*rgt.dz; } else rem--; ry = p->v[i].y; ri = i; } fbase = FBuffer; dbase = DBuffer; y = 0; } else /* y >= 0 */ { offset = (Long)y*XRange; fbase = FBuffer+offset; dbase = DBuffer+offset; } while( rem ) { while( ly<=y && rem ) { i = li-1; if( i<0 ) i=p->count-1; if( p->v[i].y > y ) { dy = 1.0/(p->v[i].y - ly); lft.di = dy*(p->v[i].inten - p->v[li].inten); lft.dx = dy*(p->v[i].x - p->v[li].x); lft.dz = dy*(p->v[i].z - p->v[li].z); lft.i = p->v[li].inten; lft.x = p->v[li].x; lft.z = p->v[li].z; } ly = p->v[i].y; rem--; li = i; } while( ry<=y && rem ) { i = ri+1; if( i>=p->count ) i = 0; if( p->v[i].y > y ) { dy = 1.0/(p->v[i].y - ry); rgt.di = dy*(p->v[i].inten - p->v[ri].inten); rgt.dx = dy*(p->v[i].x - p->v[ri].x); rgt.dz = dy*(p->v[i].z - p->v[ri].z); rgt.i = p->v[ri].inten; rgt.x = p->v[ri].x; rgt.z = p->v[ri].z; } ry = p->v[i].y; rem--; ri = i; } ymin = MinFun(ly,ry); if( ymin>YRange ) { ymin = YRange; rem = 0; } while( yx)+1; xmin = (int)(pmin->x); if( (xmin=0) ) { di = (pmax->i-pmin->i)/(xmax-xmin); dz = (pmax->z-pmin->z)/(xmax-xmin); if( xmin<0 ) { inten = pmin->i - xmin*di; z = pmin->z - xmin*dz; xmin = 0; } else /* xmin >= 0 */ { inten = pmin->i; z = pmin->z; } if( xmax>=XRange ) xmax = XRange; fptr = fbase+xmin; dptr = dbase+xmin; for( x=xmin; x *dptr ) { *fptr = Lut[(int)inten]; *dptr = (int)z; } inten += di; z += dz; fptr++; dptr++; } } lft.x += lft.dx; rgt.x += rgt.dx; lft.z += lft.dz; rgt.z += rgt.dz; lft.i += lft.di; rgt.i += rgt.di; dbase += XRange; fbase += XRange; y++; } } } void SolidRibbon( src, dst, col ) Knot __far *src, __far *dst; int col; { static Poly p; p.v[0].x = src->px+src->wx; p.v[0].y = src->py+src->wy; p.v[0].z = src->pz+src->wz; p.v[0].inten = src->inten+col; p.v[1].x = dst->px+dst->wx; p.v[1].y = dst->py+dst->wy; p.v[1].z = dst->pz+dst->wz; p.v[1].inten = dst->inten+col; p.v[2].x = dst->px-dst->wx; p.v[2].y = dst->py-dst->wy; p.v[2].z = dst->pz-dst->wz; p.v[2].inten = dst->inten+col; p.v[3].x = src->px-src->wx; p.v[3].y = src->py-src->wy; p.v[3].z = src->pz-src->wz; p.v[3].inten = src->inten+col; p.count = 4; /* OutLinePolygon( &p ); */ RenderPolygon( &p ); } static int TestSphere( x, y, z, rad ) register int x, y, z, rad; { register int temp; ClipStatus = 0; if( UseSlabPlane ) { if( z-rad>=SlabValue ) return( False ); if( z+rad>=SlabValue ) { if( SlabMode ) { ClipStatus |= BitFront; } else return( False ); } else if( SlabMode==SlabSection ) return( False ); } temp = y-rad; if( temp>=YRange ) return( False ); if( temp<0 ) ClipStatus |= BitAbove; temp = y+rad; if( temp<0 ) return( False ); if( temp>=YRange ) ClipStatus |= BitBelow; temp = x+rad; if( temp<0 ) return( False ); if( temp>=XRange ) ClipStatus |= BitRight; temp = x-rad; if( temp>=XRange ) return( False ); if( temp<0 ) ClipStatus |= BitLeft; return True; } #ifdef INVERT #define CalcInten(dz) inten = (dz)+(dz)+dx+dy #else #define CalcInten(dz) inten = (dz)+(dz)+dx-dy #endif #define UpdateAcross(dz) \ depth = (dz)+z; \ if( depth > *dptr ) \ { *dptr = depth; \ fptr = fold+dx; \ CalcInten((dz)); \ if( inten>0 ) \ { inten = (int)((inten*ColConst[rad])>>ColBits); \ *fptr = Lut[col+inten]; \ } else *fptr = Lut[col]; \ } \ dptr++; dx++; #define UpdateLine \ dx = -wide; \ dptr = dold-wide; \ tptr = LookUp[wide]+wide; \ while( dx<0 ) { UpdateAcross(*tptr); tptr--; } \ do { UpdateAcross(*tptr); tptr++; } while(dx<=wide); \ dold += XRange; fold += XRange; \ dy++; void DrawSphere(x,y,z,rad,col) int x,y,z,rad,col; { register Pixel __huge *fptr, __huge *fold; register short __huge *dptr, __huge *dold; register Byte __far *tptr; register Long offset; register int depth,wide,inten; register int dx,dy; offset = (Long)(y-rad)*XRange + x; fold=FBuffer+offset; dold=DBuffer+offset; dy = -rad; while( dy<0 ) { wide = LookUp[rad][-dy]; UpdateLine; } do { wide = LookUp[rad][dy]; UpdateLine; } while( dy<=rad ); } void ClipSphere(x,y,z,rad,col) int x,y,z,rad,col; { register Pixel __huge *fptr, __huge *fold; register short __huge *dptr, __huge *dold; register int lastx,lasty,dx,dy,dz; register int depth,wide,inten,side; register int crad,cwide,temp; register Long offset; /* Visibility Tests */ if( !TestSphere(x,y,z,rad) ) return; if( !ClipStatus ) { DrawSphere(x,y,z,rad,col); return; } if( ClipStatus&BitAbove ) { dy = -y; fold = FBuffer + x; dold = DBuffer + x; } else { dy = -rad; offset = (Long)(y+dy)*XRange+x; fold = FBuffer + offset; dold = DBuffer + offset; } if( ClipStatus&BitBelow ) { lasty = (YRange-1)-y; } else lasty = rad; side = (XRange-1)-x; /* No Slab Plane Clipping */ if( !(ClipStatus&BitFront) ) { while( dy<=lasty ) { wide = LookUp[rad][AbsFun(dy)]; lastx = MinFun(wide,side); dx = - MinFun(wide,x); dptr = dold + dx; while( dx<=lastx ) { dz = LookUp[wide][AbsFun(dx)]; UpdateAcross(dz); } dold += XRange; fold += XRange; dy++; } return; } dz = SlabValue-z; crad = LookUp[rad][AbsFun(dz)]; if( (z>SlabValue) || (SlabMode==SlabSection) ) { if( craddy ) { dy = -crad; offset = (Long)(y+dy)*XRange+x; fold = FBuffer + offset; dold = DBuffer + offset; } } while( dy<=lasty ) { temp = AbsFun(dy); wide = LookUp[rad][temp]; lastx = MinFun(wide,side); dx = - MinFun(x,wide); dptr = dold + dx; if( temp<=crad ) { cwide = LookUp[crad][temp]; while( dx<=lastx ) { temp = AbsFun(dx); if( temp<=cwide ) { /* Slab Plane Clipping Modes */ switch( SlabMode ) { case( SlabFinal ): fold[dx] = Lut[col+SlabInten]; *dptr = SliceValue; break; case( SlabHollow ): dz = LookUp[wide][temp]; depth = z - dz; if( depth>*dptr ) { *dptr = depth; #ifdef INVERT inten = dz+dz-dx-dy; #else inten = dz+dz-dx+dy; #endif if( inten>0 ) { inten=(int)( (inten*ColConst[rad]) >>(ColBits+1)); fold[dx] = Lut[col+inten]; } else fold[dx] = Lut[col]; } break; case( SlabSection ): case( SlabClose ): dz = SlabValue-z; depth = dx*dx+dy*dy+dz*dz+SliceValue; if( (*dptroffset; depth = ptr->dz+z; SETPIXEL(dptr,fbase+ptr->offset,depth,Lut[ptr->inten+c]); } } static void DrawArcDn(dbase,fbase,z,c) register short __huge *dbase; register Pixel __huge *fbase; register int z,c; { register ArcEntry __far *ptr; register short __huge *dptr; register short depth; for( ptr=ArcDn; ptroffset; depth = ptr->dz+z; SETPIXEL(dptr,fbase+ptr->offset,depth,Lut[ptr->inten+c]); } } static void DrawCylinderCaps( x1,y1,z1,c1,x2,y2,z2,c2,rad ) int x1,y1,z1,c1, x2,y2,z2,c2, rad; { register short __huge *dold, __huge *dptr; register Pixel __huge *fold; register Long offset,temp,end; register int inten,zrate,absx; register int wide,depth; register int ix,iy,ax,ay; register int lx,ly,lz; register int dx,dy,dz; lx = x2-x1; ly = y2-y1; lz = z2-z1; if( ly>0 ) { ay = ly; iy = 1; } else { ay = -ly; iy = -1; } if( lx>0 ) { ax = lx; ix = 1; } else { ax = -lx; ix = -1; } zrate = lz/MaxFun(ax,ay); end = (Long)ly*XRange+lx; temp = (Long)y1*XRange+x1; fold = FBuffer+temp; dold = DBuffer+temp; ArcAcPtr = ArcAc; ArcDnPtr = ArcDn; temp = (Long)-(rad*XRange); for( dy= -rad; dy<=rad; dy++ ) { wide = LookUp[rad][AbsFun(dy)]; for( dx= -wide; dx<=wide; dx++ ) { absx = AbsFun(dx); dz = LookUp[wide][absx]; CalcInten(dz); if( inten>0 ) { inten = (int)((inten*ColConst[rad])>>ColBits); } else inten = 0; offset = temp+dx; if( XValid(x1+dx) && YValid(y1+dy) ) { dptr = dold+offset; depth = z1+dz; SETPIXEL(dptr,fold+offset,depth,Lut[c1+inten]); } if( XValid(x2+dx) && YValid(y2+dy) ) { dptr = dold+(offset+end); depth = z2+dz; SETPIXEL(dptr,fold+(offset+end),depth,Lut[c2+inten]); } #ifndef PIXUTILS k1 = AbsFun(dx+ix); k2 = AbsFun(dx-ix); if( ((k1>wide)||(dz>=LookUp[wide][k1]-zrate)) && ((k2>wide)||(dz>LookUp[wide][k2]+zrate)) ) #endif { ArcAcPtr->offset = offset; ArcAcPtr->inten = inten; ArcAcPtr->dx=dx; ArcAcPtr->dy=dy; ArcAcPtr->dz=dz; ArcAcPtr++; } #ifndef PIXUTILS k1 = AbsFun(dy+iy); k2 = AbsFun(dy-iy); high = LookUp[rad][absx]; if( ((k1>high)||(dz>=LookUp[LookUp[rad][k1]][absx]-zrate)) && ((k2>high)||(dz>LookUp[LookUp[rad][k2]][absx]+zrate)) ) #endif { ArcDnPtr->offset = offset; ArcDnPtr->inten = inten; ArcDnPtr->dx=dx; ArcDnPtr->dy=dy; ArcDnPtr->dz=dz; ArcDnPtr++; } } temp += XRange; } } void DrawCylinder( x1,y1,z1,c1,x2,y2,z2,c2,rad ) int x1,y1,z1,c1, x2,y2,z2,c2, rad; { register short __huge *dbase; register Pixel __huge *fbase; register int zrate,zerr,ystep,err; register int ix,iy,ax,ay; register int lx,ly,lz; register int mid,tmp; register Long temp; /* Trivial Case */ if( (x1==x2) && (y1==y2) ) { if( z1>z2 ) { DrawSphere(x1,y1,z1,rad,c1); } else DrawSphere(x2,y2,z2,rad,c2); return; } if( z10 ) { ystep = XRange; ay = ly; iy = 1; } else { ystep = -XRange; ay = -ly; iy = -1; } if( lx>0 ) { ax = lx; ix = 1; } else { ax = -lx; ix = -1; } zrate = lz/MaxFun(ax,ay); temp = (Long)y1*XRange+x1; fbase = FBuffer+temp; dbase = DBuffer+temp; if( ax>ay ) { lz -= ax*zrate; zerr = err = -(ax>>1); if( c1 != c2 ) { mid = (x1+x2)>>1; while( x1!=mid ) { z1 += zrate; if( (zerr-=lz)>0 ) { zerr-=ax; z1--; } fbase+=ix; dbase+=ix; x1+=ix; if( (err+=ay)>0 ) { fbase+=ystep; dbase+=ystep; err-=ax; DrawArcDn(dbase,fbase,z1,c1); } else DrawArcAc(dbase,fbase,z1,c1); } } while( x1!=x2 ) { z1 += zrate; if( (zerr-=lz)>0 ) { zerr-=ax; z1--; } fbase+=ix; dbase+=ix; x1+=ix; if( (err+=ay)>0 ) { fbase+=ystep; dbase+=ystep; err-=ax; DrawArcDn(dbase,fbase,z1,c2); } else DrawArcAc(dbase,fbase,z1,c2); } } else /*ay>=ax*/ { lz -= ay*zrate; zerr = err = -(ay>>1); if( c1 != c2 ) { mid = (y1+y2)>>1; while( y1!=mid ) { z1 += zrate; if( (zerr-=lz)>0 ) { zerr-=ay; z1--; } fbase+=ystep; dbase+=ystep; y1+=iy; if( (err+=ax)>0 ) { fbase+=ix; dbase+=ix; err-=ay; DrawArcAc(dbase,fbase,z1,c1); } else DrawArcDn(dbase,fbase,z1,c1); } } while( y1!=y2 ) { z1 += zrate; if( (zerr-=lz)>0 ) { zerr-=ay; z1--; } fbase+=ystep; dbase+=ystep; y1+=iy; if( (err+=ax)>0 ) { fbase+=ix; dbase+=ix; err-=ay; DrawArcAc(dbase,fbase,z1,c2); } else DrawArcDn(dbase,fbase,z1,c2); } } } static int TestCylinder( x1,y1,z1,x2,y2,z2,rad ) int x1,y1,z1,x2,y2,z2,rad; { register int tmp1, tmp2; if( UseSlabPlane ) if( (z1+rad>SlabValue) || (z2+rad>SlabValue) ) return(False); ClipStatus = False; tmp1 = x1+rad; tmp2 = x2+rad; if( (tmp1<0) && (tmp2<0) ) return( False ); if( (tmp1>=XRange) || (tmp2>=XRange) ) ClipStatus = True; tmp1 = x1-rad; tmp2 = x2-rad; if( (tmp1>=XRange) && (tmp2>=XRange) ) return( False ); if( (tmp1<0) || (tmp2<0) ) ClipStatus = True; tmp1 = y1+rad; tmp2 = y2+rad; if( (tmp1<0) && (tmp2<0) ) return( False ); if( (tmp1>=YRange) || (tmp2>=YRange) ) ClipStatus = True; tmp1 = y1-rad; tmp2 = y2-rad; if( (tmp1>=YRange) && (tmp2>=YRange) ) return( False ); if( (tmp1<0) || (tmp2<0) ) ClipStatus = True; return( True ); } static void ClipArcAc(dbase,fbase,x,y,z,c) register short __huge *dbase; register Pixel __huge *fbase; register int x,y,z,c; { register ArcEntry __far *ptr; register short __huge *dptr; register short depth; register int temp; ptr = ArcAc; while( (temp=y+ptr->dy) < 0 ) if( ++ptr == ArcAcPtr ) return; while( (tempdx; if( XValid(temp) ) { dptr = dbase+ptr->offset; depth = ptr->dz+z; SETPIXEL(dptr,fbase+ptr->offset,depth,Lut[ptr->inten+c]); } ptr++; temp = y+ptr->dy; } } static void ClipArcDn(dbase,fbase,x,y,z,c) register short __huge *dbase; register Pixel __huge *fbase; register int x,y,z,c; { register ArcEntry __far *ptr; register short __huge *dptr; register short depth; register int temp; ptr = ArcDn; while( (temp=y+ptr->dy) < 0 ) if( ++ptr == ArcDnPtr ) return; while( (tempdx; if( XValid(temp) ) { dptr = dbase+ptr->offset; depth = ptr->dz+z; SETPIXEL(dptr,fbase+ptr->offset,depth,Lut[ptr->inten+c]); } ptr++; temp = y+ptr->dy; } } void ClipCylinder( x1,y1,z1,c1,x2,y2,z2,c2,rad ) int x1,y1,z1,c1, x2,y2,z2,c2, rad; { register short __huge *dbase; register Pixel __huge *fbase; register int zrate,zerr,ystep,err; register int ix,iy,ax,ay; register int lx,ly,lz; register int mid,tmp; register Long temp; /* Visibility Tests */ if( !TestCylinder(x1,y1,z1,x2,y2,z2,rad) ) return; if( !ClipStatus ) { DrawCylinder(x1,y1,z1,c1,x2,y2,z2,c2,rad); return; } /* Trivial Case */ if( (x1==x2) && (y1==y2) ) { if( z1>z2 ) { ClipSphere(x1,y1,z1,rad,c1); } else ClipSphere(x2,y2,z2,rad,c2); return; } if( z10 ) { ystep = XRange; ay = ly; iy = 1; } else { ystep = -XRange; ay = -ly; iy = -1; } if( lx>0 ) { ax = lx; ix = 1; } else { ax = -lx; ix = -1; } zrate = lz/MaxFun(ax,ay); temp = (Long)y1*XRange+x1; fbase = FBuffer+temp; dbase = DBuffer+temp; if( ax>ay ) { if( x2>1); mid = (x1+x2)/2; while( x1!=x2 ) { z1 += zrate; if( (zerr-=lz)>0 ) { zerr-=ax; z1--; } fbase+=ix; dbase+=ix; x1+=ix; if( (err+=ay)>0 ) { fbase += ystep; err -= ax; dbase += ystep; y1 += iy; ClipArcDn(dbase,fbase,x1,y1,z1,(x1=ax*/ { if( y2>1); mid = (y1+y2)/2; while( y1!=y2 ) { z1 += zrate; if( (zerr-=lz)>0 ) { zerr-=ay; z1--; } fbase+=ystep; dbase+=ystep; y1+=iy; if( (err+=ax)>0 ) { fbase += ix; err -= ay; dbase += ix; x1 += ix; ClipArcAc(dbase,fbase,x1,y1,z1,(y1>4; count += size; } FontSize = size; } void DisplayString( x, y, z, label, col ) int x, y, z; char *label; int col; { register int sx,sy; register int ex,ey; register char *ptr; register int high; high = (FontSize*3)>>1; #ifdef INVERT if( ((y+high)<0) || (y>=YRange) ) return; #else if( (y<0) || ((y-high)>=YRange) ) return; #endif while( (x<=-FontSize) && *label ) { x += FontSize; label++; } while( *label && (x