00001
00002
00003 #define MODULE_DRAW 1
00004
00005 #include "animate.h"
00006
00007 static void GetInternalMotion(align *Ap, long frame, double dframe,
00008 short *im, double *ima);
00009 static double GetFollowOnOffset(node *Np, long frame, double dframe,
00010 point Offset);
00011 static int CheckInterrupt(void);
00012 static void CalculateOffset(node *Np,long frame, double dframe, point dp, double sx,
00013 double sy, double sz);
00014 static void CalculateSize(node *Np, long frame, double dframe,
00015 double *sx, double *sy, double *sz);
00016 static void DrawLightCone(HDC hdc[], short status, node *Np,
00017 short al_type, point Offset, point TrackedOffset,
00018 double p, double t, double a,
00019 short im, double ima, double cone,
00020 double edge);
00021 static void DrawLightExtent(HDC hdc[], short status, node *Np,
00022 short al_type, point Offset,
00023 double sz);
00024 static void DrawCameraFOV(HDC hdc[],
00025 short status, node *Np, short al_type,
00026 point Offset, point TrackedOffset,
00027 double p, double t, double a,
00028 short im, double ima,
00029 double sx, double sy, double sz);
00030 static short DrawQuickObject(HDC hdc[], object *Op, point Offset
00031 , double p, double t, double a
00032 , short im, double ima
00033 , double sx, double sy, double sz, short status);
00034 static short DrawNurbsObject(HDC hdc[], object *Op, point Offset
00035 , double p, double t, double a
00036 , short im, double ima
00037 , double sx, double sy, double sz, short status);
00038 static void DrawAxis(HDC hdc[], point v1, short status);
00039 static int OnModelEdge(int npx, int npy,
00040 int sh1, int sv1, int sh2, int sv2,
00041 point v1, point v2,
00042 double *dc);
00043
00044 static int zoom_abort=NO;
00045 static int order_list[3][3]={ {0,1,2},{1,2,0},{2,0,1} };
00046
00047 static int CheckInterrupt(void){
00048 int i;
00049 MSG msg;
00050 if(do_NOT_abort)return 0;
00051 if(tool_move_flag){
00052
00053 zoom_abort=1;
00054 }
00055 else zoom_abort=0;
00056 return zoom_abort;
00057 }
00058
00059 void ScalePoint(double scalex, double scaley, double scalez,
00060 point p, point r){
00061 r[0] = (long)(scalex*(double)p[0]);
00062 r[1] = (long)(scaley*(double)p[1]);
00063 r[2] = (long)(scalez*(double)p[2]);
00064 }
00065
00066 void CopyPoint(point p1, point p2){
00067 p2[0]=p1[0]; p2[1]=p1[1]; p2[2]=p1[2];
00068 }
00069
00070 void AddPoints(point p1, point p2, point result){
00071 result[0]=p1[0]+p2[0];
00072 result[1]=p1[1]+p2[1];
00073 result[2]=p1[2]+p2[2];
00074 }
00075
00076 void SubPoints(point p1, point p2, point result){
00077 result[0]=p1[0]-p2[0];
00078 result[1]=p1[1]-p2[1];
00079 result[2]=p1[2]-p2[2];
00080 }
00081
00082 short in_stage_triview(point vp){
00083 if( ((vp[0] > TVpointX) && (vp[0] < TVpointX+TVsizeX))
00084 && ((vp[1] > TVpointY) && (vp[1] < TVpointY+TVsizeY))
00085 && ((vp[2] > TVpointZ) && (vp[2] < TVpointZ+TVsizeZ))
00086 )return 1;
00087 return 0;
00088 }
00089
00090 static short ep1[12]={0,1,2,3,4,5,6,7,0,1,2,3};
00091 static short ep2[12]={1,2,3,0,5,6,7,4,4,5,6,7};
00092 static point Pointer[6]={{ 0, 0, 0}
00093 ,{ 0, 20, 0}
00094 ,{ 0, 30, 0}
00095 ,{ 3, 20, 0}
00096 ,{ -3, 20, 0}
00097 ,{ 0, 0, 10}};
00098 static short pp1[5]={0,2,2,3,0};
00099 static short pp2[5]={1,3,4,4,5};
00100 static point Rectang[4]={{ 0, 0, 0}
00101 ,{ UNIT*4, 0, 0}
00102 ,{ UNIT*4,-UNIT*4, 0}
00103 ,{ 0,-UNIT*4, 0}};
00104 static short rp1[4]={0,1,2,3};
00105 static short rp2[4]={1,2,3,0};
00106 static point trpoints[13],srpoints[10];
00107
00108 void get_centre_stage(point p, point TVp, point TVclipMin, point TVclipMax){
00109 node *Np;
00110 object *Op;
00111 pathpoint *Pp;
00112 point Offset,TrackedOffset;
00113 short im;
00114 double phi,theta,alpha,sx,sy,sz,ima;
00115 long i,xmin,xmax,ymin,ymax,zmin,zmax,d;
00116 xmin=ymin=zmin=MAXUNIT; xmax=ymax=zmax = -MAXUNIT;
00117 for(i=0;i<3;i++)TVclipMin[i]=TVclipMax[i]=0;
00118 if((Np=FirstNp) != NULL)while(Np != NULL){
00119 if((Op=Np->fobj) != NULL)while(Op != NULL){
00120 if((CurrentFrame >= Op->firstframe) && (CurrentFrame <= Op->lastframe)){
00121 GetTransform(0,CurrentFrame,1.0,Np,Op,Offset,TrackedOffset,&phi,&theta,&alpha,
00122 &sx,&sy,&sz,&im,&ima);
00123 if(Op->type == NORMAL || Op->type == ANIMOBJ){
00124 for(i=0;i<8;i++){
00125 srpoints[i][0] = (long)((double)Op->outline[i][0])*sx;
00126 srpoints[i][1] = (long)((double)Op->outline[i][1])*sy;
00127 srpoints[i][2] = (long)((double)Op->outline[i][2])*sz;
00128 }
00129 Transform(8,srpoints,trpoints,Offset,phi,theta,alpha,im,ima);
00130 for(i=0;i<8;i++){
00131 if(trpoints[i][0] < xmin)xmin=trpoints[i][0];
00132 if(trpoints[i][0] > xmax)xmax=trpoints[i][0];
00133 if(trpoints[i][1] < ymin)ymin=trpoints[i][1];
00134 if(trpoints[i][1] > ymax)ymax=trpoints[i][1];
00135 if(trpoints[i][2] < zmin)zmin=trpoints[i][2];
00136 if(trpoints[i][2] > zmax)zmax=trpoints[i][2];
00137 }
00138 }
00139 else if(Op->type == ROBOT){
00140 if(Op->nskeleton > 0 && Op->skeleton != NULL){
00141 double t1[4][4],x,y,z;
00142 RobotTransform(Offset,phi,theta,alpha,sx,sy,sz,im,ima,t1);
00143 for(i=0;i<Op->nskeleton;i++){
00144 m4by1(t1,(double)(Op->skeleton+i)->p[0],
00145 (double)(Op->skeleton+i)->p[1],
00146 (double)(Op->skeleton+i)->p[2],&x,&y,&z);
00147 if(x < xmin)xmin=x;
00148 if(y > xmax)xmax=y;
00149 if(z < ymin)ymin=z;
00150 if(x > ymax)ymax=x;
00151 if(y < zmin)zmin=y;
00152 if(z > zmax)zmax=z;
00153 }
00154 }
00155 }
00156 else if(Op->type == PATH){
00157 Pp=Op->firstpathpoint; while(Pp != NULL){
00158 CopyPoint(Pp->p,srpoints[0]);
00159 Transform(1,srpoints,trpoints,Offset,phi,theta,alpha,im,ima);
00160 if(trpoints[0][0] < xmin)xmin=trpoints[0][0];
00161 if(trpoints[0][0] > xmax)xmax=trpoints[0][0];
00162 if(trpoints[0][1] < ymin)ymin=trpoints[0][1];
00163 if(trpoints[0][1] > ymax)ymax=trpoints[0][1];
00164 if(trpoints[0][2] < zmin)zmin=trpoints[0][2];
00165 if(trpoints[0][2] > zmax)zmax=trpoints[0][2];
00166 Pp=Pp->next;
00167 }
00168 }
00169 else{
00170 if(Offset[0] < xmin)xmin=Offset[0];
00171 if(Offset[0] > xmax)xmax=Offset[0];
00172 if(Offset[1] < ymin)ymin=Offset[1];
00173 if(Offset[1] > ymax)ymax=Offset[1];
00174 if(Offset[2] < zmin)zmin=Offset[2];
00175 if(Offset[2] > zmax)zmax=Offset[2];
00176 }
00177 }
00178 Op=Op->next;
00179 }
00180 Np=Np->next;
00181 }
00182 p[0]=(xmax+xmin)/2; p[1]=(ymax+ymin)/2; p[2]=(zmax+zmin)/2;
00183 d=max(labs(xmax-xmin),labs(ymax-ymin)); d=max(d,labs(zmax-zmin));
00184 TVclipMin[0]=xmin;TVclipMin[1]=ymin;TVclipMin[2]=zmin;
00185 TVclipMax[0]=xmax;TVclipMax[1]=ymax;TVclipMax[2]=zmax;
00186 d=max(d,UNIT); d=min(d,MAXUNIT); d = d+d*0.3; d /= 2;
00187 TVp[0]=p[0]-d; TVp[1]=p[1]-d; TVp[2]=p[2]-d;
00188 }
00189
00190 void Transform(long n ,point Ain[], point Aout[], point Offset,
00191 double p, double t, double a, short im, double ima){
00192 long i;
00193 double tr1[4][4],tr2[4][4],tr3[4][4],trpos[4][4],x,y,z;
00194 if(im > 0){
00195 if (im == 1)rotz(tr1,ima*PIo180);
00196 else if(im == 2)rotx(tr1,ima*PIo180);
00197 else if(im == 3)roty(tr1,ima*PIo180);
00198 roty(tr3,t*PI/180.0);
00199 m4by4(tr3,tr1,tr2);
00200 }
00201 else roty(tr2,t*PIo180);
00202 rotx(tr3,a*PIo180);
00203 m4by4(tr3,tr2,tr1);
00204 rotz(tr2,p*PIo180);
00205 m4by4(tr2,tr1,trpos);
00206 for(i=0;i<n;i++){
00207 m4by1(trpos,(double)Ain[i][0],(double)Ain[i][1],(double)Ain[i][2],&x,&y,&z);
00208 Aout[i][0]=(long)x; Aout[i][1]=(long)y; Aout[i][2]=(long)z;
00209 AddPoints(Aout[i],Offset,Aout[i]);
00210 }
00211 }
00212
00213 static void GetInternalMotion(align *Ap, long frame, double dframe,
00214 short *im, double *ima){
00215 double ratio,dp;
00216 *im = Ap->im;
00217 if(Ap->firstframe == Ap->lastframe){
00218 *ima=0.0;
00219 }
00220 else{
00221 ratio=((double)frame+dframe - (double)Ap->firstframe)
00222 /(double)(Ap->lastframe+1 - Ap->firstframe);
00223 dp = 360.0*ratio*Ap->ima ;
00224 if(dp < -180.0)dp += 360.0;
00225 if(dp > 180.0)dp -= 360.0;
00226 *ima = dp;
00227 }
00228 }
00229
00230 void CalculateDirection(point C, point T, double * phi,
00231 double * theta, double * alpha){
00232 double dx,dy,dz,dxy;
00233 *phi=0; *theta=0; *alpha=0;
00234 dx=(double)(T[0]-C[0]);
00235 dy=(double)(T[1]-C[1]);
00236 dz=(double)(T[2]-C[2]);
00237 dxy=sqrt(dx*dx+dy*dy);
00238 if(dxy < 1.0e-10)return;
00239 *phi=asin(dy/dxy);
00240 if(dx < 0.0){*phi = PI - *phi; if(*phi > PI) *phi = *phi-2*PI;}
00241 *alpha=asin(dz/sqrt(dx*dx+dy*dy+dz*dz));
00242 *phi *= 180.0/PI;
00243 *phi -= 90.0;
00244 *alpha *= 180.0/PI;
00245 return;
00246 }
00247
00248 static void CalculateOffset(node *Np,long frame, double dframe,
00249 point dp, double sx,
00250 double sy, double sz){
00251 object *Op;
00252 double mr;
00253 dp[0]=dp[1]=dp[2]=0;
00254 if((Op=Np->fobj) != NULL)while(Op != NULL){
00255 if((frame >= Op->firstframe) && (frame <= Op->lastframe)){
00256 if(Op->morph != NO && Op->last != NULL){
00257 mr=(double)(Op->lastframe - Op->firstframe+1);
00258 mr=((double)frame + dframe - (double)Op->firstframe)/mr;
00259 dp[0] = (long)((double)(Op->offset[0] -
00260 Op->last->offset[0])*mr + Op->last->offset[0])*sx;
00261 dp[1] = (long)((double)(Op->offset[1] -
00262 Op->last->offset[1])*mr + Op->last->offset[1])*sy;
00263 dp[2] = (long)((double)(Op->offset[2] -
00264 Op->last->offset[2])*mr + Op->last->offset[2])*sz;
00265 }
00266 else{
00267 dp[0] = (long)(Op->offset[0] * sx);
00268 dp[1] = (long)(Op->offset[1] * sy);
00269 dp[2] = (long)(Op->offset[2] * sz);
00270 }
00271 return;
00272 }
00273 Op=Op->next;
00274 }
00275 }
00276
00277 static void CalculateSize(node *Np, long frame, double dframe,
00278 double *sx, double *sy, double *sz){
00279 size *Xp;
00280 double lsx,lsy,lsz,nsx,nsy,nsz,ratio;
00281 double kx[4],ky[4],kz[4];
00282 if((Xp=Np->fsiz) != NULL)while(Xp != NULL){
00283 if(frame >= Xp->firstframe && frame <= Xp->lastframe){
00284 if(Xp->last == NULL){
00285 *sx=Xp->Sx; *sy=Xp->Sy; *sz=Xp->Sz;
00286 }
00287 else{
00288 ratio=((double)frame+dframe - (double)Xp->firstframe)
00289 /(double)(Xp->lastframe+1 - Xp->firstframe);
00290 if(Xp->last->last == NULL ||
00291 (Xp->last->lastframe - Xp->last->firstframe) == 0){
00292 lsx = lsy = lsz = 0.0;
00293 }
00294 else{
00295 lsx=Xp->last->Sx - Xp->last->last->Sx;
00296 lsy=Xp->last->Sy - Xp->last->last->Sy;
00297 lsz=Xp->last->Sz - Xp->last->last->Sz;
00298 }
00299 if(Xp->next == NULL ||
00300 (Xp->next->lastframe - Xp->next->firstframe) == 0){
00301 nsx = nsy = nsz = 0.0;
00302 }
00303 else{
00304 nsx=Xp->next->Sx - Xp->Sx;
00305 nsy=Xp->next->Sy - Xp->Sy;
00306 nsz=Xp->next->Sz - Xp->Sz;
00307 }
00308 SplinesG(kx,Xp->last->Sx,Xp->Sx,lsx,nsx);
00309 SplinesG(ky,Xp->last->Sy,Xp->Sy,lsy,nsy);
00310 SplinesG(kz,Xp->last->Sz,Xp->Sz,lsz,nsz);
00311 *sx = SplinesR(kx,ratio);
00312 *sy = SplinesR(ky,ratio);
00313 *sz = SplinesR(kz,ratio);
00314 }
00315 break;
00316 }
00317 Xp=Xp->next;
00318 }
00319 }
00320
00321 cameraparam *CalculateCameraProperties(node *Np, long frame, double dframe){
00322
00323 size *Xp;
00324 static cameraparam cc;
00325 double ratio;
00326 if((Xp=Np->fsiz) != NULL)while(Xp != NULL){
00327 if(frame >= Xp->firstframe && frame <= Xp->lastframe){
00328 if(Xp->last == NULL){
00329 return &(Xp->camera_params);
00330 }
00331 else{
00332 ratio=((double)frame+dframe - (double)Xp->firstframe)
00333 /(double)(Xp->lastframe+1 - Xp->firstframe);
00334 memcpy(&cc,&(Xp->camera_params),sizeof(cameraparam));
00335 cc.f_number=(Xp->camera_params.f_number - Xp->last->camera_params.f_number)*ratio + Xp->last->camera_params.f_number;
00336 cc.focal_length=(Xp->camera_params.focal_length - Xp->last->camera_params.focal_length)*ratio + Xp->last->camera_params.focal_length;
00337 cc.focus_distance=(Xp->camera_params.focus_distance - Xp->last->camera_params.focus_distance)*ratio + Xp->last->camera_params.focus_distance;
00338 cc.stereo_separation=(Xp->camera_params.stereo_separation - Xp->last->camera_params.stereo_separation)*ratio + Xp->last->camera_params.stereo_separation;
00339 cc.parallax_distance=(Xp->camera_params.parallax_distance - Xp->last->camera_params.parallax_distance)*ratio + Xp->last->camera_params.parallax_distance;
00340
00341 return &(cc);
00342 }
00343 }
00344 Xp=Xp->next;
00345 }
00346 return NULL;
00347 }
00348
00349
00350
00351 static double GetFollowOnOffset(node *Np, long frame, double dframe,
00352 point Offset){
00353 position *Pp;
00354 object *Op;
00355 node *Npo,*Npi;
00356 point p,RelativeOffset;
00357 long follow_count=0;
00358 double sx=1.0,sy=1.0,sz=1.0,displacement=0.0,ratio = -1.0,length_on_path;
00359 Offset[0]=Offset[1]=Offset[2]=0; Npi=Np;
00360 while(Np != NULL){
00361 if(follow_count++ > 64){
00362 SendPrgmQuery(IDQ_SELFFOLLOW1,0);
00363 SendPrgmQuery(IDQ_SELFFOLLOW2,0);
00364 Pp=Npi->fpos;
00365 if(Pp != NULL)while(Pp != NULL){
00366 Pp->type=TWEEN;
00367 Pp=Pp->next;
00368 }
00369 return 0.0;
00370 }
00371 Pp=Np->fpos; Npo=Np; Np=NULL;
00372 if(Pp != NULL)while(Pp != NULL){
00373 if((frame >= Pp->firstframe) && (frame <= Pp->lastframe)){
00374 if(Pp->type == FOLLOWON){
00375 CalculateSize(Npo,frame,dframe,&sx,&sy,&sz);
00376 CalculateOffset(Npo,frame,dframe,p,sx,sy,sz);
00377 displacement += p[1];
00378 Np=Pp->onpath;
00379 break;
00380 }
00381 else if(Pp->type == FOLLOW && Pp->onpath != NULL &&
00382 Pp->onpath->type == PATH){
00383 CalculateSize(Npo,frame,dframe,&sx,&sy,&sz);
00384 CalculateOffset(Npo,frame,dframe,p,sx,sy,sz);
00385 displacement += p[1];
00386 ratio = -1.0;
00387 if((Op=GetPathPosition(Pp->onpath,frame,dframe,RelativeOffset,
00388 &ratio,&length_on_path)) != NULL){
00389 length_on_path += displacement;
00390 if(length_on_path > 0.0){
00391 if(length_on_path >= Op->pathlength){
00392 if(Op->pathtype == CLOSED){
00393 ratio = (length_on_path-Op->pathlength)/Op->pathlength;
00394 }
00395 else ratio = 0.99;
00396 }
00397 else ratio = length_on_path/Op->pathlength;
00398 }
00399 else if(Op->pathtype == CLOSED){
00400 ratio = (Op->pathlength+length_on_path)/Op->pathlength;
00401 }
00402 else ratio = 0.0;
00403 if(ratio >= 0.0){
00404 if((Op=GetPathPosition(Pp->onpath,frame,dframe,RelativeOffset,
00405 &ratio,&length_on_path)) != NULL){
00406 AddPoints(Offset,RelativeOffset,Offset);
00407 GetOffsetPosition(Pp->onpath,Op,frame,dframe,Offset);
00408 }
00409 }
00410 }
00411 }
00412
00413 }
00414 Pp=Pp->next;
00415 }
00416 }
00417 return ratio;
00418 }
00419
00420 double GetOffsetPosition(node *Np, object *Op,
00421 long frame, double dframe,
00422 point ObjectOffset){
00423 position *Pp;
00424 point dp,RelativeOffset,TrackedOffset,spl,spn,ofs;
00425 double ratio,kx[4],ky[4],kz[4],rp,ra,rt,rsx,rsy,rsz,rima,
00426 length_on_path,gs,ge;
00427 short rim;
00428 stackdepth++;
00429 ratio=0.0;
00430 if(Np == NULL)return(0.0);
00431 if(stackdepth > 64)longjmp(r_buf,-1);
00432 if((Pp=Np->fpos) != NULL)while(Pp != NULL){
00433 if((frame >= Pp->firstframe) && (frame <= Pp->lastframe)){
00434 if(Pp->type == TWEEN){
00435 if((Pp->last == NULL))
00436 AddPoints(ObjectOffset,Pp->finish,ObjectOffset);
00437 else{
00438 ratio=((double)frame+dframe - (double)Pp->firstframe)
00439 /(double)(Pp->lastframe+1 - Pp->firstframe);
00440 SubPoints(Pp->finish,Pp->last->finish,dp);
00441 ScalePoint(ratio,ratio,ratio,dp,dp);
00442 AddPoints(Pp->last->finish,dp,dp);
00443 AddPoints(ObjectOffset,dp,ObjectOffset);
00444 }
00445 }
00446 else if(Pp->type == FOLLOW || Pp->type == FOLLOWAT){
00447 if(Pp->type == FOLLOWAT)CopyPoint(ObjectOffset,ofs);
00448 if(Pp->onpath->type == PATH){
00449 ratio = -1.0;
00450 if(GetPathPosition(Pp->onpath,frame,dframe,RelativeOffset,&ratio,
00451 &length_on_path) != NULL){
00452 AddPoints(ObjectOffset,RelativeOffset,ObjectOffset);
00453 GetOffsetPosition(Pp->onpath,Op,frame,dframe,ObjectOffset);
00454 }
00455 }
00456 else ratio=GetOffsetPosition(Pp->onpath,Op,frame,dframe,ObjectOffset);
00457 if(Pp->type == FOLLOWAT){
00458 if((Pp->last == NULL)){
00459 if((!Pp->fx))ObjectOffset[0]=ofs[0]+Pp->finish[0];
00460 if((!Pp->fy))ObjectOffset[1]=ofs[1]+Pp->finish[1];
00461 if((!Pp->fz))ObjectOffset[2]=ofs[2]+Pp->finish[2];
00462 }
00463 else{
00464 ratio=((double)frame+dframe - (double)Pp->firstframe)
00465 /(double)(Pp->lastframe+1 - Pp->firstframe);
00466 SubPoints(Pp->finish,Pp->last->finish,dp);
00467 ScalePoint(ratio,ratio,ratio,dp,dp);
00468 AddPoints(Pp->last->finish,dp,dp);
00469 if(!(Pp->fx))ObjectOffset[0]=ofs[0]+dp[0];
00470 if(!(Pp->fy))ObjectOffset[1]=ofs[1]+dp[1];
00471 if(!(Pp->fz))ObjectOffset[2]=ofs[2]+dp[2];
00472 }
00473 }
00474 }
00475 else if(Pp->type == FOLLOWOFF){
00476 GetTransform(1,frame,dframe,
00477 Pp->onpath,NULL,ObjectOffset,TrackedOffset,
00478 &rp,&rt,&ra,&rsx,&rsy,&rsz,&rim,&rima);
00479 CalculateOffset(Pp->onpath,frame,dframe,trpoints[0],rsx,rsy,rsz);
00480 Transform(1,trpoints,srpoints,ObjectOffset,rp,rt,ra,rim,rima);
00481 CopyPoint(srpoints[0],ObjectOffset);
00482 }
00483 else if(Pp->type == FOLLOWON){
00484 ratio=GetFollowOnOffset(Pp->onpath,frame,dframe,ObjectOffset);
00485 }
00486 else if(Pp->type == SPLINE){
00487 if((Pp->last == NULL))
00488 AddPoints(ObjectOffset,Pp->finish,ObjectOffset);
00489 else{
00490 ratio=((double)frame+dframe - (double)Pp->firstframe)
00491 /(double)(Pp->lastframe+1 - Pp->firstframe);
00492 if(Pp->last->last != NULL)CopyPoint(Pp->last->last->finish,spl);
00493 else{
00494 SubPoints(Pp->finish,Pp->last->finish,dp);
00495 SubPoints(Pp->last->finish,dp,spl);
00496 }
00497 if(Pp->next != NULL)CopyPoint(Pp->next->finish,spn);
00498 else{
00499 SubPoints(Pp->finish,Pp->last->finish,dp);
00500 AddPoints(Pp->finish,dp,spn);
00501 }
00502
00503
00504
00505 gs=(double)(Pp->finish[0]-spl[0])*Pp->tension_s;
00506 ge=(double)(spn[0]-Pp->last->finish[0])*Pp->tension_e;
00507 SplinesG(kx,Pp->last->finish[0],Pp->finish[0],gs,ge);
00508 gs=(double)(Pp->finish[1]-spl[1])*Pp->tension_s;
00509 ge=(double)(spn[1]-Pp->last->finish[1])*Pp->tension_e;
00510 SplinesG(ky,Pp->last->finish[1],Pp->finish[1],gs,ge);
00511 gs=(double)(Pp->finish[2]-spl[2])*Pp->tension_s;
00512 ge=(double)(spn[2]-Pp->last->finish[2])*Pp->tension_e;
00513 SplinesG(kz,Pp->last->finish[2],Pp->finish[2],gs,ge);
00514 ObjectOffset[0] += SplinesP(kx,ratio);
00515 ObjectOffset[1] += SplinesP(ky,ratio);
00516 ObjectOffset[2] += SplinesP(kz,ratio);
00517 }
00518 }
00519 }
00520 Pp=Pp->next;
00521 }
00522 return ratio;
00523 }
00524
00525 short GetTransform(short stacking, long frame, double dframe,
00526 node *Np, object *Op,
00527 point ObjectOffset, point TrackedOffset,
00528 double *phi, double *theta, double *alpha,
00529 double *sx, double *sy, double *sz,
00530 short *im, double *ima){
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543 point TrackedDummy,TrackedOrigin;
00544 align *Ap;
00545 size *Xp;
00546 short rim;
00547 double dp,dpl,dpn,ratio,rsx,rsy,rsz,rima,length_on_path;
00548 double kx[4],ky[4],kz[4];
00549 long f,ddt;
00550 if(Np == NULL)return TWEEN;
00551 ObjectOffset[0]=0; ObjectOffset[1]=0; ObjectOffset[2]=0;
00552 TrackedOffset[0]=0; TrackedOffset[1]=0; TrackedOffset[2]=0;
00553 *phi=0; *theta=0; *alpha=0;
00554 if(Np->type == LIGHT){*sx=15.0; *sy=5.0;}
00555 else {*sx=1.0; *sy=1.0;}
00556 *sz=1.0; *im=0; *ima=0.0;
00557 if(stacking == 0)stackdepth=0;
00558 if(stackdepth > 64)longjmp(r_buf,-1);
00559
00560 CalculateSize(Np,frame,dframe,sx,sy,sz);
00561
00562 if((Ap=Np->fali) != NULL){
00563 while(Ap != NULL){
00564 if(frame >= Ap->firstframe && frame <= Ap->lastframe){
00565 GetInternalMotion(Ap,frame,dframe,im,ima);
00566 if(Ap->type == TRACK ){
00567 GetOffsetPosition(Ap->topath,Op,frame,dframe,TrackedOffset);
00568 GetOffsetPosition(Np,Op,frame,dframe,ObjectOffset);
00569 CalculateDirection(ObjectOffset,TrackedOffset,phi,theta,alpha);
00570 if((Ap->last == NULL)){
00571 *theta = Ap->theta;
00572 }
00573 else{
00574 ratio=((double)frame+dframe - (double)Ap->firstframe)
00575 /(double)(Ap->lastframe+1 - Ap->firstframe);
00576 dp = Ap->theta - Ap->last->theta;
00577 if(dp < -180.0)dp += 360.0;
00578 if(dp > 180.0)dp -= 360.0;
00579 dp *= ratio;
00580 dp += Ap->last->theta;
00581 if(dp < -180.0)dp += 360.0;
00582 if(dp > 180.0)dp -= 360.0;
00583 *theta = dp;
00584 }
00585 }
00586 else if(Ap->type == COPY){
00587 stackdepth++;
00588 GetTransform(1,frame,dframe,
00589 Ap->topath,NULL,TrackedOffset,TrackedDummy,
00590 phi,theta,alpha,&rsx,&rsy,&rsz,&rim,&rima);
00591 GetOffsetPosition(Np,Op,frame,dframe,ObjectOffset);
00592 }
00593 else if(Ap->type == TOPATH){
00594 ratio=GetOffsetPosition(Np,Op,frame,dframe,ObjectOffset);
00595 if(Ap->topath->type == PATH && ratio > -1.5){
00596 if(GetPathPosition(Ap->topath,frame,dframe,TrackedOrigin,&ratio,
00597 &length_on_path) != NULL){
00598 if(ratio < 1.0){
00599 ratio=min(ratio+0.01,1.0);
00600 GetPathPosition(Ap->topath,frame,dframe,TrackedOffset,
00601 &ratio,&length_on_path);
00602 }
00603 else{
00604 ratio -= 0.1;
00605 GetPathPosition(Ap->topath,frame,dframe,TrackedOffset,
00606 &ratio,&length_on_path);
00607 SubPoints(TrackedOrigin,TrackedOffset,TrackedOffset);
00608 AddPoints(TrackedOrigin,TrackedOffset,TrackedOffset);
00609 }
00610 CalculateDirection(TrackedOrigin,TrackedOffset,phi,theta,alpha);
00611 }
00612 else{*phi=0; *alpha=0; *theta=0;}
00613 }
00614 else{
00615 *phi=0; *alpha=0; *theta=0;
00616 }
00617 if((Ap->last == NULL)){
00618 *theta = Ap->theta;
00619 }
00620 else{
00621 ratio=((double)frame+dframe - (double)Ap->firstframe)
00622 /(double)(Ap->lastframe+1 - Ap->firstframe);
00623 dp = Ap->theta - Ap->last->theta;
00624 if(dp < -180.0)dp += 360.0;
00625 if(dp > 180.0)dp -= 360.0;
00626 dp *= ratio;
00627 dp += Ap->last->theta;
00628 if(dp < -180.0)dp += 360.0;
00629 if(dp > 180.0)dp -= 360.0;
00630 *theta = dp;
00631 }
00632 }
00633 else if(Ap->type == TWEEN){
00634 if((Ap->last == NULL)){
00635 *phi=Ap->phi;
00636 *theta=Ap->theta;
00637 *alpha=Ap->alpha;
00638 }
00639 else{
00640 ratio=((double)frame+dframe - (double)Ap->firstframe)
00641 /(double)(Ap->lastframe+1 - Ap->firstframe);
00642 dp = Ap->phi - Ap->last->phi;
00643 if(dp < -180.0)dp += 360.0;
00644 if(dp > 180.0)dp -= 360.0;
00645 dp *= ratio;
00646 dp += Ap->last->phi;
00647 if(dp < -180.0)dp += 360.0;
00648 if(dp > 180.0)dp -= 360.0;
00649 *phi = dp;
00650 dp = Ap->theta - Ap->last->theta;
00651 if(dp < -180.0)dp += 360.0;
00652 if(dp > 180.0)dp -= 360.0;
00653 dp *= ratio;
00654 dp += Ap->last->theta;
00655 if(dp < -180.0)dp += 360.0;
00656 if(dp > 180.0)dp -= 360.0;
00657 *theta = dp;
00658 dp = Ap->alpha - Ap->last->alpha;
00659 if(dp < -180.0)dp += 360.0;
00660 if(dp > 180.0)dp -= 360.0;
00661 dp *= ratio;
00662 dp += Ap->last->alpha;
00663 if(dp < -180.0)dp += 360.0;
00664 if(dp > 180.0)dp -= 360.0;
00665 *alpha = dp;
00666 }
00667 GetOffsetPosition(Np,Op,frame,dframe,ObjectOffset);
00668 }
00669 else if(Ap->type == SPLINEA){
00670 if((Ap->last == NULL)){
00671 *phi=Ap->phi;
00672 *theta=Ap->theta;
00673 *alpha=Ap->alpha;
00674 }
00675 else{
00676 ratio=((double)frame+dframe - (double)Ap->firstframe)
00677 /(double)(Ap->lastframe+1 - Ap->firstframe);
00678 dp = Ap->phi - Ap->last->phi;
00679 if(dp < -180.0)dp += 360.0;
00680 if(dp > 180.0)dp -= 360.0;
00681 if(Ap->last->last == NULL)dpl=0.0;
00682 else{
00683 dpl = Ap->last->phi - Ap->last->last->phi;
00684 if(dpl < -180.0)dpl += 360.0;
00685 if(dpl > 180.0)dpl -= 360.0;
00686 ddt = Ap->last->lastframe - Ap->last->firstframe;
00687 if(ddt == 0)dpl=0.0;
00688 }
00689 if(Ap->next == NULL)dpn=0.0;
00690 else{
00691 dpn = Ap->next->phi - Ap->phi;
00692 if(dpn < -180.0)dpn += 360.0;
00693 if(dpn > 180.0)dpn -= 360.0;
00694 ddt = Ap->next->lastframe - Ap->next->firstframe;
00695 if(ddt == 0)dpn=0.0;
00696 }
00697 SplinesG(kx,Ap->last->phi,Ap->last->phi+dp,dpl,dpn);
00698 dp=SplinesR(kx,ratio);
00699 if(dp < -180.0)dp += 360.0;
00700 if(dp > 180.0)dp -= 360.0;
00701 *phi = dp;
00702 dp = Ap->theta - Ap->last->theta;
00703 if(dp < -180.0)dp += 360.0;
00704 if(dp > 180.0)dp -= 360.0;
00705 if(Ap->last->last == NULL)dpl=0.0;
00706 else{
00707 dpl = Ap->last->theta - Ap->last->last->theta;
00708 if(dpl < -180.0)dpl += 360.0;
00709 if(dpl > 180.0)dpl -= 360.0;
00710 ddt = Ap->last->lastframe - Ap->last->firstframe;
00711 if(ddt == 0)dpl=0.0;
00712 }
00713 if(Ap->next == NULL)dpn=0.0;
00714 else{
00715 dpn = Ap->next->theta - Ap->theta;
00716 if(dpn < -180.0)dpn += 360.0;
00717 if(dpn > 180.0)dpn -= 360.0;
00718 ddt = Ap->next->lastframe - Ap->next->firstframe;
00719 if(ddt == 0)dpn=0.0;
00720 }
00721 SplinesG(kx,Ap->last->theta,Ap->last->theta+dp,dpl,dpn);
00722 dp=SplinesR(kx,ratio);
00723 if(dp < -180.0)dp += 360.0;
00724 if(dp > 180.0)dp -= 360.0;
00725 *theta = dp;
00726 dp = Ap->alpha - Ap->last->alpha;
00727 if(dp < -180.0)dp += 360.0;
00728 if(dp > 180.0)dp -= 360.0;
00729 if(Ap->last->last == NULL)dpl=0.0;
00730 else{
00731 dpl = Ap->last->alpha - Ap->last->last->alpha;
00732 if(dpl < -180.0)dpl += 360.0;
00733 if(dpl > 180.0)dpl -= 360.0;
00734 ddt = Ap->last->lastframe - Ap->last->firstframe;
00735 if(ddt == 0)dpl=0.0;
00736 }
00737 if(Ap->next == NULL)dpn=0.0;
00738 else{
00739 dpn = Ap->next->alpha - Ap->alpha;
00740 if(dpn < -180.0)dpn += 360.0;
00741 if(dpn > 180.0)dpn -= 360.0;
00742 ddt = Ap->next->lastframe - Ap->next->firstframe;
00743 if(ddt == 0)dpn=0.0;
00744 }
00745 SplinesG(kx,Ap->last->alpha,Ap->last->alpha+dp,dpl,dpn);
00746 dp=SplinesR(kx,ratio);
00747 if(dp < -180.0)dp += 360.0;
00748 if(dp > 180.0)dp -= 360.0;
00749 *alpha = dp;
00750 }
00751 GetOffsetPosition(Np,Op,frame,dframe,ObjectOffset);
00752 }
00753 return Ap->type;
00754 }
00755 Ap=Ap->next;
00756 }
00757 GetOffsetPosition(Np,Op,frame,dframe,ObjectOffset);
00758 }
00759 else GetOffsetPosition(Np,Op,frame,dframe,ObjectOffset);
00760 return TWEEN;
00761 }
00762
00763
00764
00765
00766 void DrawActorCentre(HDC hdc[],point v1, double p, double t, double a,
00767 short im, double ima, double scale){
00768 int sh1,sv1,i;
00769 int ifd,ild;
00770 if(View == TRIVIEW){ifd=0;ild=3;}
00771 else {ifd=ActiveView; ild=ifd+1;}
00772 if(in_stage_triview(v1)){
00773 for(i=ifd;i<ild;i++){
00774 GetWindowCoords(i,v1[0],v1[1],v1[2],&sh1,&sv1);
00775 Rectangle(hdc[i],(int)sh1-2,(int)sv1-2,(int)sh1+2,(int)sv1+2);
00776 }
00777 }
00778 }
00779
00780 void DrawArrow(HDC hdc[], point Offset, double p, double t, double a,
00781 short im, double ima, double scale){
00782 int sh1,sv1,sh2,sv2,i;
00783 point v1,v2;
00784 point Lpointer[6];
00785 short ep;
00786 double s10;
00787 int ifd,ild;
00788 if(View == TRIVIEW){ifd=0;ild=3;}
00789 else {ifd=ActiveView; ild=ifd+1;}
00790 s10=scale/10.0;
00791 for(i=0;i<6;i++)ScalePoint(s10,s10,s10,Pointer[i],Lpointer[i]);
00792 Transform(6,Lpointer,trpoints,Offset,p,t,a,im,ima);
00793 for(ep=0;ep<5;ep++){
00794 CopyPoint(trpoints[pp1[ep]],v1);
00795 CopyPoint(trpoints[pp2[ep]],v2);
00796 if(in_stage_triview(v1) || in_stage_triview(v2)){
00797 for(i=ifd;i<ild;i++){
00798 GetWindowCoords(i,v1[0],v1[1],v1[2],&sh1,&sv1);
00799 GetWindowCoords(i,v2[0],v2[1],v2[2],&sh2,&sv2);
00800 MoveToEx(hdc[i],sh1,sv1,NULL); LineTo(hdc[i],sh2,sv2);
00801 }
00802 }
00803 }
00804 }
00805
00806 void DrawDirectionLine(HDC hdc[],
00807 point Offset,
00808 double p, double t, double a,
00809 short im, double ima, double scale){
00810 int sh1,sv1,sh2,sv2,i;
00811 point v1,v2;
00812 point Lpointer[2];
00813 short ep;
00814 double s10;
00815 int ifd,ild;
00816 if(View == TRIVIEW){ifd=0;ild=3;}
00817 else {ifd=ActiveView; ild=ifd+1;}
00818 s10=scale/10.0;
00819 for(i=0;i<2;i++)ScalePoint(s10,s10,s10,Pointer[i],Lpointer[i]);
00820 Transform(2,Lpointer,trpoints,Offset,p,t,a,im,ima);
00821 CopyPoint(trpoints[0],v1);
00822 CopyPoint(trpoints[1],v2);
00823 if(in_stage_triview(v1) || in_stage_triview(v2)){
00824 for(i=ifd;i<ild;i++){
00825 GetWindowCoords(i,v1[0],v1[1],v1[2],&sh1,&sv1);
00826 GetWindowCoords(i,v2[0],v2[1],v2[2],&sh2,&sv2);
00827 MoveToEx(hdc[i],sh1,sv1,NULL); LineTo(hdc[i],sh2,sv2);
00828 }
00829 }
00830 }
00831
00832 static short BV_id[3] ={1,2,0};
00833 static short TV_id[3] ={2,1,0};
00834 static short EV_id[6][4]={ 0, 1, 2, 3, 4, 5, 6, 7, 2, 6,10,11,
00835 0, 4, 8, 9, 1, 5, 9,10, 3, 7,11, 8};
00836 static short QF1[6]={0,4,3,0,2,0};
00837 static short QF2[6]={1,7,2,4,1,3};
00838 static short QF3[6]={0,4,3,0,2,3};
00839 static short QF4[6]={3,5,7,1,6,7};
00840
00841 #define CROSS(v1,v2,r) { \
00842 r[0] = (v1[1]*v2[2]) - (v2[1]*v1[2]); \
00843 r[1] = (v1[2]*v2[0]) - (v1[0]*v2[2]); \
00844 r[2] = (v1[0]*v2[1]) - (v2[0]*v1[1]); \
00845 }
00846
00847 static void DrawSolidBox(HDC hdc[]){
00848 int sh1,sv1,sh2,sv2,i,e,f,visi[12];
00849 double n[6][3],n1[3],n2[3];
00850 point v1,v2;
00851 int ifd,ild;
00852 if(View == TRIVIEW){ifd=0;ild=3;}
00853 else {ifd=ActiveView; ild=ifd+1;}
00854 for(f=0;f<6;f++){
00855 for(i=0;i<3;i++){
00856 n1[i]=(double)(trpoints[QF2[f]][i] - trpoints[QF1[f]][i]);
00857 n2[i]=(double)(trpoints[QF4[f]][i] - trpoints[QF3[f]][i]);
00858 }
00859 CROSS(n1,n2,n[f]);
00860 if(WindowBox_view == 0)n[f][1] = -n[f][1];
00861 }
00862 for(i=ifd;i<ild;i++){
00863 for(e=0;e<12;e++)visi[e]=0;
00864 for(f=0;f<6;f++)if(n[f][TV_id[i]] > 0.0){
00865 for(e=0;e<4;e++)visi[EV_id[f][e]]=1;
00866 }
00867 for(e=0;e<12;e++)if(visi[e]){
00868 CopyPoint(trpoints[ep1[e]],v1);
00869 CopyPoint(trpoints[ep2[e]],v2);
00870 if(in_stage_triview(v1) || in_stage_triview(v2)) {
00871 GetWindowCoords(i,v1[0],v1[1],v1[2],&sh1,&sv1);
00872 GetWindowCoords(i,v2[0],v2[1],v2[2],&sh2,&sv2);
00873 MoveToEx(hdc[i],sh1,sv1,NULL); LineTo(hdc[i],sh2,sv2);
00874 }
00875 }
00876 }
00877 }
00878
00879 static void DrawObject(HDC hdc[], object *Op,
00880 point Offset, double p,
00881 double t, double a, short im, double ima,
00882 double sx, double sy, double sz, short status){
00883 int sh1,sv1,sh2,sv2,i,ep;
00884 point v1,v2;
00885 double mr;
00886 int ifd,ild;
00887 if(View == TRIVIEW){ifd=0;ild=3;}
00888 else {ifd=ActiveView; ild=ifd+1;}
00889
00890
00891 if(status == SELECTED)DrawArrow(hdc,Offset,p,t,a,im,ima,TVsizeX/24);
00892 if(Op->w_frame.p != NULL){
00893 if(DrawQuickObject(hdc,Op,Offset,p,t,a,im,ima,sx,sy,sz,status) == OK)return;
00894 }
00895
00896
00897 if(Op->morph != NO && Op->last != NULL){
00898 mr=(double)(Op->lastframe - Op->firstframe+1);
00899 mr=(double)(CurrentFrame - Op->firstframe+1)/mr;
00900 for(i=0;i<8;i++){
00901 srpoints[i][0] = (long)((double)(Op->outline[i][0] -
00902 Op->last->outline[i][0])*mr + Op->last->outline[i][0])*sx;
00903 srpoints[i][1] = (long)((double)(Op->outline[i][1] -
00904 Op->last->outline[i][1])*mr + Op->last->outline[i][1])*sy;
00905 srpoints[i][2] = (long)((double)(Op->outline[i][2] -
00906 Op->last->outline[i][2])*mr + Op->last->outline[i][2])*sz;
00907 }
00908 }
00909 else{
00910 for(i=0;i<8;i++){
00911 srpoints[i][0] = (long)((double)Op->outline[i][0])*sx;
00912 srpoints[i][1] = (long)((double)Op->outline[i][1])*sy;
00913 srpoints[i][2] = (long)((double)Op->outline[i][2])*sz;
00914 }
00915 }
00916 Transform(8,srpoints,trpoints,Offset,p,t,a,im,ima);
00917
00918 if(status == SELECTED && tool != NOTOOL && tool != NODETOOL){
00919 DrawSolidBox(hdc);
00920 return;
00921 }
00922
00923 for(ep=0;ep<12;ep++){
00924 CopyPoint(trpoints[ep1[ep]],v1);
00925 CopyPoint(trpoints[ep2[ep]],v2);
00926 if(in_stage_triview(v1) || in_stage_triview(v2)) {
00927 for(i=ifd;i<ild;i++){
00928 GetWindowCoords(i,v1[0],v1[1],v1[2],&sh1,&sv1);
00929 GetWindowCoords(i,v2[0],v2[1],v2[2],&sh2,&sv2);
00930 MoveToEx(hdc[i],sh1,sv1,NULL); LineTo(hdc[i],sh2,sv2);
00931 }
00932 }
00933 }
00934 }
00935
00936 static short DrawNurbsObject(HDC hdc[], object *Op, point Offset
00937 , double p, double t, double a
00938 , short im, double ima
00939 , double sx, double sy, double sz, short status){
00940 vector4 *p1;
00941 nurbs *n;
00942 int sh1,sv1,sh2,sv2;
00943 point v1,v2,*Vp;
00944 long ii,jj,i,j,k,id1,id2,NP;
00945 double mr,w;
00946 int ifd,ild;
00947 if(View == TRIVIEW){ifd=0;ild=3;}
00948 else {ifd=ActiveView; ild=ifd+1;}
00949 if(Op->nNurbs == 0 || Op->Nurbs == NULL)return FAIL;
00950 for(k=0;k<Op->nNurbs;k++){
00951 n=(Op->Nurbs+k);
00952 if(n->properties.hidden)continue;
00953 if((Vp=(point *)X__Malloc((n->numU * n->numV)*sizeof(point))) == NULL)return FAIL;
00954 if(Op->morph != NO && Op->last != NULL && Op->last->Nurbs != NULL &&
00955 Op->nNurbs == Op->last->nNurbs){
00956 mr=(double)(Op->lastframe - Op->firstframe+1);
00957 mr=(double)(CurrentFrame - Op->firstframe+1)/mr;
00958 j=0;
00959 for(ii=0;ii<n->numV;ii++)
00960 for(jj=0;jj<n->numU;jj++){
00961 p1 = &(n->points[ii][jj]);
00962 w=1.0/p1->w;
00963 Vp[j][0]=(long)((p1->x)*w);
00964 Vp[j][1]=(long)((p1->y)*w);
00965 Vp[j][2]=(long)((p1->z)*w);
00966 Vp[j][0] = Vp[j][0]*sx;
00967 Vp[j][1] = Vp[j][1]*sy;
00968 Vp[j][2] = Vp[j][2]*sz;
00969 p1 = &((Op->last->Nurbs+k)->points[ii][jj]);
00970 w=1.0/p1->w;
00971 v1[0]=(long)((p1->x)*w);
00972 v1[1]=(long)((p1->y)*w);
00973 v1[2]=(long)((p1->z)*w);
00974 Vp[j][0] = (long)((double)(Vp[j][0] - v1[0])*mr + v1[0])*sx;
00975 Vp[j][1] = (long)((double)(Vp[j][1] - v1[1])*mr + v1[1])*sy;
00976 Vp[j][2] = (long)((double)(Vp[j][2] - v1[2])*mr + v1[2])*sz;
00977 j++;
00978 }
00979 }
00980 else{
00981 j=0;
00982 for(ii=0;ii<n->numV;ii++)
00983 for(jj=0;jj<n->numU;jj++){
00984 p1 = &(n->points[ii][jj]);
00985 w=1.0/p1->w;
00986 Vp[j][0]=(long)((p1->x)*w);
00987 Vp[j][1]=(long)((p1->y)*w);
00988 Vp[j][2]=(long)((p1->z)*w);
00989 Vp[j][0] = Vp[j][0]*sx;
00990 Vp[j][1] = Vp[j][1]*sy;
00991 Vp[j][2] = Vp[j][2]*sz;
00992 j++;
00993 }
00994 }
00995 Transform((long)(n->numU * n->numV),Vp,Vp,Offset,p,t,a,im,ima);
00996
00997 for(ii=0;ii<n->numV;ii++)
00998 for(jj=0;jj<n->numU-1;jj++){
00999 id1=(ii*(n->numU)+jj);
01000 id2=(ii*(n->numU)+jj+1);
01001 CopyPoint(Vp[id1],v1);
01002 CopyPoint(Vp[id2],v2);
01003 if(in_stage_triview(v1) || in_stage_triview(v2)){
01004 for(i=ifd;i<ild;i++){
01005 GetWindowCoords(i,v1[0],v1[1],v1[2],&sh1,&sv1);
01006 GetWindowCoords(i,v2[0],v2[1],v2[2],&sh2,&sv2);
01007 MoveToEx(hdc[i],sh1,sv1,NULL); LineTo(hdc[i],sh2,sv2);
01008 }
01009 }
01010 }
01011 for(jj=0;jj<n->numU;jj++)
01012 for(ii=0;ii<n->numV-1;ii++){
01013 id1=(ii*(n->numU)+jj);
01014 id2=((ii+1)*(n->numU)+jj);
01015 CopyPoint(Vp[id1],v1);
01016 CopyPoint(Vp[id2],v2);
01017 if(in_stage_triview(v1) || in_stage_triview(v2)){
01018 for(i=ifd;i<ild;i++){
01019 GetWindowCoords(i,v1[0],v1[1],v1[2],&sh1,&sv1);
01020 GetWindowCoords(i,v2[0],v2[1],v2[2],&sh2,&sv2);
01021 MoveToEx(hdc[i],sh1,sv1,NULL); LineTo(hdc[i],sh2,sv2);
01022 }
01023 }
01024 }
01025 X__Free(Vp);
01026 }
01027 return OK;
01028 }
01029
01030 static void DrawRect(HDC hdc[],point Offset, double p, double t, double a,
01031 short im, double ima, double scalex, double scaley){
01032 int sh1,sv1,sh2,sv2,i;
01033 point v1,v2;
01034 point Lpointer[4];
01035 short ep;
01036 int ifd,ild;
01037 if(View == TRIVIEW){ifd=0;ild=3;}
01038 else {ifd=ActiveView; ild=ifd+1;}
01039 for(i=0;i<4;i++)ScalePoint(scalex,scaley,1.0,Rectang[i],Lpointer[i]);
01040 Transform(4,Lpointer,trpoints,Offset,p,t,a,im,ima);
01041 for(ep=0;ep<4;ep++){
01042 CopyPoint(trpoints[rp1[ep]],v1);
01043 CopyPoint(trpoints[rp2[ep]],v2);
01044 if(in_stage_triview(v1) || in_stage_triview(v2)){
01045 for(i=ifd;i<ild;i++){
01046 GetWindowCoords(i,v1[0],v1[1],v1[2],&sh1,&sv1);
01047 GetWindowCoords(i,v2[0],v2[1],v2[2],&sh2,&sv2);
01048 MoveToEx(hdc[i],sh1,sv1,NULL); LineTo(hdc[i],sh2,sv2);
01049 }
01050 }
01051 }
01052 }
01053
01054 static void DrawGround(HDC hdc[], point v1
01055 ,double p, double t, double a, short im
01056 ,double ima, short status, double scalex, double scaley
01057 ,double scalez){
01058 RECT rc;
01059 int sh1,sv1,i;
01060 int ifd,ild;
01061 if(View == TRIVIEW){ifd=0;ild=3;}
01062 else {ifd=ActiveView; ild=ifd+1;}
01063 if(status == DESELECTED)
01064 DrawActorCentre(hdc,v1,p,t,a,im,ima,TVsizeX/24);
01065
01066
01067 if(status == SELECTED)
01068 DrawRect(hdc,v1,p,0.0,0.0,im,ima,scalex,scaley);
01069 for(i=ifd;i<ild;i++)if(i != TRITOP){
01070 GetWindowCoords(i,v1[0],v1[1],v1[2],&sh1,&sv1);
01071 MoveToEx(hdc[i],0,sv1,NULL);
01072 GetClientRect(ghwnd_triview[i],&rc);
01073 LineTo(hdc[i],rc.right+1,sv1);
01074 if(status == SELECTED){
01075 MoveToEx(hdc[i],sh1,sv1,NULL);
01076 GetWindowCoords(i,v1[0],v1[1],v1[2]+(long)(UNIT*2*scalez),&sh1,&sv1);
01077 LineTo(hdc[i],sh1,sv1);
01078 }
01079 }
01080 }
01081
01082 static void DrawActorBitmap(HDC hdc[], point v1,
01083 double p, double t, double a, short im, double ima,
01084 short status, short what_icon){
01085 int sh1,sv1,i,c;
01086 HDC hMemDC;
01087 HBITMAP hbmOld;
01088 HBRUSH holdbrush;
01089 int ifd,ild;
01090 if(View == TRIVIEW){ifd=0;ild=3;}
01091 else {ifd=ActiveView; ild=ifd+1;}
01092 if(ghCameraBitmap == NULL || ghLightBitmap == NULL)return;
01093 for(i=ifd;i<ild;i++){
01094 hMemDC = CreateCompatibleDC(hdc[i]);
01095 GetWindowCoords(i,v1[0],v1[1],v1[2],&sh1,&sv1);
01096 if(what_icon == 0){
01097 hbmOld = SelectObject(hMemDC,ghCameraBitmap); c=32;
01098 }
01099 else if(what_icon == 1){
01100 hbmOld = SelectObject(hMemDC,ghLightBitmap); c=16;
01101 }
01102 if(tool != NOTOOL && tool != NODETOOL &&
01103 tool != PAN && tool != INZOOM && status == SELECTED){
01104 BitBlt(hdc[i],sh1-c/2,sv1-16,c,16,hMemDC,0,0,SRCINVERT);
01105 }
01106 else{
01107 BitBlt(hdc[i],sh1-c/2,sv1-16,c,16,hMemDC,0,0,0x00220326);
01108 if(status == SELECTED)holdbrush=SelectObject(hdc[i],ghSelectedBrush);
01109 else holdbrush=SelectObject(hdc[i],ghDeselectedBrush);
01110 BitBlt(hdc[i],sh1-c/2,sv1-16,c,16,hMemDC,0,0,0x00ea02e9);
01111 SelectObject(hdc[i],holdbrush);
01112 }
01113
01114 SelectObject(hMemDC,hbmOld);
01115 DeleteDC(hMemDC);
01116 }
01117 }
01118
01119 static void DrawAxis(HDC hdc[], point v1, short status){
01120 int sh1,sv1,i;
01121 int ifd,ild;
01122 if(View == TRIVIEW){ifd=0;ild=3;}
01123 else {ifd=ActiveView; ild=ifd+1;}
01124 for(i=ifd;i<ild;i++){
01125 GetWindowCoords(i,v1[0],v1[1],v1[2],&sh1,&sv1);
01126 MoveToEx(hdc[i],sh1-5,sv1,NULL); LineTo(hdc[i],sh1+5,sv1);
01127 MoveToEx(hdc[i],sh1,sv1+5,NULL); LineTo(hdc[i],sh1,sv1-5);
01128 MoveToEx(hdc[i],sh1-2,sv1,NULL);
01129 LineTo(hdc[i],sh1,sv1-2); LineTo(hdc[i],sh1+2,sv1);
01130 LineTo(hdc[i],sh1,sv1+2); LineTo(hdc[i],sh1-2,sv1);
01131 }
01132 }
01133
01134 static void DrawFullObject(HDC hdc[], object *Op, point Offset
01135 , double p, double t, double a, short im, double ima
01136 , double sx, double sy, double sz, short status){
01137 int k,n,sh1,sv1,sh2,sv2,morphflag;
01138 long ep,i,Nv,Nl,Nm,j,id[2],Sz;
01139 point v1,v2,*Vp;
01140 double mr;
01141 LOGPEN lopn;
01142 int ifd,ild;
01143 if(View == TRIVIEW){ifd=0;ild=3; n=3;}
01144 else {ifd=ActiveView; ild=ifd+1; n=1;}
01145 morphflag=0;
01146 if(status == SELECTED)GetObject(ghSelectedPen,sizeof(LOGPEN),&lopn);
01147 else GetObject(ghDeselectedPen,sizeof(LOGPEN),&lopn);
01148 if(Op->in_ram)Nv=Op->npoints;
01149 else Nv=0;
01150 if(Op->morph != NO && Op->last != NULL){
01151 morphflag=1;
01152 mr=(double)(Op->lastframe - Op->firstframe+1);
01153 if(Op->lastframe == Nframes)mr += 1.0;
01154 mr=(double)(CurrentFrame - Op->firstframe+1)/mr;
01155 Nm=Op->last->npoints;
01156 if(!Op->last->in_ram || Nm != Nv)morphflag=0;
01157 }
01158 DrawNurbsObject(hdc,Op,Offset,p,t,a,im,ima,sx,sy,sz,status);
01159 Sz=(long)Nv*(long)sizeof(point);
01160 if(Nv > 0){
01161 if((Vp=(point *)X__Malloc((long)Nv*sizeof(point))) != NULL){
01162 for(j=0;j<Nv;j++){
01163 CopyPoint(Op->points[j],Vp[j]);
01164 if(morphflag == 1){
01165 CopyPoint(Op->last->points[j],v1);
01166 Vp[j][0] -= Op->origin[0];
01167 Vp[j][1] -= Op->origin[1];
01168 Vp[j][2] -= Op->origin[2];
01169 v1[0] -= Op->last->origin[0];
01170 v1[1] -= Op->last->origin[1];
01171 v1[2] -= Op->last->origin[2];
01172 Vp[j][0] = (long)((double)(Vp[j][0] - v1[0])*mr + v1[0])*sx;
01173 Vp[j][1] = (long)((double)(Vp[j][1] - v1[1])*mr + v1[1])*sy;
01174 Vp[j][2] = (long)((double)(Vp[j][2] - v1[2])*mr + v1[2])*sz;
01175 }
01176 else{
01177 Vp[j][0] = (Vp[j][0] - Op->origin[0])*sx;
01178 Vp[j][1] = (Vp[j][1] - Op->origin[1])*sy;
01179 Vp[j][2] = (Vp[j][2] - Op->origin[2])*sz;
01180 }
01181 }
01182 Transform(Nv,Vp,Vp,Offset,p,t,a,im,ima);
01183 if(global_quickdraw){
01184 long qstep,kstep;
01185 qstep=max(1,Nv/100);
01186 for(k=0;k<n;k++){
01187 i=order_list[ActiveView][k];
01188 for(j=0;j<Nv;j+=qstep)if(in_stage_triview(Vp[j])){
01189 GetWindowCoords(i,Vp[j][0],Vp[j][1],Vp[j][2],&sh1,&sv1);
01190 MoveToEx(hdc[i],sh1-1,sv1,NULL); LineTo(hdc[i],sh1+2,sv1);
01191 MoveToEx(hdc[i],sh1,sv1-1,NULL); LineTo(hdc[i],sh1,sv1+2);
01192 }
01193 if(tool_move_flag){
01194
01195
01196
01197 }
01198 if(qstep > 1){
01199 if (Nv < 100)kstep=1;
01200 else if(Nv < 1000)kstep=2;
01201 else if(Nv < 2500)kstep=3;
01202 else if(Nv < 5000)kstep=4;
01203 else if(Nv < 10000)kstep=6;
01204 else kstep=8;
01205 for(j=0;j<Nv;j+=kstep){
01206 if(j%qstep == 0)continue;
01207 if(in_stage_triview(Vp[j])){
01208 GetWindowCoords(i,Vp[j][0],Vp[j][1],Vp[j][2],&sh1,&sv1);
01209 MoveToEx(hdc[i],sh1-1,sv1,NULL); LineTo(hdc[i],sh1+2,sv1);
01210 MoveToEx(hdc[i],sh1,sv1-1,NULL); LineTo(hdc[i],sh1,sv1+2);
01211 if(HIWORD(GetQueueStatus(QS_MOUSEMOVE)) == QS_MOUSEMOVE
01212 && CheckInterrupt()){
01213
01214
01215
01216 goto ABORT;
01217 }
01218 }
01219 }
01220 if(tool_move_flag){
01221
01222
01223
01224 }
01225 }
01226 if(zoom_abort == 1){
01227
01228
01229
01230 goto ABORT;
01231 }
01232 }
01233 goto ABORT;
01234 }
01235 if(Op->in_ram)Nl=Op->nedges; else Nl=0;
01236 if(Nl > 0){
01237 long qstep,kstep;
01238 if(Preferences.detail_auto){
01239 if (Nl < 100)kstep=1;
01240 else if(Nl < 1000)kstep=2;
01241 else if(Nl < 2500)kstep=3;
01242 else if(Nl < 5000)kstep=4;
01243 else if(Nl < 10000)kstep=6;
01244 else kstep=8;
01245 }
01246 else{
01247 kstep=max(1,Preferences.detail_step);
01248 }
01249 qstep=0;
01250 for(ep=0;ep<Nl;ep+=kstep){
01251 id[0]=Op->edges[ep][0];
01252 id[1]=Op->edges[ep][1];
01253 CopyPoint(Vp[id[0]],v1);
01254 CopyPoint(Vp[id[1]],v2);
01255 if(in_stage_triview(v1) || in_stage_triview(v2)){
01256
01257 for(k=0;k<n;k++){
01258 i=order_list[ActiveView][k];
01259 GetWindowCoords(i,v1[0],v1[1],v1[2],&sh1,&sv1);
01260 GetWindowCoords(i,v2[0],v2[1],v2[2],&sh2,&sv2);
01261 if(abs(sh1-sh2) < 4 && abs(sv1-sv2) < 4){
01262 MoveToEx(hdc[i],sh1,sv1,NULL); LineTo(hdc[i],sh1+1,sv1);
01263 }
01264 else {
01265 MoveToEx(hdc[i],sh1,sv1,NULL); LineTo(hdc[i],sh2,sv2);
01266 }
01267 }
01268 if(HIWORD(GetQueueStatus(QS_MOUSEMOVE)) == QS_MOUSEMOVE
01269 && CheckInterrupt())goto ABORT;
01270 }
01271 if(qstep == 50 && tool_move_flag){
01272
01273
01274
01275 }
01276 qstep++;
01277 }
01278 if(tool_move_flag){
01279
01280
01281
01282 }
01283 }
01284 ABORT:
01285 X__Free(Vp);
01286 }
01287 }
01288 }
01289
01290 static void DrawCameraFOV(HDC hdc[], short status, node *Np, short al_type,
01291 point Offset, point TrackedOffset,
01292 double p, double t, double a,
01293 short im, double ima,
01294 double sx, double sy, double sz){
01295 HPEN hOldPen[3];
01296 COLORREF OldColour[3];
01297 int OldMode[3];
01298 int sh1,sv1,sh2,sv2,i;
01299 static short ccep1[8]={0,1,2,3,4,4,4,4};
01300 static short ccep2[8]={1,2,3,0,0,1,2,3};
01301 point v1,v2;
01302 point Lcone[4];
01303 short ep;
01304 double d,r,asp;
01305 int ifd,ild;
01306 if(View == TRIVIEW){ifd=0;ild=3;}
01307 else {ifd=ActiveView; ild=ifd+1;}
01308 if(al_type != TRACK){
01309 d=(double)(TVsizeX)*0.4;
01310 }
01311 else{
01312 SubPoints(Offset,TrackedOffset,v1);
01313 d=sqrt((double)v1[0]*(double)v1[0]+
01314 (double)v1[1]*(double)v1[1]+
01315 (double)v1[2]*(double)v1[2]);
01316 }
01317 r=d*0.42/sx;
01318 asp=r*sx/sy*0.75;
01319 for(i=0;i<4;i++)Lcone[i][1]=d;
01320 Lcone[0][0]= (long)r; Lcone[0][2]= (long)asp;
01321 Lcone[1][0]=-(long)r; Lcone[1][2]= (long)asp;
01322 Lcone[2][0]=-(long)r; Lcone[2][2]=-(long)asp;
01323 Lcone[3][0]= (long)r; Lcone[3][2]=-(long)asp;
01324 CopyPoint(Offset,trpoints[4]);
01325 Transform(4,Lcone,trpoints,Offset,p,t,a,im,ima);
01326 if(tool != NOTOOL && tool != NODETOOL &&
01327 tool != PAN && tool != INZOOM && Np == SelectedNode){
01328 for(i=ifd;i<ild;i++){
01329 OldMode[i]=SetBkMode(hdc[i],TRANSPARENT);
01330
01331 hOldPen[i]=SelectObject(hdc[i],ghDotInvertPen);
01332 }
01333 }
01334 else{
01335 for(i=ifd;i<ild;i++)OldMode[i]=SetBkMode(hdc[i],TRANSPARENT);
01336
01337 if(status == SELECTED){
01338 for(i=ifd;i<ild;i++)hOldPen[i]=SelectObject(hdc[i],ghDotSelectedPen);
01339 }
01340 else{
01341 for(i=ifd;i<ild;i++)hOldPen[i]=SelectObject(hdc[i],ghDotDeselectedPen);
01342 }
01343 }
01344 for(ep=0;ep<8;ep++){
01345 CopyPoint(trpoints[ccep1[ep]],v1);
01346 CopyPoint(trpoints[ccep2[ep]],v2);
01347 if(in_stage_triview(v1) || in_stage_triview(v2)){
01348 for(i=ifd;i<ild;i++){
01349 GetWindowCoords(i,v1[0],v1[1],v1[2],&sh1,&sv1);
01350 GetWindowCoords(i,v2[0],v2[1],v2[2],&sh2,&sv2);
01351 MoveToEx(hdc[i],sh1,sv1,NULL); LineTo(hdc[i],sh2,sv2);
01352 }
01353 }
01354 }
01355 for(i=ifd;i<ild;i++){
01356 SelectObject(hdc[i],hOldPen[i]);
01357 SetBkMode(hdc[i],OldMode[i]);
01358
01359 }
01360 }
01361
01362 static void DrawLightCone(HDC hdc[], short status, node *Np, short type,
01363 point Offset, point TrackedOffset,
01364 double p, double t, double a,
01365 short im, double ima, double cone, double edge){
01366 HPEN hOldPen[3];
01367 COLORREF OldColour[3];
01368 int OldMode[3];
01369 int sh1,sv1,sh2,sv2,i;
01370 static short lcep1[16]={0,1,2,3,4,5,6,7,8, 9,10,11,12,12,12,12};
01371 static short lcep2[16]={1,2,3,4,5,6,7,8,9,10,11, 0, 0, 3, 6, 9};
01372 static double LconeX[12]={ 1.000, 0.866, 0.500, 0.000,-0.500,-0.866,
01373 -1.000,-0.866,-0.500, 0.000, 0.500, 0.866};
01374 static double LconeY[12]={ 0.000, 0.500, 0.866, 1.000, 0.866, 0.500,
01375 0.000,-0.500,-0.866,-1.000,-0.866,-0.500};
01376 point v1,v2;
01377 point Lcone[12];
01378 short ep;
01379 double d,r;
01380 int ifd,ild;
01381 if(View == TRIVIEW){ifd=0;ild=3;}
01382 else {ifd=ActiveView; ild=ifd+1;}
01383 if(type != TRACK){
01384 d=(double)TVsizeX/2;
01385 }
01386 else{
01387 SubPoints(Offset,TrackedOffset,v1);
01388 d=sqrt((double)v1[0]*(double)v1[0]+
01389 (double)v1[1]*(double)v1[1]+
01390 (double)v1[2]*(double)v1[2]);
01391 }
01392 r=d*tan(cone/360.0*PI);
01393 for(i=0;i<12;i++){
01394 Lcone[i][1]=d;
01395 Lcone[i][0]=(long)(r*LconeX[i]); Lcone[i][2]=(long)(r*LconeY[i]);
01396 }
01397 CopyPoint(Offset,trpoints[12]);
01398 Transform(12,Lcone,trpoints,Offset,p,t,a,im,ima);
01399 if(tool != NOTOOL && tool != NODETOOL &&
01400 tool != PAN && tool != INZOOM && Np == SelectedNode){
01401 for(i=ifd;i<ild;i++){
01402
01403 OldMode[i]=SetBkMode(hdc[i],TRANSPARENT);
01404 hOldPen[i]=SelectObject(hdc[i],ghDotInvertPen);
01405 }
01406 }
01407 else{
01408 for(i=ifd;i<ild;i++)OldMode[i]=SetBkMode(hdc[i],TRANSPARENT);
01409
01410 if(status == SELECTED){
01411 for(i=ifd;i<ild;i++)hOldPen[i]=SelectObject(hdc[i],ghDotSelectedPen);
01412 }
01413 else{
01414 for(i=ifd;i<ild;i++)hOldPen[i]=SelectObject(hdc[i],ghDotDeselectedPen);
01415 }
01416 }
01417 for(ep=0;ep<16;ep++){
01418 CopyPoint(trpoints[lcep1[ep]],v1);
01419 CopyPoint(trpoints[lcep2[ep]],v2);
01420 if(in_stage_triview(v1) || in_stage_triview(v2)){
01421 for(i=ifd;i<ild;i++){
01422 GetWindowCoords(i,v1[0],v1[1],v1[2],&sh1,&sv1);
01423 GetWindowCoords(i,v2[0],v2[1],v2[2],&sh2,&sv2);
01424 MoveToEx(hdc[i],sh1,sv1,NULL); LineTo(hdc[i],sh2,sv2);
01425 }
01426 }
01427 }
01428 for(i=ifd;i<ild;i++){
01429 SetBkMode(hdc[i],OldMode[i]);
01430 SelectObject(hdc[i],hOldPen[i]);
01431
01432 }
01433 }
01434
01435 static void DrawLightExtent(HDC hdc[], short status, node *Np, short type,
01436 point vc, double sz){
01437 HPEN hOldPen[3];
01438 COLORREF OldColour[3];
01439 HBRUSH hOldBrush[3];
01440 int OldMode[3];
01441 int sh1,sv1,sh2,sv2,s;
01442 int i,ifd,ild;
01443 point vmx,vmn;
01444 if(View == TRIVIEW){ifd=0;ild=3;}
01445 else {ifd=ActiveView; ild=ifd+1;}
01446 if(tool != NOTOOL && tool != NODETOOL &&
01447 tool != PAN && tool != INZOOM && Np == SelectedNode){
01448 for(i=ifd;i<ild;i++){
01449
01450 OldMode[i]=SetBkMode(hdc[i],TRANSPARENT);
01451 hOldPen[i]=SelectObject(hdc[i],ghDotInvertPen);
01452 hOldBrush[i]=SelectObject(hdc[i],GetStockObject(NULL_BRUSH));
01453 }
01454 }
01455 else{
01456 for(i=ifd;i<ild;i++){
01457 OldMode[i]=SetBkMode(hdc[i],TRANSPARENT);
01458
01459 hOldBrush[i]=SelectObject(hdc[i],GetStockObject(NULL_BRUSH));
01460 }
01461 if(status == SELECTED){
01462 for(i=ifd;i<ild;i++)hOldPen[i]=SelectObject(hdc[i],ghDotSelectedPen);
01463 }
01464 else{
01465 for(i=ifd;i<ild;i++)hOldPen[i]=SelectObject(hdc[i],ghDotDeselectedPen);
01466 }
01467 }
01468 vmn[0]=vc[0]-sz*(double)UNIT;
01469 vmn[1]=vc[1]-sz*(double)UNIT;
01470 vmn[2]=vc[2]-sz*(double)UNIT;
01471 vmx[0]=vc[0]+sz*(double)UNIT;
01472 vmx[1]=vc[1]+sz*(double)UNIT;
01473 vmx[2]=vc[2]+sz*(double)UNIT;
01474 for(i=ifd;i<ild;i++){
01475 GetWindowCoords(i,vmn[0],vmn[1],vmn[2],&sh1,&sv1);
01476 GetWindowCoords(i,vmx[0],vmx[1],vmx[2],&sh2,&sv2);
01477 if(sh1 > sh2){s=sh2; sh2=sh1; sh1=s;}
01478 if(sv1 > sv2){s=sv2; sv2=sv1; sv1=s;}
01479 if((sh1 > 0 && sh1 < WindowSizeX[i]) ||
01480 (sh2 > 0 && sh2 < WindowSizeX[i]) ||
01481 (sv1 > 0 && sv1 < WindowSizeY[i]) ||
01482 (sv2 > 0 && sv2 < WindowSizeY[i]))
01483 Ellipse(hdc[i],sh1,sv1,sh2,sv2);
01484 }
01485 for(i=ifd;i<ild;i++){
01486 SelectObject(hdc[i],hOldPen[i]);
01487 SelectObject(hdc[i],hOldBrush[i]);
01488 SetBkMode(hdc[i],OldMode[i]);
01489
01490 }
01491 }
01492
01493 #define NP Op->w_frame.Np
01494 #define NE Op->w_frame.Ne
01495 static short DrawQuickObject(HDC hdc[], object *Op, point Offset
01496 , double p, double t, double a
01497 , short im, double ima
01498 , double sx, double sy, double sz, short status){
01499 int sh1,sv1,sh2,sv2;
01500 point v1,v2,*Vp;
01501 long i,j,ep,id1,id2;
01502 double mr;
01503 int ifd,ild;
01504 if(View == TRIVIEW){ifd=0;ild=3;}
01505 else {ifd=ActiveView; ild=ifd+1;}
01506 if(Op->w_frame.p == NULL || Op->w_frame.e == NULL ||
01507 NP == 0 || NE == 0)return FAIL;
01508 if((Vp=(point *)X__Malloc((NP)*sizeof(point))) == NULL)return FAIL;
01509 if(Op->morph != NO && Op->last != NULL && Op->last->w_frame.p != NULL &&
01510 Op->w_frame.Np == Op->last->w_frame.Np){
01511 mr=(double)(Op->lastframe - Op->firstframe+1);
01512 mr=(double)(CurrentFrame - Op->firstframe+1)/mr;
01513 for(j=0;j<NP;j++){
01514 CopyPoint(Op->w_frame.p[j],Vp[j]);
01515 CopyPoint(Op->last->w_frame.p[j],v1);
01516 Vp[j][0] = (long)((double)(Vp[j][0] - v1[0])*mr + v1[0])*sx;
01517 Vp[j][1] = (long)((double)(Vp[j][1] - v1[1])*mr + v1[1])*sy;
01518 Vp[j][2] = (long)((double)(Vp[j][2] - v1[2])*mr + v1[2])*sz;
01519 }
01520 }
01521 else{
01522 for(j=0;j<NP;j++){
01523 CopyPoint(Op->w_frame.p[j],Vp[j]);
01524 Vp[j][0] = Vp[j][0]*sx;
01525 Vp[j][1] = Vp[j][1]*sy;
01526 Vp[j][2] = Vp[j][2]*sz;
01527 }
01528 }
01529 Transform((long)(NP),Vp,Vp,Offset,p,t,a,im,ima);
01530 for(ep=0;ep<NE;ep++){
01531 id1=Op->w_frame.e[ep][0]; id2=Op->w_frame.e[ep][1];
01532 CopyPoint(Vp[id1],v1);
01533 CopyPoint(Vp[id2],v2);
01534 if(in_stage_triview(v1) || in_stage_triview(v2)){
01535 for(i=ifd;i<ild;i++){
01536 GetWindowCoords(i,v1[0],v1[1],v1[2],&sh1,&sv1);
01537 GetWindowCoords(i,v2[0],v2[1],v2[2],&sh2,&sv2);
01538 MoveToEx(hdc[i],sh1,sv1,NULL); LineTo(hdc[i],sh2,sv2);
01539 }
01540 }
01541 }
01542 X__Free(Vp);
01543 return OK;
01544 }
01545
01546
01547 int CheckBoundingObject(int type, int ifd, int hx, int vy,
01548 object *Op, point Offset, double p,
01549 double t, double a, short im, double ima,
01550 double sx, double sy, double sz, double *dc){
01551 int sh1,sv1,sh2,sv2,i,j,ep,id1,id2;
01552 point v1,v2,*Vp;
01553 double mr;
01554 if(type == 1){
01555 int morphflag;
01556 long ep,i,Nv,Nl,Nm,j,id[2],Sz;
01557 morphflag=0;
01558 if(Op->in_ram)Nv=Op->npoints;
01559 else Nv=0;
01560 if(Op->morph != NO && Op->last != NULL){
01561 morphflag=1;
01562 mr=(double)(Op->lastframe - Op->firstframe+1);
01563 if(Op->lastframe == Nframes)mr += 1.0;
01564 mr=(double)(CurrentFrame - Op->firstframe+1)/mr;
01565 Nm=Op->last->npoints;
01566 if(!Op->last->in_ram || Nm != Nv)morphflag=0;
01567 }
01568 Sz=(long)Nv*(long)sizeof(point);
01569 if(Nv > 0){
01570 if((Vp=(point *)X__Malloc((long)Nv*sizeof(point))) != NULL){
01571 for(j=0;j<Nv;j++){
01572 CopyPoint(Op->points[j],Vp[j]);
01573 if(morphflag == 1){
01574 CopyPoint(Op->last->points[j],v1);
01575 Vp[j][0] -= Op->origin[0];
01576 Vp[j][1] -= Op->origin[1];
01577 Vp[j][2] -= Op->origin[2];
01578 v1[0] -= Op->last->origin[0];
01579 v1[1] -= Op->last->origin[1];
01580 v1[2] -= Op->last->origin[2];
01581 Vp[j][0] = (long)((double)(Vp[j][0] - v1[0])*mr + v1[0])*sx;
01582 Vp[j][1] = (long)((double)(Vp[j][1] - v1[1])*mr + v1[1])*sy;
01583 Vp[j][2] = (long)((double)(Vp[j][2] - v1[2])*mr + v1[2])*sz;
01584 }
01585 else{
01586 Vp[j][0] = (Vp[j][0] - Op->origin[0])*sx;
01587 Vp[j][1] = (Vp[j][1] - Op->origin[1])*sy;
01588 Vp[j][2] = (Vp[j][2] - Op->origin[2])*sz;
01589 }
01590 }
01591 Transform(Nv,Vp,Vp,Offset,p,t,a,im,ima);
01592 if(global_quickdraw){
01593 for(j=0;j<Nv;j++)if(in_stage_triview(Vp[j])){
01594 GetWindowCoords(ifd,Vp[j][0],Vp[j][1],Vp[j][2],&sh1,&sv1);
01595 if(CheckClosestObject(ifd,dc,Vp[j],hx,vy,4)){
01596 X__Free(Vp);
01597 return 1;
01598 }
01599 }
01600 X__Free(Vp);
01601 return 0;
01602 }
01603 if(Op->in_ram)Nl=Op->nedges; else Nl=0;
01604 if(Nl > 0) for(ep=0;ep<Nl;ep++){
01605 id[0]=Op->edges[ep][0];
01606 id[1]=Op->edges[ep][1];
01607 CopyPoint(Vp[id[0]],v1);
01608 CopyPoint(Vp[id[1]],v2);
01609 if(in_stage_triview(v1) || in_stage_triview(v2)){
01610 GetWindowCoords(ifd,v1[0],v1[1],v1[2],&sh1,&sv1);
01611 GetWindowCoords(ifd,v2[0],v2[1],v2[2],&sh2,&sv2);
01612 if(OnModelEdge(hx,vy,sh1,sv1,sh2,sv2,v1,v2,dc)){
01613 X__Free(Vp);
01614 return 1;
01615 }
01616 }
01617 }
01618 X__Free(Vp);
01619 }
01620 }
01621 return 0;
01622 }
01623 if(Op->w_frame.p == NULL || Op->w_frame.e == NULL ||
01624 NP == 0 || NE == 0)goto BBOX;
01625 if((Vp=(point *)X__Malloc((NP)*sizeof(point))) == NULL)goto BBOX;
01626 if(Op->morph != NO && Op->last != NULL && Op->last->w_frame.p != NULL &&
01627 Op->w_frame.Np == Op->last->w_frame.Np){
01628 mr=(double)(Op->lastframe - Op->firstframe+1);
01629 mr=(double)(CurrentFrame - Op->firstframe+1)/mr;
01630 for(j=0;j<NP;j++){
01631 CopyPoint(Op->w_frame.p[j],Vp[j]);
01632 CopyPoint(Op->last->w_frame.p[j],v1);
01633 Vp[j][0] = (long)((double)(Vp[j][0] - v1[0])*mr + v1[0])*sx;
01634 Vp[j][1] = (long)((double)(Vp[j][1] - v1[1])*mr + v1[1])*sy;
01635 Vp[j][2] = (long)((double)(Vp[j][2] - v1[2])*mr + v1[2])*sz;
01636 }
01637 }
01638 else{
01639 for(j=0;j<NP;j++){
01640 CopyPoint(Op->w_frame.p[j],Vp[j]);
01641 Vp[j][0] = Vp[j][0]*sx;
01642 Vp[j][1] = Vp[j][1]*sy;
01643 Vp[j][2] = Vp[j][2]*sz;
01644 }
01645 }
01646 Transform((long)(NP),Vp,Vp,Offset,p,t,a,im,ima);
01647 for(ep=0;ep<NE;ep++){
01648 id1=Op->w_frame.e[ep][0]; id2=Op->w_frame.e[ep][1];
01649 CopyPoint(Vp[id1],v1);
01650 CopyPoint(Vp[id2],v2);
01651 if(in_stage_triview(v1) || in_stage_triview(v2)){
01652 GetWindowCoords(ifd,v1[0],v1[1],v1[2],&sh1,&sv1);
01653 GetWindowCoords(ifd,v2[0],v2[1],v2[2],&sh2,&sv2);
01654 if(OnModelEdge(hx,vy,sh1,sv1,sh2,sv2,v1,v2,dc)){
01655 X__Free(Vp);
01656 return 1;
01657 }
01658 }
01659 }
01660 X__Free(Vp);
01661 return 0;
01662 BBOX:
01663 if(Op->morph != NO && Op->last != NULL){
01664 mr=(double)(Op->lastframe - Op->firstframe+1);
01665 mr=(double)(CurrentFrame - Op->firstframe+1)/mr;
01666 for(i=0;i<8;i++){
01667 srpoints[i][0] = (long)((double)(Op->outline[i][0] -
01668 Op->last->outline[i][0])*mr + Op->last->outline[i][0])*sx;
01669 srpoints[i][1] = (long)((double)(Op->outline[i][1] -
01670 Op->last->outline[i][1])*mr + Op->last->outline[i][1])*sy;
01671 srpoints[i][2] = (long)((double)(Op->outline[i][2] -
01672 Op->last->outline[i][2])*mr + Op->last->outline[i][2])*sz;
01673 }
01674 }
01675 else{
01676 for(i=0;i<8;i++){
01677 srpoints[i][0] = (long)((double)Op->outline[i][0])*sx;
01678 srpoints[i][1] = (long)((double)Op->outline[i][1])*sy;
01679 srpoints[i][2] = (long)((double)Op->outline[i][2])*sz;
01680 }
01681 }
01682 Transform(8,srpoints,trpoints,Offset,p,t,a,im,ima);
01683 for(ep=0;ep<12;ep++){
01684 CopyPoint(trpoints[ep1[ep]],v1);
01685 CopyPoint(trpoints[ep2[ep]],v2);
01686 if(in_stage_triview(v1) || in_stage_triview(v2)) {
01687 GetWindowCoords(ifd,v1[0],v1[1],v1[2],&sh1,&sv1);
01688 GetWindowCoords(ifd,v2[0],v2[1],v2[2],&sh2,&sv2);
01689 if(OnModelEdge(hx,vy,sh1,sv1,sh2,sv2,v1,v2,dc))return 1;
01690 }
01691 }
01692 return 0;
01693 }
01694
01695 static int OnModelEdge(int npx, int npy,
01696 int sh1, int sv1, int sh2, int sv2,
01697 point vp1, point vp2,
01698 double *dc){
01699 int i,found=0;
01700 double x,y,z,mu,a,b,c,d;
01701 a=(double)(sh2-sh1); b=(double)(sv2-sv1);
01702 if((sh2-sh1) != 0 || (sv2-sv1) != 0){
01703 x=(double)npx; y=(double)npy;
01704 mu=(a*(x-(double)sh1) + b*(y-(double)sv1))/(a*a+b*b);
01705 if(mu > 0.0001 && mu < 0.9999){
01706 x=a*mu+(double)sh1; y=b*mu+(double)sv1;
01707 sh1=(int)x; sv1=(int)y;
01708 if(abs(npx-sh1) < 4 && abs(npy-sv1) < 4){
01709 a=(double)(vp2[0]-vp1[0]);
01710 b=(double)(vp2[1]-vp1[1]);
01711 c=(double)(vp2[2]-vp1[2]);
01712 mu=(a*((double)NpointerX-(double)(vp1[0]))
01713 +b*((double)NpointerY-(double)(vp1[1]))
01714 +c*((double)NpointerZ-(double)(vp1[2])))/(a*a+b*b+c*c);
01715 x=a*mu+(double)(vp1[0]);
01716 y=b*mu+(double)(vp1[1]);
01717 z=c*mu+(double)(vp1[2]);
01718 d=(x-(double)NpointerX)*(x-(double)NpointerX)
01719 +(y-(double)NpointerY)*(y-(double)NpointerY)
01720 +(z-(double)NpointerZ)*(z-(double)NpointerZ);
01721 if(d < *dc){
01722 *dc=d;
01723 found=1;
01724 }
01725 }
01726 }
01727 }
01728 return found;
01729 }
01730
01731 #undef NP
01732 #undef NE
01733
01734
01735
01736
01737 void DrawNode(HDC hDC[], node *Np, short status){
01738 point ObjectOffset,TrackedOffset;
01739 object *Op;
01740 short im,al_type;
01741 double phi,theta,alpha,sx,sy,sz,ima;
01742 if((Op=Np->fobj) != NULL)while(Op != NULL){
01743 if((CurrentFrame >= Op->firstframe) && (CurrentFrame <= Op->lastframe)){
01744 al_type=GetTransform(0,CurrentFrame,1.0,Np,Op,ObjectOffset,TrackedOffset,
01745 &phi,&theta,&alpha,&sx,&sy,&sz,&im,&ima);
01746 if((Op->type == PATH) && (Op->firstpathpoint != NULL)){
01747 if(tool == PATHEDITOR && Np == SelectedNode)DrawPath(hDC,
01748 Op,ObjectOffset,phi,theta,alpha,im,ima,EDITING);
01749 else DrawPath(hDC,
01750 Op,ObjectOffset,phi,theta,alpha,im,ima,status);
01751 }
01752 else if(Op->type == NORMAL || Op->type == ANIMOBJ){
01753 if(DrawStatus == 0 || Op->quick_only == 1)
01754 DrawObject(hDC,Op,ObjectOffset,phi,theta,alpha,
01755 im,ima,sx,sy,sz,status);
01756 else if(DrawStatus == 3 || (DrawStatus == 2 && Np != SelectedNode)
01757 || (DrawStatus == 1 && Np == SelectedNode))
01758 DrawFullObject(hDC,Op,ObjectOffset,phi,theta,alpha,
01759 im,ima,sx,sy,sz,status);
01760 else DrawObject(hDC,Op,ObjectOffset,phi,theta,alpha,
01761 im,ima,sx,sy,sz,status);
01762 }
01763 else if(Op->type == PARTICLE)
01764 DrawObject(hDC,Op,ObjectOffset,phi,theta,alpha,
01765 im,ima,sx,sy,sz,status);
01766 else if(Op->type == CAMERA){
01767 DrawActorBitmap(hDC,ObjectOffset,
01768 phi,theta,alpha,0,0.0,status,0);
01769 if(show_camera_fov)DrawCameraFOV(hDC,status,Np,al_type,
01770 ObjectOffset,TrackedOffset,
01771 phi,theta,alpha,im,ima,sx,sy,sz);
01772 else DrawArrow(hDC,ObjectOffset,
01773 phi,theta,alpha,im,ima,TVsizeX/20);
01774 }
01775 else if(Op->type == LIGHT){
01776 DrawActorBitmap(hDC,ObjectOffset,
01777 phi,theta,alpha,im,ima,status,1);
01778 if(Op->lighttype == SPOTLIGHT){
01779 if(show_light_cones)DrawLightCone(hDC,status,Np,al_type,
01780 ObjectOffset,TrackedOffset,
01781 phi,theta,alpha,im,ima,sx,sy);
01782 else DrawArrow(hDC,ObjectOffset,
01783 phi,theta,alpha,im,ima,TVsizeX/20);
01784 }
01785 if(Op->depth_cue && show_light_cones)
01786 DrawLightExtent(hDC,status,Np,al_type,ObjectOffset,sz);
01787 }
01788 else if(Op->type == GROUND)DrawGround(hDC,
01789 ObjectOffset,phi,theta,alpha,im,ima,status,sx,sy,sz);
01790 else if(Op->type == TARGET)DrawAxis(hDC,
01791 ObjectOffset,status);
01792 else if(Op->type == ROBOT){
01793 if(DrawStatus == 3 || (DrawStatus == 2 && Np != SelectedNode)
01794 || (DrawStatus == 1 && Np == SelectedNode))
01795 DrawFullRobot(hDC,
01796 Op,ObjectOffset,phi,theta,alpha,
01797 im,ima,sx,sy,sz,status);
01798 else DrawRobot( hDC,
01799 Op,ObjectOffset,phi,theta,alpha,
01800 im,ima,sx,sy,sz,status);
01801 }
01802 }
01803 Op=Op->next;
01804 }
01805 }
01806
01807 void DrawInvertNode(HDC hDC[], node *Np, short status){
01808 int i,oldROP[3];
01809 int ifd,ild;
01810 if(View == TRIVIEW){ifd=0;ild=3;}
01811 else {ifd=ActiveView; ild=ifd+1;}
01812 if(hDC == NULL){
01813 HDC hdc[3];
01814 for(i=ifd;i<ild;i++){
01815 hdc[i]=GetDC(ghwnd_triview[i]);
01816
01817 SelectObject(hdc[i],ghInvertPen);
01818 RealizePalette (hdc[i]);
01819 oldROP[i]=SetROP2(hdc[i],R2_XORPEN);
01820 }
01821 DrawNode(hdc,Np,(short)abs(status));
01822 for(i=ifd;i<ild;i++){
01823 SetROP2(hdc[i],oldROP[i]);
01824 ReleaseDC(ghwnd_triview[i],hdc[i]);
01825 }
01826 }
01827 else{
01828 for(i=ifd;i<ild;i++){
01829 if(hDC[i] == NULL)return;
01830 oldROP[i]=SetROP2(hDC[i],R2_XORPEN);
01831 }
01832 DrawNode(hDC,Np,(short)abs(status));
01833 for(i=ifd;i<ild;i++){
01834 SetROP2(hDC[i],oldROP[i]);
01835 if(status >= 0)InvalidateRect(ghwnd_triview[i],NULL,FALSE);
01836 }
01837 }
01838 }
01839
01840 void ReDrawStageDisplay(BOOL draw_selected){
01841 int i,oldROP[3];
01842 node *Np;
01843 RECT rc;
01844 HDC hdc;
01845 int ifd,ild;
01846 HCURSOR lhcurSave;
01847 zoom_abort=0;
01848 if(View == TRIVIEW){ifd=0;ild=3;}
01849 else {ifd=ActiveView; ild=ifd+1;}
01850 for(i=ifd;i<ild;i++){
01851 if(ghdc_triview_Bitmap[i] == NULL)return;
01852 if(ghbm_triview[i] == NULL)return;
01853 GetClientRect(ghwnd_triview[i],&rc);
01854 PatBlt(ghdc_triview_Bitmap[i],0,0,rc.right,rc.bottom,PATCOPY);
01855 SelectObject(ghdc_triview_Bitmap[i],ghDeselectedPen);
01856 }
01857 if(DrawStatus > 0 && global_quickdraw == 0)lhcurSave=SetCursor(ghcurWait);
01858 if( draw_grid_on)DrawGrid(ghdc_triview_Bitmap);
01859 if((Np=FirstNp) != NULL)while(Np != NULL){
01860 if(Np != SelectedNode && Np->type != NORMAL && Np->type != ANIMOBJ){
01861 DrawNode(ghdc_triview_Bitmap,Np,DESELECTED);
01862 }
01863 Np=Np->next;
01864 }
01865 if((Np=FirstNp) != NULL)while(Np != NULL){
01866 if(Np != SelectedNode && (Np->type == NORMAL || Np->type == ANIMOBJ)){
01867 DrawNode(ghdc_triview_Bitmap,Np,DESELECTED);
01868 }
01869 Np=Np->next;
01870 }
01871 if(SelectedNode != NULL){
01872 if(tool != NOTOOL && tool != NODETOOL &&
01873 tool != PAN && tool != INZOOM){
01874 for(i=ifd;i<ild;i++){
01875 SelectObject(ghdc_triview_Bitmap[i],ghInvertPen);
01876 oldROP[i]=SetROP2(ghdc_triview_Bitmap[i],R2_XORPEN);
01877 }
01878 }
01879 else{
01880 for(i=ifd;i<ild;i++){
01881 SelectObject(ghdc_triview_Bitmap[i],ghSelectedPen);
01882 }
01883 }
01884 if(tool == PATHEDITOR)DrawNode(ghdc_triview_Bitmap,SelectedNode,EDITING);
01885 else if(draw_selected)DrawNode(ghdc_triview_Bitmap,SelectedNode,SELECTED);
01886 if(tool == TRACKER && subtool == SHIFTER)DrawActorTrack(ghdc_triview_Bitmap,0);
01887 if(tool == TRACKER && subtool == ANGLER )DrawActorRotations(ghdc_triview_Bitmap,0);
01888 if(tool != NOTOOL && tool != NODETOOL &&
01889 tool != PAN && tool != INZOOM)
01890 for(i=ifd;i<ild;i++)SetROP2(ghdc_triview_Bitmap[i],oldROP[i]);
01891 }
01892 for(i=ifd;i<ild;i++)DrawArrowIcons(ghdc_triview_Bitmap[i],i);
01893 if(DrawStatus > 0 && global_quickdraw == 0)SetCursor(lhcurSave);
01894 for(i=ifd;i<ild;i++){
01895 InvalidateRect(ghwnd_triview[i],NULL,FALSE);
01896 UpdateWindow(ghwnd_triview[i]);
01897 }
01898 return;
01899 }
01900
01901 void ReDrawQuickDisplay(BOOL draw_selected){
01902
01903 int i,oldROP[3];
01904 node *Np;
01905 RECT rc;
01906 HDC hDC[3];
01907 HBRUSH hOldBrush[3];
01908 int ifd,ild;
01909 zoom_abort=0;
01910 if(View == TRIVIEW){ifd=0;ild=3;}
01911 else {ifd=ActiveView; ild=ifd+1;}
01912 for(i=ifd;i<ild;i++){
01913 hDC[i]=GetDC(ghwnd_triview[i]);
01914 if(hDC[i] == NULL)return;
01915
01916 hOldBrush[i]=SelectObject(hDC[i],ghbrushWindow);
01917 RealizePalette(hDC[i]);
01918 GetClientRect(ghwnd_triview[i],&rc);
01919 PatBlt(hDC[i],0,0,rc.right,rc.bottom,PATCOPY);
01920 DrawArrowIcons(hDC[i],i);
01921 SelectObject(hDC[i],ghDeselectedPen);
01922 }
01923 if(draw_grid_on)DrawGrid(hDC);
01924 if((Np=FirstNp) != NULL)while(Np != NULL){
01925 if(Np != SelectedNode && Np->type != NORMAL && Np->type != ANIMOBJ){
01926 DrawNode(hDC,Np,DESELECTED);
01927 }
01928 Np=Np->next;
01929 }
01930 if(SelectedNode != NULL){
01931 if(tool != NOTOOL && tool != NODETOOL &&
01932 tool != PAN && tool != INZOOM){
01933 for(i=ifd;i<ild;i++){
01934 SelectObject(hDC[i],ghInvertPen);
01935 oldROP[i]=SetROP2(hDC[i],R2_XORPEN);
01936 }
01937 }
01938 else{
01939 for(i=ifd;i<ild;i++){
01940 SelectObject(hDC[i],ghSelectedPen);
01941 }
01942 }
01943 if(tool == PATHEDITOR)DrawNode(hDC,SelectedNode,EDITING);
01944 else if(draw_selected)DrawNode(hDC,SelectedNode,SELECTED);
01945 if(tool == TRACKER && subtool == SHIFTER)DrawActorTrack(hDC,0);
01946 if(tool == TRACKER && subtool == ANGLER )DrawActorRotations(hDC,0);
01947 if(tool != NOTOOL && tool != NODETOOL &&
01948 tool != PAN && tool != INZOOM)
01949 for(i=ifd;i<ild;i++)SetROP2(hDC[i],oldROP[i]);
01950 }
01951 for(i=ifd;i<ild;i++)SelectObject(hDC[i],ghDeselectedPen);
01952 if((Np=FirstNp) != NULL)while(Np != NULL){
01953 if(Np != SelectedNode && (Np->type == NORMAL || Np->type == ANIMOBJ)){
01954 DrawNode(hDC,Np,DESELECTED);
01955
01956 }
01957 Np=Np->next;
01958 }
01959 if(SelectedNode != NULL){
01960 if(tool != NOTOOL && tool != NODETOOL &&
01961 tool != PAN && tool != INZOOM){
01962 for(i=ifd;i<ild;i++){
01963 SelectObject(hDC[i],ghInvertPen);
01964 oldROP[i]=SetROP2(hDC[i],R2_XORPEN);
01965 }
01966 }
01967 else{
01968 for(i=ifd;i<ild;i++){
01969 SelectObject(hDC[i],ghSelectedPen);
01970 }
01971 }
01972 if(tool == PATHEDITOR)DrawNode(hDC,SelectedNode,EDITING);
01973 else if(draw_selected)DrawNode(hDC,SelectedNode,SELECTED);
01974 if(tool == TRACKER && subtool == SHIFTER)DrawActorTrack(hDC,0);
01975 if(tool == TRACKER && subtool == ANGLER )DrawActorRotations(hDC,0);
01976 if(tool != NOTOOL && tool != NODETOOL &&
01977 tool != PAN && tool != INZOOM)
01978 for(i=ifd;i<ild;i++)SetROP2(hDC[i],oldROP[i]);
01979 }
01980
01981 for(i=ifd;i<ild;i++){
01982 SelectObject(hDC[i],hOldBrush[i]);
01983 ReleaseDC(ghwnd_triview[i],hDC[i]);
01984 }
01985 return;
01986 }
01987