
#help_index "Graphics/Math"
I8 GrXOffsets[8]={-1,0,1,-1,1,-1,0,1},
GrYOffsets[8]={-1,-1,-1,0,0,1,1,1};
public void Line(void *aux_data,
I8 x1,I8 y1,I8 z1,
I8 x2,I8 y2,I8 z2,
void plot_cb(void *aux,I8 x,I8 y,I8 z),
I8 step=1,I8 start=0)
{
I8 i,j,d,dx=x2-x1,dy=y2-y1,dz=z2-z1,_x,_y,_z;
I8 adx=AbsI8(dx),ady=AbsI8(dy),adz=AbsI8(dz);
BoolI1 first=TRUE;
if (adx>=ady) {
if (adx>=adz) {
if (d=adx) {
if (dx>=0)
dx=0x100000000;
else
dx=-0x100000000;
dy=dy<<32/d;
dz=dz<<32/d;
}
} else {
if (d=adz) {
dx=dx<<32/d;
dy=dy<<32/d;
if (dz>=0)
dz=0x100000000;
else
dz=-0x100000000;
}
}
} else {
if (ady>=adz) {
if (d=ady) {
dx=dx<<32/d;
if (dy>=0)
dy=0x100000000;
else
dy=-0x100000000;
dz=dz<<32/d;
}
} else {
if (d=adz) {
dx=dx<<32/d;
dy=dy<<32/d;
if (dz>=0)
dz=0x100000000;
else
dz=-0x100000000;
}
}
}
x1<<=32; y1<<=32; z1<<=32;
for (j=0;j<start;j++) {
x1+=dx; y1+=dy; z1+=dz;
}
if (step!=1 && step!=0) {
dx*=step;
dy*=step;
dz*=step;
d/=step;
}
for (i=start;i<=d;i++) {
if (_x!=x1.i4[1] || _y!=y1.i4[1] || _z!=z1.i4[1] || first)
plot_cb(aux_data,x1.i4[1],y1.i4[1],z1.i4[1]);
first=FALSE;
_x=x1.i4[1]; _y=y1.i4[1]; _z=z1.i4[1];
x1+=dx; y1+=dy; z1+=dz;
}
if (step==1 && (_x!=x2||_y!=y2||_z!=z2))
plot_cb(aux_data,x2,y2,z2);
}
public void Box(void *aux_data,
I8 x1,I8 y1,I8 z1,
I8 x2,I8 y2,I8 z2,
I8 x3,I8 y3,I8 z3,
void plot_cb(void *aux,I8 x,I8 y,I8 z))
{
I8 i,j,
d1,dx1=x2-x1,dy1=y2-y1,dz1=z2-z1,
d2,dx2=x3-x1,dy2=y3-y1,dz2=z3-z1,
adx1=AbsI8(dx1),ady1=AbsI8(dy1),adz1=AbsI8(dz1),
adx2=AbsI8(dx2),ady2=AbsI8(dy2),adz2=AbsI8(dz2),
last_x,last_y,last_z;
BoolI1 first=TRUE;
if (adx1>=ady1)
d1=adx1>=adz1 ? adx1:adz1;
else
d1=ady1>=adz1 ? ady1:adz1;
if (adx2>=ady2)
d2=adx2>=adz2 ? adx2:adz2;
else
d2=ady2>=adz2 ? ady2:adz2;
d1<<=1;
d2<<=1;
if (d1) {
dx1=dx1<<32/d1;
dy1=dy1<<32/d1;
dz1=dz1<<32/d1;
}
if (d2) {
dx2=dx2<<32/d2;
dy2=dy2<<32/d2;
dz2=dz2<<32/d2;
}
x1<<=32; y1<<=32; z1<<=32;
for (j=0;j<=d1;j++) {
x2=x1; y2=y1; z2=z1;
for (i=0;i<=d2;i++) {
if (x2.i4[1]!=last_x || y2.i4[1]!=last_y || z2.i4[1]!=last_z ||first)
plot_cb(aux_data,x2.i4[1],y2.i4[1],z2.i4[1]);
first=FALSE;
last_x=x2.i4[1]; last_y=y2.i4[1]; last_z=z2.i4[1];
x2+=dx2; y2+=dy2; z2+=dz2;
}
x1+=dx1; y1+=dy1; z1+=dz1;
}
}
#help_index "Graphics/Math/3D Transformation"
#help_file "::/LT/Doc/Transform.TXZ"
I8 gr_scale;
gr_scale.u4[0]=0;
gr_scale.i4[1]=1;
public void GrRotate(I8 *r,I8 *x,I8 *y,I8 *z)
{
I8 x1,y1,z1,xx=*x,yy=*y,zz=*z;
x1=(r[0]*xx+r[1]*yy+r[2]*zz+r[3])>>32;
y1=(r[4]*xx+r[5]*yy+r[6]*zz+r[7])>>32;
z1=(r[8]*xx+r[9]*yy+r[10]*zz+r[11])>>32;
*x=x1;*y=y1;*z=z1;
}
public void GrTransform(GrBitMap *base,I8 *x,I8 *y,I8 *z)
{
GrRotate(base->r,x,y,z);
*x+=base->x;
*y+=base->y;
*z+=base->z;
}
public I8 *GrRotX(double phi,TssStruct *tss=NULL)
{
double my_cos,my_sin;
I8 *r=MAllocZ(sizeof(I8)*16,tss);
my_cos=Cos(phi)*gr_scale;
my_sin=Sin(phi)*gr_scale;
r[5]=my_cos;
r[10]=my_cos;
r[9]=my_sin;
r[6]=-my_sin;
r[0]=gr_scale;
r[15]=gr_scale;
return r;
}
public I8 *GrRotY(double zeta,TssStruct *tss=NULL)
{
double my_cos,my_sin;
I8 *r=MAllocZ(sizeof(I8)*16,tss);
my_cos=Cos(zeta)*gr_scale;
my_sin=Sin(zeta)*gr_scale;
r[0]=my_cos;
r[10]=my_cos;
r[8]=-my_sin;
r[2]=my_sin;
r[5]=gr_scale;
r[15]=gr_scale;
return r;
}
public I8 *GrRotZ(double theta,TssStruct *tss=NULL)
{
double my_cos,my_sin;
I8 *r=MAllocZ(sizeof(I8)*16,tss);
my_cos=Cos(theta)*gr_scale;
my_sin=Sin(theta)*gr_scale;
r[0]=my_cos;
r[5]=my_cos;
r[4]=my_sin;
r[1]=-my_sin;
r[10]=gr_scale;
r[15]=gr_scale;
return r;
}
public I8 *GrScaleMat(I8 *m1,double s,TssStruct *tss=NULL)
{
I8 i,*r=MAllocZ(sizeof(I8)*16,tss);
for (i=0;i<16;i++)
r[i]=m1[i]*s;
return r;
}
public I8 *GrMulMat(I8 *m1,I8 *m2,TssStruct *tss=NULL)
{
I8 *r=MAllocZ(sizeof(I8)*16,tss);
I8 i,j,k;
double d;
for (i=0;i<4;i++) {
for (j=0;j<4;j++) {
for (k=0;k<4;k++) {
d=m1[k+4*j];
d*=m2[i+4*k];
d/=gr_scale;
r[i+4*j]+=d;
}
}
}
return r;
}
public I8 GrDetMat(I8 *m1)
{ //determinant
I8 i;
double m[16],d;
for (i=0;i<16;i++)
m[i]=m1[i]/ToDouble(0x100000000);
d=m[0]*(m[5]*m[10]-m[6]*m[9])-
m[1]*(m[4]*m[10]-m[6]*m[8])+
m[2]*(m[4]*m[9]-m[5]*m[8]);
return d*0x100000000;
}
public void GrScalePenWidth(GrBitMap *base)
{
I8 d;
if (base->flags&BMF_TRANSFORMATION) {
if (base->pen_width) {
d=base->pen_width*GrDetMat(base->r)+0x80000000;
base->pen_width=d.u4[1];
if (base->pen_width<1)
base->pen_width=1;
}
}
}
public void GrIdent(TssStruct *tss=NULL)
{
I8 *r=MAllocZ(sizeof(I8)*16,tss);
r[0].i4[1]=1;
r[5].i4[1]=1;
r[10].i4[1]=1;
r[15].i4[1]=1;
}
public void GrSetIdent(I8 *r)
{
MemSet(r,0,16*sizeof(I8));
r[0].i4[1]=1;
r[5].i4[1]=1;
r[10].i4[1]=1;
r[15].i4[1]=1;
}
public void GrSetTranslation(I8 *r,I8 x,I8 y,I8 z)
{
r[3]=x<<32;
r[7]=y<<32;
r[11]=z<<32;
r[15]=gr_scale;
}
public BoolI8 GrSetSymmetry(GrBitMap *base,I8 x1,I8 y1,I8 x2,I8 y2)
{
double d;
if (y1==y2 && x1==x2)
return FALSE;
base->sym.snx=y2-y1;
base->sym.sny=x1-x2;
base->sym.snz=0;
if (d=Sqrt(SqrI8(base->sym.snx)+
SqrI8(base->sym.sny)+
SqrI8(base->sym.snz))) {
d=gr_scale/d;
base->sym.snx *= d;
base->sym.sny *= d;
base->sym.snz *= d;
}
base->sym.sx=x1;
base->sym.sy=y1;
base->sym.sz=0;
return TRUE;
}
public BoolI8 GrSetSymmetry3(GrBitMap *base,I8 x1,I8 y1,I8 z1,I8 x2,I8 y2,I8 z2,I8 x3,I8 y3,I8 z3)
{
double d,x,y,z,xx,yy,zz;
I8 xx1,yy1,zz1,xx2,yy2,zz2,*r;
xx1=x1-x2; yy1=y1-y2; zz1=z1-z2;
xx2=x3-x2; yy2=y3-y2; zz2=z3-z2;
if (!xx1 && !yy1 && !zz1 ||
!xx2 && !yy2 && !zz2 ||
xx1==xx2 && yy1==yy2 && zz1==zz2)
return FALSE;
x=yy1*zz2-zz1*yy2;
y=-xx1*zz2+zz1*xx2;
z=xx1*yy2-yy1*xx2;
if (base->flags & BMF_TRANSFORMATION) {
r=base->r;
xx=x*r[0]+y*r[1]+z*r[2];
yy=x*r[4]+y*r[5]+z*r[6];
zz=x*r[8]+y*r[9]+z*r[10];
x=xx; y=yy; z=zz;
}
if (d=Sqrt(Sqr(x)+Sqr(y)+Sqr(z))) {
d=gr_scale/d;
base->sym.snx = d*x;
base->sym.sny = d*y;
base->sym.snz = d*z;
}
if (base->flags & BMF_TRANSFORMATION)
GrTransform(base,&x1,&y1,&z1);
base->sym.sx=x1;
base->sym.sy=y1;
base->sym.sz=z1;
return TRUE;
}
public void GrReflect(GrBitMap *base,I8 *_x,I8 *_y,I8 *_z)
{
I8 x=*_x<<32,y=*_y<<32,z=*_z<<32,
xx=*_x-base->sym.sx,yy=*_y-base->sym.sy,zz=*_z-base->sym.sz,
d=(xx*base->sym.snx+yy*base->sym.sny+zz*base->sym.snz)>>16,
xn,yn,zn,xx2,yy2,zz2;
xn=d*base->sym.snx>>15;
yn=d*base->sym.sny>>15;
zn=d*base->sym.snz>>15;
xx=x-xn;
yy=y-yn;
zz=z-zn;
xx2=x+xn;
yy2=y+yn;
zz2=z+zn;
if (SqrI8(xx>>16 -base->sym.sx<<16)+
SqrI8(yy>>16 -base->sym.sy<<16)+
SqrI8(zz>>16 -base->sym.sz<<16)<
SqrI8(xx2>>16-base->sym.sx<<16)+
SqrI8(yy2>>16-base->sym.sy<<16)+
SqrI8(zz2>>16-base->sym.sz<<16)) {
*_x=xx.i4[1]; *_y=yy.i4[1]; *_z=zz.i4[1];
} else {
*_x=xx2.i4[1]; *_y=yy2.i4[1]; *_z=zz2.i4[1];
}
}
#help_index "Graphics/Math"
public void Circle(void *aux_data,
I8 cx,I8 cy,I8 cz,
I8 radius,
void plot_cb(void *aux,I8 x,I8 y,I8 z),
I8 step=1,
double start_radians=0,
double len_radians=2*pi)
{
I8 i,j,len=len_radians*radius;
I8 x,y,x1,y1,s1,s2,c;
double t;
if (radius<=0) return;
t=1.0/radius;
s1=1<<24*Sin(t);
s2=-s1;
c=1<<24*Cos(t);
if (start_radians) {
x=radius*Cos(start_radians);
y=-radius*Sin(start_radians);
} else {
x=radius;
y=0;
}
x<<=8;
y<<=8;
for (i=0;i<=len;i+=step) {
plot_cb(aux_data,cx+x>>8,cy+y>>8,cz);
for (j=0;j<step;j++) {
x1=(c*x+s1*y)>>24;
y1=(s2*x+c*y)>>24;
x=x1; y=y1;
}
}
}
public void Ellipse(void *aux_data,
I8 cx,I8 cy,I8 cz,
I8 x_radius,I8 y_radius,
void plot_cb(void *aux,I8 x,I8 y,I8 z),
double rot_angle=0,
I8 step=1,
double start_radians=0,
double len_radians=2*pi)
{
I8 i,j,len;
I8 x,y,_x,_y,x1,y1,x2,y2, s1,s2,c, s12,s22,c2;
double t;
BoolI1 first=TRUE;
if (x_radius<=0 || y_radius<=0 || step<1)
return;
if (x_radius>=y_radius) {
t=1.0/x_radius;
len=len_radians*x_radius;
} else {
t=1.0/y_radius;
len=len_radians*y_radius;
}
s1=1<<24*Sin(t);
s2=-s1;
c=1<<24*Cos(t);
s12=1<<24*Sin(rot_angle);
s22=-s12;
c2=1<<24*Cos(rot_angle);
if (start_radians) {
x=x_radius*Cos(start_radians);
y=-x_radius*Sin(start_radians);
} else {
x=x_radius;
y=0;
}
x<<=8;
y<<=8;
x2=x;
y2=y;
y1=y2*y_radius/x_radius;
x=(c2*x2+s12*y1)>>24;
y=(s22*x2+c2*y1)>>24;
for (i=0;i<=len;i+=step) {
if (x>>8!=_x || y>>8!=_y || first)
plot_cb(aux_data,cx+x>>8,cy+y>>8,cz);
_x=x>>8; _y=y>>8; first=FALSE;
for (j=0;j<step;j++) {
x1=(c*x2+s1*y2)>>24;
y1=(s2*x2+c*y2)>>24;
x2=x1;
y2=y1;
y1=y1*y_radius/x_radius;
x=(c2*x1+s12*y1)>>24;
y=(s22*x1+c2*y1)>>24;
}
}
}
public void RegPolygon(void *aux_data,
I8 cx,I8 cy,I8 cz,
I8 x_radius,I8 y_radius,I8 sides,
void plot_cb(void *aux,I8 x,I8 y,I8 z),
double rot_angle=0,
I8 step=1,
double start_radians=0,
double len_radians=2*pi)
{
I8 i,n,x,y,x1,y1,x2,y2,
xx1,yy1,xx2,yy2,
s1,s2,c, s12,s22,c2;
double angle_step;
if (sides<=0 || x_radius<=0 || y_radius<=0)
return;
angle_step=2*pi/sides;
n=len_radians/angle_step;
s1=1<<24*Sin(angle_step);
s2=-s1;
c=1<<24*Cos(angle_step);
s12=1<<24*Sin(rot_angle);
s22=-s12;
c2=1<<24*Cos(rot_angle);
if (start_radians) {
x=x_radius*Cos(start_radians);
y=-x_radius*Sin(start_radians);
} else {
x=x_radius;
y=0;
}
x<<=8;
y<<=8;
x2=x;
y2=y;
y1=y2*y_radius/x_radius;
x=(c2*x2+s12*y1)>>24;
y=(s22*x2+c2*y1)>>24;
xx1=cx+x>>8;
yy1=cy+y>>8;
for (i=0;i<n;i++) {
x1=(c*x2+s1*y2)>>24;
y1=(s2*x2+c*y2)>>24;
x2=x1;
y2=y1;
y1=y1*y_radius/x_radius;
x=(c2*x1+s12*y1)>>24;
y=(s22*x1+c2*y1)>>24;
xx2=cx+x>>8;
yy2=cy+y>>8;
Line(aux_data,xx1,yy1,cz,xx2,yy2,cz,plot_cb,step);
xx1=xx2; yy1=yy2;
}
}
public I8 DistP3I4(P3I4 *p1,P3I4 *p2)
{
return Sqrt(SqrI8(p1->x-p2->x)+SqrI8(p1->y-p2->y)+SqrI8(p1->z-p2->z));
}
public void Bezier2(void *aux_data,P3I4 *ctrl,void plot_cb(void *aux,I8 x,I8 y,I8 z),BoolI1
first=TRUE)
{//2nd order
I8 x,y,z,xx,yy,zz,dx,dy,dz,d_max;
double x0=ctrl[0].x,y0=ctrl[0].y,z0=ctrl[0].z;
double x1=ctrl[1].x-x0,y1=ctrl[1].y-y0,z1=ctrl[1].z-z0;
double x2=ctrl[2].x-x0,y2=ctrl[2].y-y0,z2=ctrl[2].z-z0;
double t,d=DistP3I4(&ctrl[0],&ctrl[1])+
DistP3I4(&ctrl[1],&ctrl[2])+
DistP3I4(&ctrl[2],&ctrl[0]),
s=0.5/d,t1,t2;
xx=x0; yy=y0; zz=z0;
if (first)
plot_cb(aux_data,xx,yy,zz);
for (t=0.0;t<=1.0;t+=s) {
t1=t*(1.0-t);
t2=t*t;
x=x0+x1*t1+x2*t2;
y=y0+y1*t1+y2*t2;
z=z0+z1*t1+z2*t2;
dx=AbsI8(x-xx);
dy=AbsI8(y-yy);
dz=AbsI8(z-zz);
if (dx>dy)
d_max=dx;
else
d_max=dy;
if (dz>d_max)
d_max=dz;
if (!d_max)
s*=1.1;
else {
s*=0.9;
plot_cb(aux_data,x,y,z);
xx=x;yy=y;zz=z;
}
}
x=ctrl[2].x; y=ctrl[2].y; z=ctrl[2].z;
if (xx!=x || yy!=y || zz!=z)
plot_cb(aux_data,x,y,z);
}
public void Bezier3(void *aux_data,P3I4 *ctrl,void plot_cb(void *aux,I8 x,I8 y,I8 z),BoolI1
first=TRUE)
{ //3rd order
I8 x,y,z,xx,yy,zz,dx,dy,dz,d_max;
double x0=ctrl[0].x,y0=ctrl[0].y,z0=ctrl[0].z;
double x1=ctrl[1].x-x0,y1=ctrl[1].y-y0,z1=ctrl[1].z-z0;
double x2=ctrl[2].x-x0,y2=ctrl[2].y-y0,z2=ctrl[2].z-z0;
double x3=ctrl[3].x-x0,y3=ctrl[3].y-y0,z3=ctrl[3].z-z0;
double t,d=DistP3I4(&ctrl[0],&ctrl[1])+
DistP3I4(&ctrl[1],&ctrl[2])+
DistP3I4(&ctrl[2],&ctrl[3])+
DistP3I4(&ctrl[3],&ctrl[0]),
s=0.5/d,nt,t1,t2,t3;
xx=x0; yy=y0; zz=z0;
if (first)
plot_cb(aux_data,xx,yy,zz);
for (t=0.0;t<=1.0;t+=s) {
nt=1.0-t;
t1=t*nt*nt;
t2=t*t*nt;
t3=t*t*t;
x=x0+x1*t1+x2*t2+x3*t3;
y=y0+y1*t1+y2*t2+y3*t3;
z=z0+z1*t1+z2*t2+z3*t3;
dx=AbsI8(x-xx);
dy=AbsI8(y-yy);
dz=AbsI8(z-zz);
if (dx>dy)
d_max=dx;
else
d_max=dy;
if (dz>d_max)
d_max=dz;
if (!d_max)
s*=1.1;
else {
s*=0.9;
plot_cb(aux_data,x,y,z);
xx=x;yy=y;zz=z;
}
}
x=ctrl[3].x; y=ctrl[3].y; z=ctrl[3].z;
if (xx!=x || yy!=y || zz!=z)
plot_cb(aux_data,x,y,z);
}
public void BSpline2(void *aux_data,P3I4 *ctrl,I8 cnt,void plot_cb(void *aux,I8 x,I8 y,I8 z),BoolI1
closed=FALSE)
{ //2nd order
I8 i,j;
P3I4 *c;
BoolI1 first=TRUE;
if (cnt<3) return;
if (closed) {
cnt++;
c=MAlloc(sizeof(P3I4)*(cnt*2-1));
j=1;
for (i=0;i<cnt-2;i++) {
c[j].x=(ctrl[i].x+ctrl[i+1].x)/2.0;
c[j].y=(ctrl[i].y+ctrl[i+1].y)/2.0;
c[j].z=(ctrl[i].z+ctrl[i+1].z)/2.0;
j+=2;
}
c[j].x=(ctrl[0].x+ctrl[cnt-2].x)/2.0;
c[j].y=(ctrl[0].y+ctrl[cnt-2].y)/2.0;
c[j].z=(ctrl[0].z+ctrl[cnt-2].z)/2.0;
c[0].x=(c[1].x+c[j].x)/2.0;
c[0].y=(c[1].y+c[j].y)/2.0;
c[0].z=(c[1].z+c[j].z)/2.0;
j=2;
for (i=0;i<cnt-2;i++) {
c[j].x=(c[j-1].x+c[j+1].x)/2.0;
c[j].y=(c[j-1].y+c[j+1].y)/2.0;
c[j].z=(c[j-1].z+c[j+1].z)/2.0;
j+=2;
}
c[j].x=c[0].x;
c[j].y=c[0].y;
c[j].z=c[0].z;
} else {
c=MAlloc(sizeof(P3I4)*(cnt*2-1));
c[0].x=ctrl[0].x;
c[0].y=ctrl[0].y;
c[0].z=ctrl[0].z;
c[cnt*2-2].x=ctrl[cnt-1].x;
c[cnt*2-2].y=ctrl[cnt-1].y;
c[cnt*2-2].z=ctrl[cnt-1].z;
j=1;
for (i=0;i<cnt-1;i++) {
c[j].x=(ctrl[i].x+ctrl[i+1].x)/2.0;
c[j].y=(ctrl[i].y+ctrl[i+1].y)/2.0;
c[j].z=(ctrl[i].z+ctrl[i+1].z)/2.0;
j+=2;
}
j=2;
for (i=0;i<cnt-2;i++) {
c[j].x=(c[j-1].x+c[j+1].x)/2.0;
c[j].y=(c[j-1].y+c[j+1].y)/2.0;
c[j].z=(c[j-1].z+c[j+1].z)/2.0;
j+=2;
}
}
for (i=0;i<cnt*2-2;i+=2) {
Bezier2(aux_data,&c[i],plot_cb,first);
first=FALSE;
}
Free(c);
}
public void BSpline3(void *aux_data,P3I4 *ctrl,I8 cnt,void plot_cb(void *aux,I8 x,I8 y,I8 z),BoolI1
closed=FALSE)
{ //3rd order
I8 i,j;
double x,y,z;
P3I4 *c;
BoolI1 first=TRUE;
if (cnt<3) return;
if (closed) {
cnt++;
c=MAlloc(sizeof(P3I4)*(cnt*3-2));
j=1;
for (i=0;i<cnt-2;i++) {
x=ctrl[i].x;
y=ctrl[i].y;
z=ctrl[i].z;
c[j].x=(ctrl[i+1].x-x)/3.0+x;
c[j].y=(ctrl[i+1].y-y)/3.0+y;
c[j].z=(ctrl[i+1].z-z)/3.0+z;
j++;
c[j].x=2.0*(ctrl[i+1].x-x)/3.0+x;
c[j].y=2.0*(ctrl[i+1].y-y)/3.0+y;
c[j].z=2.0*(ctrl[i+1].z-z)/3.0+z;
j+=2;
}
x=ctrl[cnt-2].x;
y=ctrl[cnt-2].y;
z=ctrl[cnt-2].z;
c[j].x=(ctrl[0].x-x)/3.0+x;
c[j].y=(ctrl[0].y-y)/3.0+y;
c[j].z=(ctrl[0].z-z)/3.0+z;
j++;
c[j].x=2.0*(ctrl[0].x-x)/3.0+x;
c[j].y=2.0*(ctrl[0].y-y)/3.0+y;
c[j].z=2.0*(ctrl[0].z-z)/3.0+z;
c[0].x=(c[1].x+c[j].x)/2.0;
c[0].y=(c[1].y+c[j].y)/2.0;
c[0].z=(c[1].z+c[j].z)/2.0;
j=3;
for (i=0;i<cnt-2;i++) {
c[j].x=(c[j-1].x+c[j+1].x)/2.0;
c[j].y=(c[j-1].y+c[j+1].y)/2.0;
c[j].z=(c[j-1].z+c[j+1].z)/2.0;
j+=3;
}
c[j].x=c[0].x;
c[j].y=c[0].y;
c[j].z=c[0].z;
} else {
c=MAlloc(sizeof(P3I4)*(cnt*3-2));
c[0].x=ctrl[0].x;
c[0].y=ctrl[0].y;
c[0].z=ctrl[0].z;
c[cnt*3-3].x=ctrl[cnt-1].x;
c[cnt*3-3].y=ctrl[cnt-1].y;
c[cnt*3-3].z=ctrl[cnt-1].z;
j=1;
for (i=0;i<cnt-1;i++) {
x=ctrl[i].x;
y=ctrl[i].y;
z=ctrl[i].z;
c[j].x=(ctrl[i+1].x-x)/3.0+x;
c[j].y=(ctrl[i+1].y-y)/3.0+y;
c[j].z=(ctrl[i+1].z-z)/3.0+z;
j++;
c[j].x=2.0*(ctrl[i+1].x-x)/3.0+x;
c[j].y=2.0*(ctrl[i+1].y-y)/3.0+y;
c[j].z=2.0*(ctrl[i+1].z-z)/3.0+z;
j+=2;
}
j=3;
for (i=0;i<cnt-2;i++) {
c[j].x=(c[j-1].x+c[j+1].x)/2.0;
c[j].y=(c[j-1].y+c[j+1].y)/2.0;
c[j].z=(c[j-1].z+c[j+1].z)/2.0;
j+=3;
}
}
for (i=0;i<cnt*3-3;i+=3) {
Bezier3(aux_data,&c[i],plot_cb,first);
first=FALSE;
}
Free(c);
}
#define CC_LEFT 1
#define CC_RIGHT 2
#define CC_TOP 4
#define CC_BOTTOM 8
public BoolI8 ClipLine(I8 *_x1,I8 *_y1,I8 *_x2,I8 *_y2,I8 left,I8 top,I8 right,I8 bottom)
{
I8 x,y,x1=*_x1,y1=*_y1,x2=*_x2,y2=*_y2;
U8 cc,cc1,cc2;
if (y1>bottom)
cc1=CC_BOTTOM;
else if (y1<top)
cc1=CC_TOP;
else
cc1=0;
if (x1>right)
cc1|=CC_RIGHT;
else if (x1<left)
cc1|=CC_LEFT;
if (y2>bottom)
cc2=CC_BOTTOM;
else if (y2<top)
cc2=CC_TOP;
else
cc2=0;
if (x2>right)
cc2|=CC_RIGHT;
else if (x2<left)
cc2|=CC_LEFT;
do {
if (!(cc1|cc2))
return TRUE;
if (cc1&cc2)
return FALSE;
if (cc1)
cc=cc1;
else
cc=cc2;
if (cc&CC_BOTTOM) {
x=x1+(x2-x1)*(bottom-y1)/(y2-y1);
y=bottom;
} else if (cc&CC_TOP) {
x=x1+(x2-x1)*(top-y1)/(y2-y1);
y=top;
} else if (cc&CC_RIGHT) {
y=y1+(y2-y1)*(right-x1)/(x2-x1);
x=right;
} else {
y=y1+(y2-y1)*(left-x1)/(x2-x1);
x=left;
}
if (cc==cc1) {
*_x1=x1=x;
*_y1=y1=y;
if (y1>bottom)
cc1=CC_BOTTOM;
else if (y1<top)
cc1=CC_TOP;
else
cc1=0;
if (x1>right)
cc1|=CC_RIGHT;
else if (x1<left)
cc1|=CC_LEFT;
} else {
*_x2=x2=x;
*_y2=y2=y;
if (y2>bottom)
cc2=CC_BOTTOM;
else if (y2<top)
cc2=CC_TOP;
else
cc2=0;
if (x2>right)
cc2|=CC_RIGHT;
else if (x2<left)
cc2|=CC_LEFT;
}
} while (TRUE);
}
#help_index "Graphics"
public BoolI8 GrLimits(GrBitMap *base,I8 *left,I8 *top,I8 *right,I8 *bottom,I8 width=0,I8 height=0)
{ //returns screen, not window coordinates
*left=0;
*top=0;
*right=base->width-1;
*bottom=base->height-1;
if (base->flags & BMF_SCREEN_BITMAP) {
if (GR_WIDTH-1<*right)
*right=GR_WIDTH-1;
if (GR_HEIGHT-1<*bottom)
*bottom=GR_HEIGHT-1;
if (base->win_tss->win_pixel_left>*left)
*left=base->win_tss->win_pixel_left;
if (base->win_tss->win_pixel_top>*top)
*top=base->win_tss->win_pixel_top;
if (base->win_tss->win_pixel_right<*right)
*right=base->win_tss->win_pixel_right;
if (base->win_tss->win_pixel_bottom<*bottom)
*bottom=base->win_tss->win_pixel_bottom;
}
*left-=width;
*right+=width;
*top-=height;
*bottom+=height;
return *left<=*right && *top<=*bottom;
}
BoolI8 GrClipLine(GrBitMap *base,I8 *x1,I8 *y1,I8 *x2,I8 *y2,I8 width=0,I8 height=0)
{ //also converts window to screen coordinates
I8 left,top,right,bottom;
if (GrLimits(base,&left,&top,&right,&bottom,width,height)) {
if (base->flags & BMF_SCREEN_BITMAP) {
*x1+=base->win_tss->win_pixel_left;
*y1+=base->win_tss->win_pixel_top;
*x2+=base->win_tss->win_pixel_left;
*y2+=base->win_tss->win_pixel_top;
}
return ClipLine(x1,y1,x2,y2,left,top,right,bottom);
} else
return FALSE;
}
public void GrPlot(GrBitMap *base,I8 x,I8 y)
{ //Clipping but No transformation or pen width
if (base->brush)
GrBlot(base,x,y,base->brush);
else if (base->flags & BMF_SCREEN_BITMAP) {
if (x>=0 && y>=0) {
x+=base->win_tss->win_pixel_left;
y+=base->win_tss->win_pixel_top;
if (x<=base->win_tss->win_pixel_right &&
y<=base->win_tss->win_pixel_bottom &&
0<=x<base->right_margin-base->left_margin &&
0<=y<base->bottom_margin-base->top_margin &&
(base->flags&BMF_ON_TOP ||
!IsPixelCovered(base->win_tss,x,y)))
GrPlot0(base,x,y);
}
} else
if (0<=x<base->right_margin-base->left_margin &&
0<=y<base->bottom_margin-base->top_margin)
GrPlot0(base,x,y);
}
public I8 GrPeek(GrBitMap *base,I8 x,I8 y)
//Returns pixel color or -1 if off-screen or covered.
{ //Clipping but No transformation
BoolI1 peek=TRUE;
if (base->flags & BMF_SCREEN_BITMAP) {
if (x<0) peek=FALSE;
x+=base->win_tss->win_pixel_left;
if (x>base->win_tss->win_pixel_right) peek=FALSE;
if (y<0) peek=FALSE;
y+=base->win_tss->win_pixel_top;
if (y>base->win_tss->win_pixel_bottom) peek=FALSE;
if (x>=base->right_margin-base->left_margin) peek=FALSE;
if (y>=base->bottom_margin-base->top_margin) peek=FALSE;
if (!(base->flags&BMF_ON_TOP) &&
IsPixelCovered(base->win_tss,x,y)) peek=FALSE;
} else {
if (x<0) peek=FALSE;
if (x>=base->right_margin-base->left_margin) peek=FALSE;
if (y<0) peek=FALSE;
if (y>=base->bottom_margin-base->top_margin) peek=FALSE;
}
if (peek)
return GrPeek0(base,x,y);
else
return -1;
}
I8 GrFloodFillRay(GrBitMap *base,I8 x,I8 y)
{
I8 cnt,j,x1,ray_len,ray_len2;
cnt=ray_len=GrRayLen(base,&x,y);
y--;
j=ray_len;
x1=x;
while (j>0) {
if (ray_len2=GrRayLenMinus(base,x1,y))
cnt+=GrFloodFillRay(base,x1,y);
j-=ray_len2+1;
x1-=ray_len2+1;
}
y+=2;
j=ray_len;
x1=x;
while (j>0) {
if (ray_len2=GrRayLenMinus(base,x1,y))
cnt+=GrFloodFillRay(base,x1,y);
j-=ray_len2+1;
x1-=ray_len2+1;
}
return cnt;
}
public I8 GrFloodFill(GrBitMap *base,I8 x,I8 y,BoolI1 not_color=FALSE)
{
//$FG,2$not_color=TRUE$FG$ means fill up to everything which is not the current color.
//$FG,2$not_color=FALSE$FG$ means fill all parts equal to the color under the point.
I8 cnt=0,j,c,old_color2=base->color2,old_flags=base->flags;
GrBitMap *old_brush;
if (base->flags & BMF_DONT_DRAW) //TODO
return 0;
old_brush=base->brush;
base->brush=NULL;
if ((j=GrPeek(base,x,y))>=0) {
switch (base->type) {
case BMT_COLOR4:
case BMT_COLOR4_U1:
if (not_color) {
base->color2=base->color&0xFFFFFF;
base->flags|=BMF_FILL_NOT_COLOR;
} else {
base->color2=j;
if (base->color2==base->color&0xFFFFFF)
break;
base->flags&=~BMF_FILL_NOT_COLOR;
}
if (not_color && j!=base->color2 ||
!not_color)
cnt=GrFloodFillRay(base,x,y);
break;
case BMT_MONO:
c=base->color&0xFFFFFF ?1:0;
if (not_color) {
base->color2=c;
base->flags|=BMF_FILL_NOT_COLOR;
} else {
base->color2=j;
if (base->color2==c)
break;
base->flags&=~BMF_FILL_NOT_COLOR;
}
if (not_color && j!=c ||
!not_color)
cnt=GrFloodFillRay(base,x,y);
break;
}
}
base->brush=old_brush;
base->flags=old_flags;
base->color2=old_color2;
return cnt;
}
public void GrPlot2(GrBitMap *base,I8 x,I8 y,I8 z)
{ //Clipping and transformation but no pen_width
I8 _x,_y,_z;
BoolI1 was_transform=FALSE,was_symmetry=FALSE;
if (base->flags & BMF_TRANSFORMATION) {
GrTransform(base,&x,&y,&z);
base->flags&=~BMF_TRANSFORMATION;
was_transform=TRUE;
}
if (base->flags & BMF_SYMMETRY) {
_x=x; _y=y; _z=z;
GrReflect(base,&_x,&_y,&_z);
base->flags&=~BMF_SYMMETRY;
GrPlot(base,_x,_y);
was_symmetry=TRUE;
if (base->flags&BMF_JUST_MIRROR)
goto done;
}
GrPlot(base,x,y);
done:
if (was_transform)
base->flags|=BMF_TRANSFORMATION;
if (was_symmetry)
base->flags|=BMF_SYMMETRY;
}
public void GrPlot3(GrBitMap *base,I8 x,I8 y,I8 z)
{ //clipping and transformation and pen width
I8 _x,_y,_z,i,j,w,old_color,dist;
BoolI1 was_transform=FALSE,was_symmetry=FALSE;
if (base->flags & BMF_TRANSFORMATION) {
GrTransform(base,&x,&y,&z);
base->flags&=~BMF_TRANSFORMATION;
was_transform=TRUE;
}
if (base->flags & BMF_SYMMETRY) {
_x=x; _y=y; _z=z;
GrReflect(base,&_x,&_y,&_z);
base->flags&=~BMF_SYMMETRY;
GrPlot3(base,_x,_y,_z);
was_symmetry=TRUE;
if (base->flags&BMF_JUST_MIRROR)
goto done;
}
w=base->pen_width>>1;
if (w<=0)
GrPlot(base,x,y);
else if (base->pen_width<GR_NUM_PEN_BRUSHES) {
old_color=base->color;
if (base->color.u1[3]==ROPB_EQU)
base->color.u1[3]=ROPB_TRANSPARENT;
if (base->color.u1[3]==ROPB_CLEAR_MASK_EQU)
base->color.u1[3]=ROPB_CLEAR_MASK_TRANSPARENT;
if (GrBlot(base,x-w,y-w,gr_pen_brushes[base->pen_width])) {
if (base->flags & BMF_SCREEN_BITMAP) {
x+=base->win_tss->win_pixel_left;
y+=base->win_tss->win_pixel_top;
}
if (base->flags & BMF_LOCATE_NEAREST) {
dist=DistI8(x,y,base->cur_x,base->cur_y);
if (dist<base->nearest_dist) {
base->nearest_grelem_num=base->cur_grelem_num;
base->nearest_dist=dist;
}
}
if (base->flags & BMF_RECORD_EXTENTS) {
if (x-w<base->min_x) base->min_x=x-w;
if (y-w<base->min_y) base->min_y=y-w;
if (base->pen_width & 1) {
if (x+w>base->max_x) base->max_x=x+w;
if (y+w>base->max_y) base->max_y=y+w;
} else {
if (x+w-1>base->max_x) base->max_x=x+w-1;
if (y+w-1>base->max_y) base->max_y=y+w-1;
}
}
}
base->color=old_color;
} else if (base->pen_width & 1) {
for (i=-w;i<=w;i++)
for (j=-w;j<=w;j++)
GrPlot(base,x+i,y+j);
} else {
for (i=-w;i<w;i++)
for (j=-w;j<w;j++)
GrPlot(base,x+i,y+j);
}
done:
if (was_transform)
base->flags|=BMF_TRANSFORMATION;
if (was_symmetry)
base->flags|=BMF_SYMMETRY;
}
void GrLinePlot0(GrBitMap *base,I8 x,I8 y,I8 z)
{
nounusedwarn z;
if (!(base->flags & BMF_SCREEN_BITMAP) ||
base->flags&BMF_ON_TOP ||
!IsPixelCovered(base->win_tss,x,y))
GrPlot0(base,x,y);
}
void GrLinePlot(GrBitMap *base,I8 x,I8 y,I8 z)
{
nounusedwarn z;
GrPlot(base,x,y);
}
public void GrLine(GrBitMap *base,I8 x1,I8 y1,I8 x2,I8 y2,I8 step=1,I8 start=0)
{
if (step==1 && !start && !base->brush) {
if (GrClipLine(base,&x1,&y1,&x2,&y2))
Line(base,x1,y1,0,x2,y2,0,&GrLinePlot0,step,start);
} else
Line(base,x1,y1,0,x2,y2,0,&GrLinePlot,step,start);
}
public void GrCircle(GrBitMap *base,I8 cx,I8 cy,I8 radius,
I8 step=1,double start_radians=0,double len_radians=2*pi)
{
Circle(base,cx,cy,0,radius,&GrLinePlot,step,start_radians,len_radians);
}
public void GrEllipse(GrBitMap *base,
I8 cx,I8 cy,
I8 x_radius,I8 y_radius,
double rot_angle=0,
I8 step=1,
double start_radians=0,
double len_radians=2*pi)
{
Ellipse(base,cx,cy,0,x_radius,y_radius,&GrLinePlot,rot_angle,step,start_radians,len_radians);
}
public void GrRegPolygon(GrBitMap *base,
I8 cx,I8 cy,
I8 x_radius,I8 y_radius,I8 sides,
double rot_angle=0,
I8 step=1,
double start_radians=0,
double len_radians=2*pi)
{
RegPolygon(base,cx,cy,0,x_radius,y_radius,sides,
&GrLinePlot,rot_angle,step,start_radians,len_radians);
}
public void Gr2Bezier(GrBitMap *base,P3I4 *ctrl)
{
Bezier2(base,ctrl,&GrLinePlot);
}
public void Gr3Bezier(GrBitMap *base,P3I4 *ctrl)
{
Bezier3(base,ctrl,&GrLinePlot);
}
public void Gr2BSpline(GrBitMap *base,P3I4 *ctrl,I8 cnt,BoolI1 closed=FALSE)
{
BSpline2(base,ctrl,cnt,&GrLinePlot,closed);
}
public void Gr3BSpline(GrBitMap *base,P3I4 *ctrl,I8 cnt,BoolI1 closed=FALSE)
{
BSpline3(base,ctrl,cnt,&GrLinePlot,closed);
}
public void GrLine2(GrBitMap *base,I8 x1,I8 y1,I8 z1,I8 x2,I8 y2,I8 z2,I8 step=1,I8 start=0)
{ //transformation but not pen width
I8 _x1,_y1,_z1,_x2,_y2,_z2;
BoolI1 was_transform=FALSE,was_symmetry=FALSE;
if (base->flags & BMF_TRANSFORMATION) {
GrTransform(base,&x1,&y1,&z1);
GrTransform(base,&x2,&y2,&z2);
base->flags&=~BMF_TRANSFORMATION;
was_transform=TRUE;
}
if (base->flags & BMF_SYMMETRY) {
_x1=x1; _y1=y1; _z1=z1;
GrReflect(base,&_x1,&_y1,&_z1);
_x2=x2; _y2=y2; _z2=z2;
GrReflect(base,&_x2,&_y2,&_z2);
base->flags&=~BMF_SYMMETRY;
if (step==1 && !start && !base->brush) {
if (GrClipLine(base,&_x1,&_y1,&_x2,&_y2))
Line(base,_x1,_y1,0,_x2,_y2,0,&GrLinePlot0,step,start);
} else
Line(base,_x1,_y1,0,_x2,_y2,0,&GrLinePlot,step,start);
was_symmetry=TRUE;
if (base->flags&BMF_JUST_MIRROR)
goto done;
}
if (step==1 && !start && !base->brush) {
if (GrClipLine(base,&x1,&y1,&x2,&y2))
Line(base,x1,y1,0,x2,y2,0,&GrLinePlot0,step,start);
} else
Line(base,x1,y1,0,x2,y2,0,&GrLinePlot,step,start);
done:
if (was_transform)
base->flags|=BMF_TRANSFORMATION;
if (was_symmetry)
base->flags|=BMF_SYMMETRY;
}
void GrLine3Plot(GrBitMap *base,I8 x,I8 y,I8 z)
{
GrPlot3(base,x,y,z);
}
public void GrLine3(GrBitMap *base,I8 x1,I8 y1,I8 z1,I8 x2,I8 y2,I8 z2,I8 step=1,I8 start=0)
{ //transformation with pen width
I8 _x1,_y1,_z1,_x2,_y2,_z2;
BoolI1 was_transform=FALSE,was_symmetry=FALSE;
if (base->flags & BMF_TRANSFORMATION) {
GrTransform(base,&x1,&y1,&z1);
GrTransform(base,&x2,&y2,&z2);
base->flags&=~BMF_TRANSFORMATION;
was_transform=TRUE;
}
if (base->flags & BMF_SYMMETRY) {
_x1=x1; _y1=y1; _z1=z1;
GrReflect(base,&_x1,&_y1,&_z1);
_x2=x2; _y2=y2; _z2=z2;
GrReflect(base,&_x2,&_y2,&_z2);
base->flags&=~BMF_SYMMETRY;
Line(base,_x1,_y1,0,_x2,_y2,0,&GrLine3Plot,step,start);
was_symmetry=TRUE;
if (base->flags&BMF_JUST_MIRROR)
goto done;
}
Line(base,x1,y1,0,x2,y2,0,&GrLine3Plot,step,start);
done:
if (was_transform)
base->flags|=BMF_TRANSFORMATION;
if (was_symmetry)
base->flags|=BMF_SYMMETRY;
}
public BoolI8 GrPutS3(GrBitMap *base,I8 x1,I8 y1,I8 z1,I1 *s)
{ //transformation
//BMF_SYMMETRY is silly.
if (base->flags & BMF_TRANSFORMATION)
GrTransform(base,&x1,&y1,&z1);
return GrPutS(base,x1,y1,s);
}
public BoolI8 GrVPutS3(GrBitMap *base,I8 x1,I8 y1,I8 z1,I1 *s)
{ //Vertical text
//transformation
//BMF_SYMMETRY is silly.
if (base->flags & BMF_TRANSFORMATION)
GrTransform(base,&x1,&y1,&z1);
return GrVPutS(base,x1,y1,s);
}
public void GrPrintF3(GrBitMap *base,I8 x,I8 y,I8 z,I1 *fmt,...)
{
I1 *buf=SPrintFJoin(NULL,fmt,argc,argv);
GrPutS3(base,x,y,z,buf);
Free(buf);
}
public void GrVPrintF3(GrBitMap *base,I8 x,I8 y,I8 z,I1 *fmt,...)
{ //Vertical text
I1 *buf=SPrintFJoin(NULL,fmt,argc,argv);
GrVPutS3(base,x,y,z,buf);
Free(buf);
}
public void GrEllipse3(GrBitMap *base,
I8 cx,I8 cy,I8 cz,
I8 x_radius,I8 y_radius,
double rot_angle=0,
I8 step=1,
double start_radians=0,
double len_radians=2*pi)
{
I8 x,y,z;
double m1,a1,m2,a2,s,c;
if (base->flags & BMF_TRANSFORMATION) {
base->flags&=~BMF_TRANSFORMATION;
GrTransform(base,&cx,&cy,&cz);
c=Cos(rot_angle);
s=Sin(rot_angle);
x_radius<<=24;
y_radius<<=24;
x=x_radius*c;
y=x_radius*s;
z=0;
GrRotate(base->r,&x,&y,&z);
R2P(&m1,&a1,x,y);
x=-y_radius*s;
y=y_radius*c;
z=0;
GrRotate(base->r,&x,&y,&z);
R2P(&m2,&a2,x,y);
m2=m2*Abs(Sin(a2-a1));
Ellipse(base,cx,cy,cz,
m1/0x1000000,m2/0x1000000,&GrLine3Plot,-a1,step,start_radians,len_radians);
base->flags|=BMF_TRANSFORMATION;
} else
Ellipse(base,cx,cy,cz,x_radius,y_radius,&GrLine3Plot,rot_angle,step,start_radians,len_radians);
}
public void GrCircle3(GrBitMap *base,I8 cx,I8 cy,I8 cz,I8 radius,
I8 step=1,double start_radians=0,double len_radians=2*pi)
{ //transformation with pen width
if (base->flags & BMF_TRANSFORMATION)
GrEllipse3(base,cx,cy,cz,radius,radius,0,step,start_radians,len_radians);
else
Circle(base,cx,cy,cz,radius,&GrLine3Plot,step,start_radians,len_radians);
}
public void GrRegPolygon3(GrBitMap *base,
I8 cx,I8 cy,I8 cz,
I8 x_radius,I8 y_radius,I8 sides,
double rot_angle=0,
I8 step=1,
double start_radians=0,
double len_radians=2*pi)
{
I8 x,y,z;
double m1,a1,m2,a2,s,c;
if (base->flags & BMF_TRANSFORMATION) {
base->flags&=~BMF_TRANSFORMATION;
GrTransform(base,&cx,&cy,&cz);
c=Cos(rot_angle);
s=Sin(rot_angle);
x_radius<<=24;
y_radius<<=24;
x=x_radius*c;
y=x_radius*s;
z=0;
GrRotate(base->r,&x,&y,&z);
R2P(&m1,&a1,x,y);
x=-y_radius*s;
y=y_radius*c;
z=0;
GrRotate(base->r,&x,&y,&z);
R2P(&m2,&a2,x,y);
m2=m2*Abs(Sin(a2-a1));
RegPolygon(base,cx,cy,cz,
m1/0x1000000,m2/0x1000000,sides,&GrLine3Plot,-a1,step,start_radians,len_radians);
base->flags|=BMF_TRANSFORMATION;
} else
RegPolygon(base,cx,cy,cz,x_radius,y_radius,sides,&GrLine3Plot,rot_angle,step,start_radians,len_radians
);
}
public I8 GrFloodFill3(GrBitMap *base,I8 x1,I8 y1,I8 z1,BoolI1 not_color=FALSE)
{ //transformation
//$FG,2$not_color=TRUE$FG$ means fill up to everything which is not the current color.
//$FG,2$not_color=FALSE$FG$ means fill all parts equal to the color under the point.
I8 cnt,old_flags=base->flags;
I8 _x,_y,_z;
if (base->flags & BMF_TRANSFORMATION) {
GrTransform(base,&x1,&y1,&z1);
base->flags&=~BMF_TRANSFORMATION;
}
if (base->flags & BMF_SYMMETRY) {
_x=x1; _y=y1; _z=z1;
GrReflect(base,&_x,&_y,&_z);
base->flags&=~BMF_SYMMETRY;
cnt=GrFloodFill(base,_x,_y,not_color);
if (base->flags&BMF_JUST_MIRROR)
goto done;
}
cnt=GrFloodFill(base,x1,y1,not_color);
done:
base->flags=old_flags;
return cnt;
}
public void GrBox3(GrBitMap *base,I8 x,I8 y,I8 z,I8 w,I8 h)
{ //Clipping and transformation
I8 x2,y2,z2,x3,y3,z3;
GrBitMap *old_brush=base->brush;
if (base->flags & BMF_TRANSFORMATION) {
base->brush=NULL;
x2=x+w; y2=y; z2=z;
x3=x; y3=y+h; z3=z;
GrTransform(base,&x,&y,&z);
GrTransform(base,&x2,&y2,&z2);
GrTransform(base,&x3,&y3,&z3);
if (!(base->flags&BMF_JUST_MIRROR) ||
!(base->flags&BMF_SYMMETRY))
Box(base,x,y,z,x2,y2,z2,x3,y3,z3,&GrLinePlot);
if (base->flags & BMF_SYMMETRY) {
GrReflect(base,&x,&y,&z);
GrReflect(base,&x2,&y2,&z2);
GrReflect(base,&x3,&y3,&z3);
Box(base,x,y,z,x2,y2,z2,x3,y3,z3,&GrLinePlot);
}
base->brush=old_brush;
} else {
if (!(base->flags&BMF_JUST_MIRROR)||
!(base->flags&BMF_SYMMETRY))
GrBox(base,x,y,w,h);
if (base->flags & BMF_SYMMETRY) {
base->brush=NULL;
x2=x+w; y2=y; z2=z;
x3=x; y3=y+h; z3=z;
GrReflect(base,&x,&y,&z);
GrReflect(base,&x2,&y2,&z2);
GrReflect(base,&x3,&y3,&z3);
Box(base,x,y,z,x2,y2,z2,x3,y3,z3,&GrLinePlot);
base->brush=old_brush;
}
}
}
public BoolI8 GrBlot3(GrBitMap *base,I8 x1,I8 y1,I8 z1,GrBitMap *img)
{ //Clipping and transformation
I8 reg i,j,w=img->width,h=img->height,old_color=base->color,reg color,
d1,dx1,dy1,dz1,
reg d2,dx2,dy2,dz2,
adx1,ady1,adz1,
adx2,ady2,adz2,
x2,y2,z2,x3,y3,z3,
dw,reg dh,x,y,_x1,_y1,_z1,_x2,_y2,_z2,_x3,_y3,_z3,
last_x,last_y;
BoolI1 first;
GrBitMap *old_brush=base->brush;
if (base->flags & (BMF_TRANSFORMATION | BMF_SYMMETRY)) {
x2=x1+w; y2=y1; z2=z1;
x3=x1; y3=y1+h; z3=z1;
if (base->flags & BMF_TRANSFORMATION) {
GrTransform(base,&x1,&y1,&z1);
GrTransform(base,&x2,&y2,&z2);
GrTransform(base,&x3,&y3,&z3);
}
if (base->flags & BMF_SYMMETRY) {
_x1=x1; _y1=y1; _z1=z1;
GrReflect(base,&_x1,&_y1,&_z1);
_x2=x2; _y2=y2; _z2=z2;
GrReflect(base,&_x2,&_y2,&_z2);
_x3=x3; _y3=y3; _z3=z3;
GrReflect(base,&_x3,&_y3,&_z3);
dx1=_x2-_x1; dy1=_y2-_y1; dz1=_z2-_z1;
dx2=_x3-_x1; dy2=_y3-_y1; dz2=_z3-_z1;
adx1=AbsI8(dx1); ady1=AbsI8(dy1); adz1=AbsI8(dz1);
adx2=AbsI8(dx2); ady2=AbsI8(dy2); adz2=AbsI8(dz2);
if (adx1>=ady1)
d1=adx1>=adz1 ? adx1:adz1;
else
d1=ady1>=adz1 ? ady1:adz1;
if (adx2>=ady2)
d2=adx2>=adz2 ? adx2:adz2;
else
d2=ady2>=adz2 ? ady2:adz2;
if (AbsI8(d1)!=w ||AbsI8(d2)!=h) {
d1<<=1;
d2<<=1;
}
if (d1) {
dx1=dx1<<32/d1;
dy1=dy1<<32/d1;
dz1=dz1<<32/d1;
} else
goto normal_image;
if (d2) {
dx2=dx2<<32/d2;
dy2=dy2<<32/d2;
dz2=dz2<<32/d2;
} else
goto normal_image;
base->brush=NULL;
x=0;y=0;
dw=w<<32/d1;
dh=h<<32/d2;
first=TRUE;
_x1<<=32; _y1<<=32; _z1<<=32;
for (j=0;j<=d1;j++) {
_x2=_x1; _y2=_y1; _z2=_z1;
y=0;
for (i=0;i<=d2;i++) {
if (_x2.i4[1]!=last_x || _y2.i4[1]!=last_y ||first) {
color=GrPeek(img,x.i4[1],y.i4[1]);
if (color>=0 &&
(old_color.u1[3]!=ROPB_TRANSPARENT ||
color&0xFFFFFF!=img->bkcolor&0xFFFFFF)) {
base->color=old_color&0xFF000000+color;
GrPlot(base,_x2.i4[1],_y2.i4[1]);
}
}
first=FALSE;
last_x=_x2.i4[1]; last_y=_y2.i4[1];
_x2+=dx2; _y2+=dy2; _z2+=dz2;
y+=dh;
}
_x1+=dx1; _y1+=dy1; _z1+=dz1;
x+=dw;
}
normal_image:
if (base->flags&BMF_JUST_MIRROR)
goto done;
}
dx1=x2-x1; dy1=y2-y1; dz1=z2-z1;
dx2=x3-x1; dy2=y3-y1; dz2=z3-z1;
adx1=AbsI8(dx1); ady1=AbsI8(dy1); adz1=AbsI8(dz1);
adx2=AbsI8(dx2); ady2=AbsI8(dy2); adz2=AbsI8(dz2);
if (adx1>=ady1)
d1=adx1>=adz1 ? adx1:adz1;
else
d1=ady1>=adz1 ? ady1:adz1;
if (adx2>=ady2)
d2=adx2>=adz2 ? adx2:adz2;
else
d2=ady2>=adz2 ? ady2:adz2;
if (AbsI8(d1)!=w ||AbsI8(d2)!=h) {
d1<<=1;
d2<<=1;
}
if (d1) {
dx1=dx1<<32/d1;
dy1=dy1<<32/d1;
dz1=dz1<<32/d1;
} else
return FALSE;
if (d2) {
dx2=dx2<<32/d2;
dy2=dy2<<32/d2;
dz2=dz2<<32/d2;
} else
return FALSE;
base->brush=NULL;
x=0;y=0;
dw=w<<32/d1;
dh=h<<32/d2;
first=TRUE;
x1<<=32; y1<<=32; z1<<=32;
for (j=0;j<=d1;j++) {
x2=x1; y2=y1; z2=z1;
y=0;
for (i=0;i<=d2;i++) {
if (x2.i4[1]!=last_x || y2.i4[1]!=last_y || first) {
color=GrPeek(img,x.i4[1],y.i4[1]);
if (color>=0 &&
(old_color.u1[3]!=ROPB_TRANSPARENT ||
color&0xFFFFFF!=img->bkcolor&0xFFFFFF)) {
base->color=old_color&0xFF000000+color;
GrPlot(base,x2.i4[1],y2.i4[1]);
}
}
first=FALSE;
last_x=x2.i4[1]; last_y=y2.i4[1];
x2+=dx2; y2+=dy2; z2+=dz2;
y+=dh;
}
x1+=dx1; y1+=dy1; z1+=dz1;
x+=dw;
}
base->color=old_color;
base->brush=old_brush;
return TRUE; //TODO: check off screen
} else
return GrBlot(base,x1,y1,img);
done:
}
public void Gr2Bezier3(GrBitMap *base,P3I4 *ctrl)
{
I8 i,x,y,z;
P3I4 *ctrl2;
if (base->flags & BMF_TRANSFORMATION) {
ctrl2=MAlloc(sizeof(P3I4)*3);
for (i=0;i<3;i++) {
x=ctrl[i].x;
y=ctrl[i].y;
z=ctrl[i].z;
GrTransform(base,&x,&y,&z);
ctrl2[i].x=x;
ctrl2[i].y=y;
ctrl2[i].z=z;
}
base->flags&=~BMF_TRANSFORMATION;
Bezier2(base,ctrl2,&GrLine3Plot);
base->flags|=BMF_TRANSFORMATION;
Free(ctrl2);
} else
Bezier2(base,ctrl,&GrLine3Plot);
}
public void Gr3Bezier3(GrBitMap *base,P3I4 *ctrl)
{
I8 i,x,y,z;
P3I4 *ctrl2;
if (base->flags & BMF_TRANSFORMATION) {
ctrl2=MAlloc(sizeof(P3I4)*4);
for (i=0;i<4;i++) {
x=ctrl[i].x;
y=ctrl[i].y;
z=ctrl[i].z;
GrTransform(base,&x,&y,&z);
ctrl2[i].x=x;
ctrl2[i].y=y;
ctrl2[i].z=z;
}
base->flags&=~BMF_TRANSFORMATION;
Bezier3(base,ctrl2,&GrLine3Plot);
base->flags|=BMF_TRANSFORMATION;
Free(ctrl2);
} else
Bezier3(base,ctrl,&GrLine3Plot);
}
public void Gr2BSpline3(GrBitMap *base,P3I4 *ctrl,I8 cnt,BoolI1 closed=FALSE)
{
I8 i,x,y,z;
P3I4 *ctrl2;
if (base->flags & BMF_TRANSFORMATION) {
ctrl2=MAlloc(sizeof(P3I4)*cnt);
for (i=0;i<cnt;i++) {
x=ctrl[i].x;
y=ctrl[i].y;
z=ctrl[i].z;
GrTransform(base,&x,&y,&z);
ctrl2[i].x=x;
ctrl2[i].y=y;
ctrl2[i].z=z;
}
base->flags&=~BMF_TRANSFORMATION;
BSpline2(base,ctrl2,cnt,&GrLine3Plot,closed);
base->flags|=BMF_TRANSFORMATION;
Free(ctrl2);
} else
BSpline2(base,ctrl,cnt,&GrLine3Plot,closed);
}
public void Gr3BSpline3(GrBitMap *base,P3I4 *ctrl,I8 cnt,BoolI1 closed=FALSE)
{
I8 i,x,y,z;
P3I4 *ctrl2;
if (base->flags & BMF_TRANSFORMATION) {
ctrl2=MAlloc(sizeof(P3I4)*cnt);
for (i=0;i<cnt;i++) {
x=ctrl[i].x;
y=ctrl[i].y;
z=ctrl[i].z;
GrTransform(base,&x,&y,&z);
ctrl2[i].x=x;
ctrl2[i].y=y;
ctrl2[i].z=z;
}
base->flags&=~BMF_TRANSFORMATION;
BSpline3(base,ctrl2,cnt,&GrLine3Plot,closed);
base->flags|=BMF_TRANSFORMATION;
Free(ctrl2);
} else
BSpline3(base,ctrl,cnt,&GrLine3Plot,closed);
}
public void GrSpeedLine(GrBitMap *base,I8 x1,I8 y1,I8 x2,I8 y2,double speed)
{
U8 old_flags=base->flags;
I8 old_pen_width=base->pen_width;
base->pen_width=base->speedline_scale*speed;
base->flags&=~(BMF_TRANSFORMATION|BMF_SYMMETRY|BMF_JUST_MIRROR);
GrLine3(base,x1,y1,0,x2,y2,0);
base->flags=old_flags;
base->pen_width=old_pen_width;
}
public void GrSpeedLine2(GrBitMap *base,I8 x1,I8 y1,I8 z1,I8 x2,I8 y2,I8 z2,double speed)
{ //transformation but not pen width
U8 old_flags=base->flags;
I8 _x1,_y1,_z1,_x2,_y2,_z2;
if (base->flags & BMF_TRANSFORMATION) {
GrTransform(base,&x1,&y1,&z1);
GrTransform(base,&x2,&y2,&z2);
base->flags&=~BMF_TRANSFORMATION;
}
if (base->flags & BMF_SYMMETRY) {
_x1=x1; _y1=y1; _z1=z1;
GrReflect(base,&_x1,&_y1,&_z1);
_x2=x2; _y2=y2; _z2=z2;
GrReflect(base,&_x2,&_y2,&_z2);
base->flags&=~BMF_SYMMETRY;
GrSpeedLine(base,_x1,_y1,_x2,_y2,speed);
if (base->flags & BMF_JUST_MIRROR)
goto done;
}
GrSpeedLine(base,x1,y1,x2,y2,speed);
done:
base->flags=old_flags;
}
Graphic Plotting