SKELETON.C

Go to the documentation of this file.
00001 /* --
00002 OpenFX - Modelling, Animation and Rendering Package
00003 -- */
00004 
00005 
00006 /* file SKELETON.C  skeleton file for the designer */
00007 
00008 // Handle all skeleton functions
00009 
00010 #define MODULE_SKELETON 1
00011 
00012 #include "design.h"
00013 
00014 #define NODE_AXIS    0
00015 #define RED_AXIS     1
00016 #define GREEN_AXIS   2
00017 #define YELLOW_AXIS  3
00018 #define TIME_DELAY  30
00019 
00020 static skel *PickSkeleton(int H, int V, int view);
00021 static void DefaultOrientAxes(skel *sp);
00022 static void SelectBySk(skel *sp,int op, int children);
00023 static void SkTwist(void);
00024 static void SkPivot(void);
00025 static void SkRotateRubberBones(void);
00026 static void DrawSkeletonAxes(skel *sp,int view,int sh1,int sv1, HDC hDC);
00027 static void DrawTrSkeletonAxes(skel *sp,int view,int sh1,int sv1, HDC hDC);
00028 static void DuplicateSkeletonChildren(skel *, skel *, skel *, long );
00029 static BOOL CALLBACK SkToolBarDlgProc(HWND, UINT, WPARAM, LPARAM);
00030 static double GetBoneRelativeDistance(point v, point s, point sp, vector d, double len, double *l, vector r);
00031 
00032 static BOOL SkMovedFlag=FALSE;
00033 static BOOL SkSelectFlag=FALSE;
00034 static BOOL SkRubberBonesRotate=FALSE;
00035 static int ep1[12]={0,1,2,3,4,5,6,7,0,1,2,3};
00036 static int ep2[12]={1,2,3,0,5,6,7,4,4,5,6,7};
00037 static int SelectedSkeletonAxis=0;
00038 static point LastSkeletonPoint;
00039 static skel *LastSkeletonVertex=NULL,*SkAssNode=NULL,
00040             *SkSelectedNode1=NULL,*SkSelectedNode2=NULL;
00041 
00042 static skel *PickSkeleton(int H, int V, int view){
00043  skel *sp,*sf;
00044  double d,dmin,dth;
00045  int sho,svo;
00046  sp=MainSp;
00047  sf=NULL;
00048  dmin=(double)TVsizeX*(double)TVsizeX;
00049  dth=dmin/32/32;
00050  while(sp != NULL){
00051    GetWindowCoords(view,sp->xyz[0],sp->xyz[1],sp->xyz[2],&sho,&svo);
00052    if( (sho > H-4) && (sho < H+4) && (svo > V-4) && (svo < V+4)){
00053      d=(double)(sp->xyz[0]-NpointerX)*(double)(sp->xyz[0]-NpointerX)
00054       +(double)(sp->xyz[1]-NpointerY)*(double)(sp->xyz[1]-NpointerY)
00055       +(double)(sp->xyz[2]-NpointerZ)*(double)(sp->xyz[2]-NpointerZ);
00056      if(d < dmin){
00057        dmin=d;
00058        sf=sp;
00059      }
00060    }
00061    sp=sp->last;
00062  }
00063  return sf;
00064 }
00065 
00066 void ZeroSkeletonBoundingBox(skel *sp){
00067  int i,j;
00068  for(i=0;i<8;i++)for(j=0;j<3;j++)sp->bx[i][j] = sp->xyz[j];
00069  if(sp->at != NULL){
00070    for(j=0;j<3;j++)sp->bx[2][j]=sp->at->xyz[j];
00071    for(j=0;j<3;j++)sp->bx[3][j]=sp->at->xyz[j];
00072    for(j=0;j<3;j++)sp->bx[6][j]=sp->at->xyz[j];
00073    for(j=0;j<3;j++)sp->bx[7][j]=sp->at->xyz[j];
00074  }
00075 }
00076 
00077 static void DefaultOrientAxes(skel *sp){
00078  vector x={1.0,0.0,0.0},y={0.0,1.0,0.0},z={0.0,0.0,1.0};
00079  if(sp->at == NULL)return;
00080  VECSUB((double)sp->at->xyz,(double)sp->xyz,sp->v); O_normalize(sp->v);
00081  if     (fabs(sp->v[2]) < 0.9)CROSS(sp->v,z,sp->u)
00082  else if(fabs(sp->v[1]) < 0.9)CROSS(y,sp->v,sp->u)
00083  else                         CROSS(x,sp->v,sp->u)
00084  O_normalize(sp->u);
00085  CROSS(sp->u,sp->v,sp->w);
00086  O_normalize(sp->w);
00087 }
00088 
00089 void GetSkeletonBoundBox(skel *sp, int ass){
00090  long l;
00091  int i,j,flag=0;
00092  vector p,box[8];
00093  vertex *vp;
00094  double a,b,c,amin,amax,bmin,bmax,cmin,cmax;
00095  amin=bmin=cmin=   FARAWAY;
00096  amax=bmax=cmax=  -FARAWAY;
00097  ZeroSkeletonBoundingBox(sp);
00098  if((vp=MainVp) != NULL)for(l=0;l<Nvert;l++){
00099    if(ass && vp->status == SELECTED)vp->sp=sp;
00100    if(vp->sp == sp){
00101      flag=1;
00102      VECSUB((double)vp->xyz,(double)sp->xyz,p)
00103      a=DOT(p,sp->u); amin=min(a,amin); amax=max(a,amax);
00104      b=DOT(p,sp->v); bmin=min(b,bmin); bmax=max(b,bmax);
00105      c=DOT(p,sp->w); cmin=min(c,cmin); cmax=max(c,cmax);
00106    }
00107    vp++;
00108  }
00109  if(flag){ /* assign bounding box */
00110    box[0][0]=amin; box[0][1]=bmin; box[0][2]=cmax;
00111    box[1][0]=amax; box[1][1]=bmin; box[1][2]=cmax;
00112    box[2][0]=amax; box[2][1]=bmax; box[2][2]=cmax;
00113    box[3][0]=amin; box[3][1]=bmax; box[3][2]=cmax;
00114    box[4][0]=amin; box[4][1]=bmin; box[4][2]=cmin;
00115    box[5][0]=amax; box[5][1]=bmin; box[5][2]=cmin;
00116    box[6][0]=amax; box[6][1]=bmax; box[6][2]=cmin;
00117    box[7][0]=amin; box[7][1]=bmax; box[7][2]=cmin;
00118    for(i=0;i<8;i++)for(j=0;j<3;j++){
00119      sp->bx[i][j] = sp->xyz[j] + (long)(box[i][0]*sp->u[j] +
00120                                         box[i][1]*sp->v[j] +
00121                                         box[i][2]*sp->w[j]);
00122    }
00123  }
00124 }
00125 
00126 void SelectByHierarchy(skel *sp, int op){
00127   vertex *vp;
00128   skel *sp1,*sp2;
00129   int drawval=0;
00130   long i;
00131   if(sp != NULL){
00132     if((sp1=MainSp) != NULL)while(sp1 != NULL){
00133       sp1->id=0; sp1=sp1->last;
00134     }
00135     if((sp1=MainSp) != NULL)while(sp1 != NULL){
00136       sp2=sp1;
00137       while(sp2 != NULL){
00138         if(sp2 == sp)sp1->id=1;
00139         sp2=sp2->at;
00140       }
00141       sp1=sp1->last;
00142     }
00143     if(op == DLG_SKEL_SELECT){
00144       if((vp=MainVp) != NULL)for(i=0;i<Nvert;i++,vp++){
00145         if((sp1=vp->sp) != NULL && sp1->id == 1 && vp->status != SELECTED){
00146           if(drawval == 0)drawval=1;
00147           if(vp->status == HIDDEN)drawval=2;
00148           vp->status=SELECTED;
00149           NvertSelect++; NvertDeselect--;
00150         }
00151       }
00152     }
00153     else if(op == DLG_SKEL_DESELECT){
00154       if((vp=MainVp) != NULL)for(i=0;i<Nvert;i++,vp++){
00155         if((sp1=vp->sp) != NULL && sp1->id == 1 && vp->status != DESELECTED){
00156           if(vp->status == HIDDEN){
00157             vp->status=DESELECTED;
00158             drawval=2;
00159           }
00160           else{
00161             if(drawval == 0)drawval=1;
00162             vp->status=DESELECTED;
00163             NvertSelect--; NvertDeselect++;
00164           }
00165         }
00166       }
00167     }
00168     else if(op == DLG_SKEL_HIDE){
00169       if((vp=MainVp) != NULL)for(i=0;i<Nvert;i++,vp++){
00170         if((sp1=vp->sp) != NULL && sp1->id == 1 && vp->status != HIDDEN){
00171           drawval=2;
00172           if(vp->status == SELECTED){NvertSelect--; NvertDeselect++;}
00173           vp->status=HIDDEN;
00174         }
00175       }
00176     }
00177     else if(op == 1){ /* select TV */
00178       if((vp=MainVp) != NULL)for(i=0;i<Nvert;i++,vp++){
00179         if(vp->status == DESELECTED && (sp1=vp->sp) != NULL &&
00180           ((!SkSelectFlag && sp1 == sp) || (SkSelectFlag && sp1->id == 1)) ){
00181           if(drawval == 0)drawval=1;
00182           vp->status=SELECTED;
00183           NvertSelect++; NvertDeselect--;
00184         }
00185       }
00186     }
00187     else if(op == 2){ /* deselect TV */
00188       if((vp=MainVp) != NULL)for(i=0;i<Nvert;i++,vp++){
00189         if(vp->status == SELECTED && (sp1=vp->sp) != NULL &&
00190           ((!SkSelectFlag && sp1 == sp) || (SkSelectFlag && sp1->id == 1)) ){
00191           if(drawval == 0)drawval=1;
00192           vp->status=DESELECTED;
00193           NvertSelect--; NvertDeselect++;
00194         }
00195       }
00196     }
00197     else if(op == 3){ /* hide TV */
00198       if((vp=MainVp) != NULL)for(i=0;i<Nvert;i++,vp++){
00199         if((sp1=vp->sp) != NULL &&
00200           ((!SkSelectFlag && sp1 == sp) || (SkSelectFlag && sp1->id == 1)) ){
00201           drawval=2;
00202           if(vp->status == SELECTED){NvertSelect--; NvertDeselect++;}
00203           vp->status=HIDDEN;
00204         }
00205       }
00206     }
00207     else if(op == 4){ /* reveal TV */
00208       if((vp=MainVp) != NULL)for(i=0;i<Nvert;i++,vp++){
00209         if(vp->status == HIDDEN && (sp1=vp->sp) != NULL &&
00210           ((!SkSelectFlag && sp1 == sp) || (SkSelectFlag && sp1->id == 1)) ){
00211           drawval=2;
00212           vp->status=DESELECTED;
00213         }
00214       }
00215     }
00216     if(drawval == 2)DrawModel();
00217     else if(drawval == 1)DrawVerticesOnly(NULL);
00218     UpdateCounters();
00219   }
00220 }
00221 
00222 static void SelectBySk(skel *sp,int op, int children){
00223   vertex *vp;
00224   skel *sp1,*sp2;
00225   int drawval=0;
00226   long i;
00227   if(sp != NULL){
00228     if((sp1=MainSp) != NULL)while(sp1 != NULL){
00229       sp1->id=0; sp1=sp1->last;
00230     }
00231     if(children == 1){ /* plus all selected */
00232       if((sp1=MainSp) != NULL)while(sp1 != NULL){
00233         sp2=sp1;
00234         while(sp2 != NULL){
00235           if(sp2 == sp)sp1->id=1;
00236           sp2=sp2->at;
00237         }
00238         sp1=sp1->last;
00239       }
00240     }
00241     else{ /* just as attached */
00242       if((sp1=MainSp) != NULL)while(sp1 != NULL){
00243         if(sp1 == sp)sp1->id=1;
00244         sp1=sp1->last;
00245       }
00246     }
00247     if(op == SELECTED){
00248       if((vp=MainVp) != NULL)for(i=0;i<Nvert;i++,vp++){
00249         if((sp1=vp->sp) != NULL && sp1->id == 1 && vp->status == DESELECTED){
00250           if(drawval == 0)drawval=1;
00251           vp->status=SELECTED;
00252           NvertSelect++; NvertDeselect--;
00253         }
00254       }
00255     }
00256     else if(op == DESELECTED){
00257       if((vp=MainVp) != NULL)for(i=0;i<Nvert;i++,vp++){
00258         if((sp1=vp->sp) != NULL && sp1->id == 1 && vp->status == SELECTED){
00259           if(drawval == 0)drawval=1;
00260           vp->status=DESELECTED;
00261           NvertSelect--; NvertDeselect++;
00262         }
00263       }
00264     }
00265     if(drawval == 1){
00266       DrawVerticesOnly(NULL); /* WM_PAINT will redraw the skeleton */
00267       UpdateCounters();
00268     }
00269   }
00270 }
00271 
00272 int skintriview(point p){
00273  if( ((p[0] > TVpointX) && (p[0] < TVpointX+TVsizeX))
00274   && ((p[1] > TVpointY) && (p[1] < TVpointY+TVsizeY))
00275   && ((p[2] > TVpointZ) && (p[2] < TVpointZ+TVsizeZ))
00276    )return 1;
00277  return 0;
00278 }
00279 
00280 void SkDelete(skel *sp){
00281  vertex *vp;
00282  long i;
00283  EraseSkeleton(sp);
00284  if((vp=MainVp) != NULL)for(i=0;i<Nvert;i++){ /* remove vertex point to sk */
00285    if(vp->sp == sp)vp->sp=NULL;
00286    vp++;
00287  }
00288  ClearNurbsSkeleton(sp);
00289 }
00290 
00291 void ResetSkeletonWeights(void){
00292  double w=1.0,r=1.0,z=0.1;
00293  skel *sp; 
00294  if(Read3Reals("Reset All Bones",&w,&r,&z,2) == OK){
00295    sp=MainSp; while(sp != NULL){
00296      sp->weight=w;
00297      sp->wrange=r;
00298      sp->wzone=z;
00299      sp=sp->last;
00300    }
00301  }
00302 }
00303 
00304 void AutoVerticesToSkeleton(void){
00305  int i;
00306  vertex *vp;
00307  skel *sp,*nearest_sp;
00308  double d,l,dmin;
00309  vector r;
00310  i=MessageBox(ghwnd_main,"Confirm ?","Auto Assign",MB_YESNO);
00311  if(i != IDYES)return;
00312  sp=MainSp; while(sp != NULL){ 
00313    VECCOPY(sp->xyz,sp->xyz_last);
00314    sp=sp->last;
00315  }
00316  sp=MainSp; while(sp != NULL){ 
00317    if(sp->at != NULL){ // Calcuate lengths and bone directions
00318      VECSUB((double)sp->at->xyz_last,(double)sp->xyz_last,sp->d_last)
00319      sp->len_last=sqrt(DOT(sp->d_last,sp->d_last));
00320      VECSCALE(1.0/sp->len_last,sp->d_last,sp->d_last);     
00321      VECSUB((double)sp->at->xyz,(double)sp->xyz,sp->d)
00322      sp->len=sqrt(DOT(sp->d,sp->d));
00323      VECSCALE(1.0/sp->len,sp->d,sp->d);     
00324    }
00325    sp=sp->last;
00326  }
00327  vp=MainVp; if(MainVp != NULL && Nvert > 0)for(i=0;i<Nvert;i++){
00328    if(vp->status == SELECTED){ 
00329      dmin=(double)MAXUNIT; nearest_sp=NULL;
00330      sp=MainSp; while(sp != NULL){ 
00331        if(sp->at != NULL && sp->weight > 0.0){ // go through each bone and calculate its distance from the vertex
00332         d=GetBoneRelativeDistance(vp->xyz,sp->xyz_last,sp->at->xyz_last,sp->d_last,sp->len_last,&l,r);
00333          d=d/fabs(sp->weight); // to allow for weights to influence 
00334          if(d < dmin){
00335            if(l < sp->wrange+sp->wzone){  // inside range
00336              dmin=d;
00337              nearest_sp=sp;
00338            }
00339          }
00340        }
00341        sp=sp->last;
00342      }
00343      if(nearest_sp != NULL){
00344        vp->sp=nearest_sp;
00345      }
00346    }
00347    vp++;
00348  }
00349  sp=MainSp; while(sp != NULL){ 
00350    GetSkeletonBoundBox(sp,0);
00351    sp=sp->last;
00352  }
00353 }
00354 
00355 static void SkTwist(void){
00356  int x,xo,MickeyX;
00357  POINT pt;
00358  long xp,yp,evTime;
00359  double I,ltr[4][4];
00360  skel *sp;
00361  if(SkSelectedNode1 == NULL)return;
00362  GetCursorPos(&pt); xo=pt.x;
00363  sp=SkSelectedNode1;
00364  ClipCursor(NULL);
00365  evTime=GetTickCount()+TIME_DELAY;
00366  do {
00367    if(evTime > GetTickCount())continue;
00368    GetCursorPos(&pt); x=pt.x;
00369    MickeyX = x-xo; xo=x;
00370    if(MickeyX != 0){
00371      if(MickeyX > 0)I=(double)max( 1,min( 45,MickeyX));
00372      else           I=(double)min(-1,max(-45,MickeyX));
00373      DrawSkeleton();
00374      rotate_round_vector(I,sp->v,ltr);
00375      mv4by1(ltr,sp->u,sp->u);
00376      mv4by1(ltr,sp->w,sp->w);
00377      DrawSkeleton();
00378    }
00379    evTime=GetTickCount()+TIME_DELAY;
00380  }
00381  while (GetAsyncKeyState(VK_LBUTTON) & 0x8000);
00382  return;
00383 }
00384 
00385 static double GetBoneRelativeDistance(point v, point s, point sp, vector d, double len, double *l, vector r){
00386  vector dp,q;
00387  double ll;
00388  VECSUB((double)v,(double)s,dp)
00389  ll=DOT(dp,d);
00390  if(ll < 0.0){ // closest point is behind start
00391    *l=0.0;     // fraction of bone to offset vector
00392    VECSUB((double)v,(double)s,r)
00393  }
00394  else if(ll > len){ // closest point is beyond end
00395    *l=1.0;   
00396    VECSUB((double)v,(double)sp,r)
00397  } 
00398  else{
00399    *l=ll/len;
00400    VECSUM((double)s,ll*d,q)
00401    VECSUB((double)v,q,r)
00402  }  
00403  return sqrt(DOT(r,r));  // closest distance of v to bone from (s to sp) 
00404 }
00405 
00406 static void GetNewVertexPositionForBone(skel *sp, vector p){
00407  double l;
00408  vector pb;
00409  l=sp->len * sp->l; // this is relative position along new bone of start point of vector to P
00410  VECSUM((double)sp->xyz,l*sp->d,pb)
00411  VECSUM(pb,sp->r,p) // this is the position of the vertex relative to the new bone's position
00412 }
00413 
00414 static void GetNewVertexPositionForRotatedBone(skel *sp, point v, vector p){
00415  m4by1(sp->tr,(double)v[0],(double)v[1],(double)v[2],&p[0],&p[1],&p[2]);
00416 }
00417 
00418 
00419 static void RubberBonesDeformConstant(void){ // Perform rubber Bones Action constant scaling - constant effect inside range
00420  int i;  
00421  vertex *vp;
00422  skel *sp,*spsel;
00423  double l,f,x,ff,wsum;
00424  vector r,p,nv;
00425  // setup 
00426  sp=MainSp; while(sp != NULL){ 
00427    if(sp->at != NULL){ // Calcuate lengths and bone directions
00428      VECSUB((double)sp->at->xyz_last,(double)sp->xyz_last,sp->d_last)
00429      sp->len_last=sqrt(DOT(sp->d_last,sp->d_last));
00430      VECSCALE(1.0/sp->len_last,sp->d_last,sp->d_last);     
00431      VECSUB((double)sp->at->xyz,(double)sp->xyz,sp->d)
00432      sp->len=sqrt(DOT(sp->d,sp->d));
00433      VECSCALE(1.0/sp->len,sp->d,sp->d);     
00434    }
00435    sp=sp->last;
00436  }
00437  // now move each selected vertex
00438  vp=MainVp; if(MainVp != NULL && Nvert > 0)for(i=0;i<Nvert;i++){
00439    if(vp->status == SELECTED){   
00440      wsum=0.0;
00441      sp=MainSp; while(sp != NULL){ 
00442        sp->r_scale=0.0; 
00443        if(sp->at != NULL){ // go through each bone and calculate its distance from the vertex
00444          sp->r_dist=GetBoneRelativeDistance(vp->xyz,sp->xyz_last,sp->at->xyz_last,
00445                           sp->d_last,sp->len_last,&l,r);
00446          sp->l=l;  // relative position along bone to which vertex is closest
00447          VECCOPY(r,sp->r) // vector from (point l to vertex) 
00448          if(sp->r_dist < sp->wrange*ruler){  // bone is in range
00449            f=(sp->wrange-sp->wzone)*ruler;
00450            sp->r_scale=sp->weight;
00451            if(l < 1.e-3 || l > 1-1.e-3){  // at end of bone
00452              ff=sqrt(1.0 - sp->r_dist/(sp->wrange*ruler));  // fall off for all vertices
00453              sp->r_scale *= ff;
00454            }
00455            else if((x=sp->r_dist - f) > 0){ // in the transition zone
00456              sp->r_scale *= (1.0-x/f);
00457            }  
00458            wsum += sp->r_scale;
00459          }
00460        }
00461        sp=sp->last;
00462      }
00463      if(wsum > 0.0){ // there are some changes to this vertex, otherwise no change to this vertex
00464        nv[0]=nv[1]=nv[2]=0.0; 
00465        sp=MainSp; while(sp != NULL){ // scale weights
00466          if(sp->at != NULL){ // go through each bone and calculate the new position based on any bone move
00467            if(SkRubberBonesRotate)GetNewVertexPositionForRotatedBone(sp,vp->xyz,p);
00468            else                   GetNewVertexPositionForBone(sp,p);
00469            VECSUM(nv,(sp->r_scale/wsum)*p,nv)  // weight the new point
00470          }
00471          sp=sp->last;
00472        }
00473        // assign new vertex position based on bone weight
00474        VECCOPY((long)nv,vp->xyz)
00475      }
00476    }
00477    vp++;
00478  }
00479 }
00480 
00481 static void RubberBonesDeformVariable(void){ // Perform rubber Bones Action  with variable scaling - strength proportionate to distance from bone - no matter how close
00482  int i;
00483  vertex *vp;
00484  skel *sp;
00485  double l,dmin,dthresh=32,wsum;
00486  vector r,p,nv;
00487  // setup 
00488  sp=MainSp; while(sp != NULL){ 
00489    if(sp->at != NULL){ // Calcuate lengths and bone directions
00490      VECSUB((double)sp->at->xyz_last,(double)sp->xyz_last,sp->d_last)
00491      sp->len_last=sqrt(DOT(sp->d_last,sp->d_last));
00492      VECSCALE(1.0/sp->len_last,sp->d_last,sp->d_last);     
00493      VECSUB((double)sp->at->xyz,(double)sp->xyz,sp->d)
00494      sp->len=sqrt(DOT(sp->d,sp->d));
00495      VECSCALE(1.0/sp->len,sp->d,sp->d);     
00496    }
00497    sp=sp->last;
00498  }
00499  // now move each selected vertex
00500  vp=MainVp; if(MainVp != NULL && Nvert > 0)for(i=0;i<Nvert;i++){
00501    if(vp->status == SELECTED){   
00502      dmin=(double)MAXUNIT;
00503      sp=MainSp; while(sp != NULL){ 
00504        if(sp->at != NULL){ // go through each bone and calculate its distance from the vertex
00505          sp->r_scale=max(dthresh,(sp->r_dist=GetBoneRelativeDistance(vp->xyz,sp->xyz_last,sp->at->xyz_last,
00506                           sp->d_last,sp->len_last,&l,r)));
00507          sp->l=l;  // relative position along bone to which vertex is closest
00508          VECCOPY(r,sp->r) // vector from (point l to vertex) 
00509          if(sp->r_scale < dmin)dmin=sp->r_scale;
00510        }
00511        sp=sp->last;
00512      }
00513      wsum=0.0;
00514      sp=MainSp; while(sp != NULL){ // calculate bone influence
00515        if(sp->at != NULL){ // go through each bone and calculate its distance from the vertex
00516          sp->r_scale = (dmin/(sp->r_scale))*(dmin/(sp->r_scale))*sp->weight;
00517          if(sp->r_dist > (sp->wrange-sp->wzone)*ruler){  // bone is out of range
00518            if(sp->r_dist > sp->wrange*ruler)sp->r_scale=0.0;
00519            else{
00520              double s = (sp->r_dist - (sp->wrange-sp->wzone)*ruler)/(sp->wzone*ruler);
00521              sp->r_scale *= (1.0-s); 
00522            }
00523          } 
00524          wsum += sp->r_scale;   
00525        }
00526        sp=sp->last;
00527      }
00528      if(wsum > 1.e-4){ // there are some changes to this vertex, otherwise no change to this vertex
00529        sp=MainSp; while(sp != NULL){ // scale influences so all influences sum to 1.0 (unless bones are out of range
00530          if(sp->at != NULL){
00531            sp->r_scale /= wsum;
00532          }
00533          sp=sp->last;
00534        }
00535        // now each bone contains the weight influence to move the bone based on its last position
00536        // find the vertex position based on the new bone positions
00537        nv[0]=nv[1]=nv[2]=0.0; 
00538        sp=MainSp; while(sp != NULL){ // scale weights
00539          if(sp->at != NULL){ // go through each bone and calculate the new position based on any bone move
00540            if(SkRubberBonesRotate)GetNewVertexPositionForRotatedBone(sp,vp->xyz,p);
00541            else                   GetNewVertexPositionForBone(sp,p);
00542            VECSUM(nv,(sp->r_scale)*p,nv)  // weight the new point
00543          }
00544          sp=sp->last;
00545        }
00546        // assign new vertex position based on bone weight
00547        VECCOPY((long)nv,vp->xyz)
00548      }
00549    }
00550    vp++;
00551  }
00552 }
00553 
00554 static void RubberBonesDeform(void){ // call the appropriate model
00555  if(rubberbone_model == 0)RubberBonesDeformVariable();
00556  else                     RubberBonesDeformConstant();
00557 }
00558 
00559 static void SkRotateRubberBones(void){ 
00560  int x,xo,MickeyX;
00561  POINT pt;
00562  long xp,yp,evTime;
00563  double I,ltr[4][4],sst[4][4],xr,yr,zr;
00564  skel *sp,*ls,*ssp;
00565  point p2;
00566  vector v;
00567  if((ls=LastSkeletonVertex) == NULL)return;
00568  GetCursorPos(&pt); xo=pt.x;
00569  ClipCursor(NULL);
00570  evTime=GetTickCount()+TIME_DELAY;
00571  do {
00572    if(evTime > GetTickCount())continue;
00573    GetCursorPos(&pt); x=pt.x;
00574    MickeyX = x-xo; xo=x;
00575    if(MickeyX != 0){
00576      DrawSkeleton();
00577      if(MickeyX > 0)I=(double)max( 1,min( 45,MickeyX));
00578      else           I=(double)min(-1,max(-45,MickeyX));
00579      if     (ActiveView == 0){v[0] =  0.0; v[1] = 0.0; v[2] = 1.0;} // perpendicular to active window
00580      else if(ActiveView == 1){v[0] =  0.0; v[1] = 1.0; v[2] = 0.0;}
00581      else if(ActiveView == 2){v[0] = -1.0; v[1] = 0.0; v[2] = 0.0;}
00582      if(ls->at == NULL){  /* main node */
00583        VECSCALE(1000.0*(double)UNIT2,v,v)
00584        VECSUM((double)ls->xyz,v,v)
00585        mv4by1(ls->t,v,v);
00586        VECCOPY((long)v,p2)
00587        arbitrary_rotate(I,ls->tp,p2,ltr);
00588      }
00589      else{
00590        VECSCALE(1000.0*(double)UNIT2,v,v)
00591        VECSUM((double)ls->at->xyz,v,v)
00592        mv4by1(ls->at->t,v,v);
00593        VECCOPY((long)v,p2)
00594        arbitrary_rotate(I,ls->at->tp,p2,ltr);
00595      }
00596      ssp=MainSp; while(ssp != NULL){  // work out transformation matrices
00597        sp=ssp; while(sp != NULL){
00598          if(sp == LastSkeletonVertex){
00599            m4by4(ltr,ssp->t,sst);
00600            c4to4(sst,ssp->t);
00601            break;
00602          }
00603          sp=sp->at;
00604        }
00605        ssp=ssp->last;
00606      }
00607      sp=MainSp; while(sp != NULL){ // apply transformation matrices 
00608         m4by4(sp->t,sp->tr,sst); c4to4(sst,sp->tr);  // tr is the total transform
00609         m4by1(sp->t,(double)(sp->xyz[0]),(double)(sp->xyz[1])
00610               ,(double)(sp->xyz[2]),&xr,&yr,&zr);
00611         sp->xyz[0]=(long)xr; sp->xyz[1]=(long)yr; sp->xyz[2]=(long)zr;
00612         null_transform(sp->t);  // must reset as Skeleton has been moved
00613         sp=sp->last;
00614      }
00615      DrawSkeleton();
00616    }
00617    evTime=GetTickCount()+TIME_DELAY;
00618  }
00619  while (GetAsyncKeyState(VK_LBUTTON) & 0x8000);
00620  return;
00621 }
00622 
00623 static void SkPivot(void){  // SKANIMATE tool - manipulate skeleton pose interactively
00624  int x,xo,MickeyX;          // display shows only skeleton and bounding box
00625  POINT pt;
00626  long xp,yp,evTime;
00627  double I,ltr[4][4],sst[4][4];
00628  skel *sp,*ls,*ssp;
00629  point p2;
00630  vector v;
00631  if((ls=LastSkeletonVertex) == NULL)return;
00632  GetCursorPos(&pt); xo=pt.x;
00633  sp=SkSelectedNode1;
00634  ClipCursor(NULL);
00635  evTime=GetTickCount()+TIME_DELAY;
00636  do {
00637    if(evTime > GetTickCount())continue;
00638    GetCursorPos(&pt); x=pt.x;
00639    MickeyX = x-xo; xo=x;
00640    if(MickeyX != 0){
00641      if(MickeyX > 0)I=(double)max( 1,min( 45,MickeyX));
00642      else           I=(double)min(-1,max(-45,MickeyX));
00643      if(1){ /* ctrl */
00644        if(ls->at == NULL){  /* main node */
00645          if     (SelectedSkeletonAxis == RED_AXIS  )VECCOPY(ls->u,v)
00646          else if(SelectedSkeletonAxis == GREEN_AXIS)VECCOPY(ls->v,v)
00647          else                                       VECCOPY(ls->w,v)
00648          VECSCALE(1000.0*(double)UNIT2,v,v)
00649          VECSUM((double)ls->xyz,v,v)
00650          mv4by1(ls->t,v,v);
00651          VECCOPY((long)v,p2)
00652          arbitrary_rotate(I,ls->tp,p2,ltr);
00653        }
00654        else{
00655          if(SelectedSkeletonAxis == NODE_AXIS){
00656            arbitrary_rotate(I,ls->tp,ls->at->tp,ltr);
00657          }
00658          else{
00659            if     (SelectedSkeletonAxis == RED_AXIS   )VECCOPY(ls->at->u,v)
00660            else if(SelectedSkeletonAxis == GREEN_AXIS )VECCOPY(ls->at->v,v)
00661            else if(SelectedSkeletonAxis == YELLOW_AXIS)VECCOPY(ls->at->w,v)
00662            VECSCALE(1000.0*(double)UNIT2,v,v)
00663            VECSUM((double)ls->at->xyz,v,v)
00664            mv4by1(ls->at->t,v,v);
00665            VECCOPY((long)v,p2)
00666            arbitrary_rotate(I,ls->at->tp,p2,ltr);
00667          }
00668        }
00669      }
00670      else{
00671        null_transform(ltr);   /* do nothing */
00672      }
00673      ssp=MainSp; while(ssp != NULL){
00674        sp=ssp; while(sp != NULL){
00675          if(sp == LastSkeletonVertex){
00676            m4by4(ltr,ssp->t,sst);
00677            c4to4(sst,ssp->t);
00678            break;
00679          }
00680          sp=sp->at;
00681        }
00682        ssp=ssp->last;
00683      }
00684      DrawModel();
00685      if(ghwndOpenGLview == NULL)Draw3dView(0,0);
00686      UpdateWindow(ghwnd_view);
00687    }
00688    evTime=GetTickCount()+TIME_DELAY;
00689  }
00690  while (GetAsyncKeyState(VK_LBUTTON) & 0x8000);
00691  return;
00692 }
00693 
00694 static void DrawTrSkeletonAxes(skel *sp,int view,int sh1,int sv1, HDC hDC){
00695  HPEN holdPen=NULL;
00696  int i,j,draw,draw_red,draw_green,draw_yellow;
00697  vector vpu,vpv,vpw;
00698  point pu,pv,pw;
00699  double s,x,y,z;
00700  long ix,iy,iz;
00701  int sh2,sv2,sh[8],sv[8];
00702  draw_red=NO; draw_green=NO; draw_yellow=NO;
00703  if(sp == SkSelectedNode1){
00704    if(SelectedSkeletonAxis == RED_AXIS   )draw_red=YES;
00705    if(SelectedSkeletonAxis == GREEN_AXIS )draw_green=YES;
00706    if(SelectedSkeletonAxis == YELLOW_AXIS)draw_yellow=YES;
00707    s=(double)TVsizeX/10;
00708    draw=YES;
00709    holdPen=SelectObject(hDC,ghSelectedPen);
00710  }
00711  else if(sp == SkSelectedNode2){
00712    if(SelectedSkeletonAxis == NODE_AXIS){
00713      holdPen=SelectObject(hDC,ghSelectedPen);
00714      draw_green=YES;
00715    }
00716    s=(double)TVsizeX/15;
00717    draw=YES;
00718  }
00719  else{
00720    s=(double)TVsizeX/15;
00721    draw=NO;
00722  }
00723  if(draw){
00724    for(i=0;i<3;i++){
00725      vpu[i]=(s * sp->u[i]) + (double)sp->xyz[i];
00726      vpv[i]=(s * sp->v[i]) + (double)sp->xyz[i];
00727      vpw[i]=(s * sp->w[i]) + (double)sp->xyz[i];
00728    }
00729    m4by1(sp->t,vpu[0],vpu[1],vpu[2],&x,&y,&z);
00730    pu[0]=(long)x; pu[1]=(long)y; pu[2]=(long)z;
00731    m4by1(sp->t,vpv[0],vpv[1],vpv[2],&x,&y,&z);
00732    pv[0]=(long)x; pv[1]=(long)y; pv[2]=(long)z;
00733    m4by1(sp->t,vpw[0],vpw[1],vpw[2],&x,&y,&z);
00734    pw[0]=(long)x; pw[1]=(long)y; pw[2]=(long)z;
00735    GetWindowCoords(view,pu[0],pu[1],pu[2],&sh2,&sv2);
00736    if(draw_red == YES){
00737      MoveToEx(hDC,sh2,sv2,NULL); LineTo(hDC,sh1,sv1);
00738      Ellipse(hDC,sh2-2,sv2-2,sh2+3,sv2+3);
00739    }
00740    GetWindowCoords(view,pv[0],pv[1],pv[2],&sh2,&sv2);
00741    if(draw_green == YES){
00742      MoveToEx(hDC,sh2,sv2,NULL); LineTo(hDC,sh1,sv1);
00743      Ellipse(hDC,sh2-2,sv2-2,sh2+3,sv2+3);
00744    }
00745    GetWindowCoords(view,pw[0],pw[1],pw[2],&sh2,&sv2);
00746    if(draw_yellow == YES){
00747      MoveToEx(hDC,sh2,sv2,NULL); LineTo(hDC,sh1,sv1);
00748      Ellipse(hDC,sh2-2,sv2-2,sh2+3,sv2+3);
00749    }
00750  }
00751  if(holdPen != NULL)SelectObject(hDC,holdPen);
00752  for(i=0;i<8;i++){
00753    m4by1(sp->t,(double)(sp->bx[i][0]),
00754                (double)(sp->bx[i][1]),
00755                (double)(sp->bx[i][2]),&x,&y,&z);
00756    GetWindowCoords(view,(long)x,(long)y,(long)z,&sh[i],&sv[i]);
00757  }
00758  if(sh[0] == sh1 &&    /* if box is zero size quit */
00759     sv[0] == sv1 &&
00760     sh[1] == sh1 &&
00761     sv[1] == sv1 &&
00762     sh[4] == sh1 &&
00763     sv[4] == sv1)return;
00764  for(i=0;i<12;i++){
00765    MoveToEx(hDC,sh[ep1[i]],sv[ep1[i]],NULL);
00766    LineTo(hDC,sh[ep2[i]],sv[ep2[i]]);
00767  }
00768  return;
00769 }
00770 
00771 void DrawTrSkeletonInOne(HDC hDC, int view){
00772  HBRUSH holdBrush;
00773  HPEN   holdPen,holdPen1;
00774  int sh1,sv1,sh2,sv2,i;
00775  double x,y,z;
00776  skel *sp;
00777  if(Nskel == 0 || MainSp == NULL)return;
00778  holdPen=SelectObject(hDC,ghEdgePen);
00779  holdBrush=SelectObject(hDC,GetStockObject(HOLLOW_BRUSH));
00780  SelectPalette(hDC,ghpaletteScreen,FALSE);
00781  RealizePalette(hDC);
00782  sp=MainSp;
00783  while(sp != NULL){
00784    m4by1(sp->t,(double)(sp->xyz[0]),(double)(sp->xyz[1])
00785               ,(double)(sp->xyz[2]),&x,&y,&z);
00786    sp->tp[0]=(long)x; sp->tp[1]=(long)y; sp->tp[2]=(long)z;
00787    sp=sp->last;
00788  }
00789  sp=MainSp;
00790  while(sp != NULL){
00791   if(skintriview(sp->tp) || (sp->at != NULL && skintriview(sp->at->tp))){
00792     GetWindowCoords(view,sp->tp[0],sp->tp[1],sp->tp[2],&sh1,&sv1);
00793     if(sp->at != NULL){
00794       GetWindowCoords(view,sp->at->tp[0],
00795                       sp->at->tp[1],sp->at->tp[2],&sh2,&sv2);
00796       MoveToEx(hDC,sh1,sv1,NULL); LineTo(hDC,sh2,sv2);
00797     }
00798     if(sp == LastSkeletonVertex)holdPen1=SelectObject(hDC,ghInvertPen);
00799     if(sp == FirstSp)Rectangle(hDC,sh1-4,sv1-4,sh1+5,sv1+5);
00800     else Ellipse(hDC,sh1-3,sv1-3,sh1+4,sv1+4);
00801     if(sp == LastSkeletonVertex)SelectObject(hDC,holdPen1);
00802     DrawTrSkeletonAxes(sp,view,sh1,sv1,hDC);
00803   }
00804   sp=sp->last;
00805  }
00806  SelectObject(hDC,holdPen);
00807  SelectObject(hDC,holdBrush);
00808 }
00809 
00810 static void DrawSkeletonAxes(skel *sp,int view,int sh1,int sv1, HDC hDC){
00811  HPEN holdPen;
00812  point pu,pv,pw;
00813  double s;
00814  int i,sh2,sv2;
00815  if(sp == SkSelectedNode1)s=(double)TVsizeX/5;
00816  else                     s=(double)TVsizeX/20;
00817  for(i=0;i<3;i++){
00818    pu[i]=(long)(s * sp->u[i]) + sp->xyz[i];
00819    pv[i]=(long)(s * sp->v[i]) + sp->xyz[i];
00820    pw[i]=(long)(s * sp->w[i]) + sp->xyz[i];
00821  }
00822  holdPen=SelectObject(hDC,ghSelectorPen);
00823  GetWindowCoords(view,pu[0],pu[1],pu[2],&sh2,&sv2);
00824  MoveToEx(hDC,sh1,sv1,NULL); LineTo(hDC,sh2,sv2);
00825  SelectObject(hDC,ghDeselectorPen);
00826  GetWindowCoords(view,pw[0],pw[1],pw[2],&sh2,&sv2);
00827  MoveToEx(hDC,sh1,sv1,NULL); LineTo(hDC,sh2,sv2);
00828  SelectObject(hDC,holdPen);
00829 }
00830 
00831 static void DrawSkeletonRubberBone(skel *sp1, int view, HDC hDC){
00832  HPEN holdPen;
00833  int sh1,sv1,sh2,sv2,dx,dy;
00834  skel *sp;
00835  sp=sp1;
00836  holdPen=SelectObject(hDC,ghDeselectorPen);
00837  GetWindowCoords(view,sp->xyz[0],sp->xyz[1],sp->xyz[2],&sh1,&sv1);
00838  if(view == TRITOP)       GetWindowCoords(view,sp->xyz[0]+(long)(sp->wrange*ruler),sp->xyz[1],sp->xyz[2],&sh2,&sv2);
00839  else if(view == TRIFRONT)GetWindowCoords(view,sp->xyz[0]+(long)(sp->wrange*ruler),sp->xyz[1],sp->xyz[2],&sh2,&sv2);
00840  else if(view == TRIRIGHT)GetWindowCoords(view,sp->xyz[0],sp->xyz[1]+(long)(sp->wrange*ruler),sp->xyz[2],&sh2,&sv2);
00841  dy=dx=sh2-sh1; 
00842  Ellipse(hDC,sh1-dx,sv1-dy,sh1+dx,sv1+dy);
00843  if((sp=sp1->at) != NULL && fabs(sp->wrange-sp1->wrange) > 0.1){
00844    GetWindowCoords(view,sp->xyz[0],sp->xyz[1],sp->xyz[2],&sh1,&sv1);
00845    if(view == TRITOP)       GetWindowCoords(view,sp->xyz[0]+(long)(sp1->wrange*ruler),sp->xyz[1],sp->xyz[2],&sh2,&sv2);
00846    else if(view == TRIFRONT)GetWindowCoords(view,sp->xyz[0]+(long)(sp1->wrange*ruler),sp->xyz[1],sp->xyz[2],&sh2,&sv2);
00847    else if(view == TRIRIGHT)GetWindowCoords(view,sp->xyz[0],sp->xyz[1]+(long)(sp->wrange*ruler),sp->xyz[2],&sh2,&sv2);
00848    dy=dx=sh2-sh1; 
00849    Ellipse(hDC,sh1-dx,sv1-dy,sh1+dx,sv1+dy);
00850  }
00851  // Edges??
00852  SelectObject(hDC,holdPen);
00853 }
00854 
00855 void DrawSkeletonInOne(HDC hDC, int view){
00856  HBRUSH holdBrush;
00857  HPEN   holdPen;
00858  int    oldROP;
00859  int sh1,sv1,sh2,sv2,i;
00860  skel *sp;
00861  holdPen=SelectObject(hDC,ghInvertPen);
00862  holdBrush=SelectObject(hDC,GetStockObject(HOLLOW_BRUSH));
00863  oldROP=SetROP2(hDC,R2_XORPEN);
00864  SelectPalette(hDC,ghpaletteScreen,FALSE);
00865  RealizePalette(hDC);
00866  DrawOne3dCursor(hDC,view);
00867  sp=MainSp;
00868  while(sp != NULL){
00869   if(skintriview(sp->xyz) || (sp->at != NULL && skintriview(sp->at->xyz))){
00870     GetWindowCoords(view,sp->xyz[0],sp->xyz[1],sp->xyz[2],&sh1,&sv1);
00871     if(sp->at != NULL){
00872       GetWindowCoords(view,sp->at->xyz[0],
00873                       sp->at->xyz[1],sp->at->xyz[2],&sh2,&sv2);
00874       MoveToEx(hDC,sh1,sv1,NULL); LineTo(hDC,sh2,sv2);
00875     }
00876     if(sp == FirstSp)Rectangle(hDC,sh1-4,sv1-4,sh1+5,sv1+5);
00877     else             Ellipse(hDC,sh1-3,sv1-3,sh1+4,sv1+4);
00878     DrawSkeletonAxes(sp,view,sh1,sv1,hDC);
00879     DrawSkeletonRubberBone(sp,view,hDC);
00880   }
00881   sp=sp->last;
00882  }
00883  DrawOne3dCursor(hDC,view);
00884  SelectObject(hDC,holdPen);
00885  SelectObject(hDC,holdBrush);
00886  SetROP2(hDC,oldROP);
00887 }
00888 
00889 void TidyUpOldSkeltonType(void){
00890  skel *sp;
00891  if((sp=FirstSp) != NULL)while(sp != NULL){
00892    DefaultOrientAxes(sp);
00893    GetSkeletonBoundBox(sp,0); /* do NOT assign */
00894    sp=sp->next;
00895  }
00896 }
00897 
00898 void TabSkeletonAxis(void){
00899   SelectedSkeletonAxis++;
00900   if(SelectedSkeletonAxis > 3)SelectedSkeletonAxis=0;
00901   DrawModel();
00902 }
00903 
00904 void SkToolOn(void){
00905  LastSkeletonVertex=NULL;
00906  SkSelectedNode1=NULL; SkSelectedNode2=NULL;
00907  if(tool == SKANIMATE){
00908    short i;
00909    skel *sp;
00910    if((sp=MainSp) != NULL)while(sp != NULL){
00911      null_transform(sp->t);
00912      for(i=0;i<3;i++)sp->tp[i]=sp->xyz[i];
00913      sp=sp->last;
00914    }
00915    Save_Undo(1);
00916  }
00917  else if(tool == SKRUBBERBONES)Save_Undo(1);
00918 }
00919 
00920 void SkToolOff(void){
00921  LastSkeletonVertex=NULL;
00922  SkSelectedNode1=NULL; SkSelectedNode2=NULL;
00923  if(tool == SKANIMATE){
00924    int i;
00925    double x,y,z;
00926    vector p;
00927    skel *sp;
00928    vertex *vp;
00929    if((sp=MainSp) != NULL)while(sp != NULL){
00930      for(i=0;i<3;i++)sp->xyz[i]=sp->tp[i];
00931      sp=sp->last;
00932    }
00933    if((vp=MainVp) != NULL && Nvert > 0)for(i=0;i<Nvert;i++){ /* move vertices */
00934      if(vp->sp != NULL){
00935        m4by1(vp->sp->t,(double)vp->xyz[0],(double)vp->xyz[1]
00936                       ,(double)vp->xyz[2],&x,&y,&z);
00937        vp->xyz[0]=(long)x; vp->xyz[1]=(long)y; vp->xyz[2]=(long)z;
00938      }
00939      vp++;
00940    }
00941    if((sp=MainSp) != NULL)while(sp != NULL){ /* move axes and bounding box */
00942      for(i=0;i<8;i++){
00943        m4by1(sp->t,(double)sp->bx[i][0],(double)sp->bx[i][1]
00944                   ,(double)sp->bx[i][2],&x,&y,&z);
00945        sp->bx[i][0]=(long)x; sp->bx[i][1]=(long)y; sp->bx[i][2]=(long)z;
00946      }
00947      VECSCALE((double)UNIT2*1000.0,sp->u,p) VECSUM(p,(double)sp->xyz,p)
00948      m4by1(sp->t,p[0],p[1],p[2],&(sp->u[0]),&(sp->u[1]),&(sp->u[2]));
00949      VECSUB(sp->u,(double)sp->xyz,sp->u) O_normalize(sp->u);
00950      VECSCALE((double)UNIT2*1000.0,sp->v,p) VECSUM(p,(double)sp->xyz,p)
00951      m4by1(sp->t,p[0],p[1],p[2],&(sp->v[0]),&(sp->v[1]),&(sp->v[2]));
00952      VECSUB(sp->v,(double)sp->xyz,sp->v) O_normalize(sp->v);
00953      VECSCALE((double)UNIT2*1000.0,sp->w,p) VECSUM(p,(double)sp->xyz,p)
00954      m4by1(sp->t,p[0],p[1],p[2],&(sp->w[0]),&(sp->w[1]),&(sp->w[2]));
00955      VECSUB(sp->w,(double)sp->xyz,sp->w) O_normalize(sp->w);
00956      sp=sp->last;
00957    }
00958  }
00959 }
00960 
00961 void SkToolDown(int x, int y){
00962  SkMovedFlag=FALSE;
00963  if(tool == SKADD){
00964    SkAssNode=NULL;
00965    if(LastSkeletonVertex != NULL){
00966      LastSkeletonPoint[0]=NpointerX;
00967      LastSkeletonPoint[1]=NpointerY;
00968      LastSkeletonPoint[2]=NpointerZ;
00969      DrawRubber3dLine(LastSkeletonPoint,LastSkeletonVertex->xyz);
00970    }
00971    else{  // if not selected
00972      LastSkeletonVertex=PickSkeleton(x,y,ActiveView);
00973      if(LastSkeletonVertex != NULL){
00974        LastSkeletonPoint[0]=NpointerX;
00975        LastSkeletonPoint[1]=NpointerY;
00976        LastSkeletonPoint[2]=NpointerZ;
00977        DrawRubber3dLine(LastSkeletonPoint,LastSkeletonVertex->xyz);
00978      }
00979    }
00980  }
00981  else if(tool == SKGRAB){
00982    LastSkeletonVertex=NULL;
00983    if(!(GetAsyncKeyState(VK_CONTROL) & 0x8000))
00984      LastSkeletonVertex=PickSkeleton(x,y,ActiveView);
00985  }
00986  else if(tool == SKRENAME){
00987    LastSkeletonVertex=NULL;
00988    if(!(GetAsyncKeyState(VK_CONTROL) & 0x8000))
00989      LastSkeletonVertex=PickSkeleton(x,y,ActiveView);
00990  }
00991  else if(tool == SKRUBBERBONES){
00992    skel *sp;
00993    int i; 
00994    LastSkeletonVertex=NULL;
00995    if(GetKeyState(VK_MENU) & 0x8000)SkRubberBonesRotate=TRUE;
00996    LastSkeletonVertex=PickSkeleton(x,y,ActiveView);
00997    sp=MainSp;
00998    while(sp != NULL){
00999      VECCOPY(sp->xyz,sp->xyz_last);
01000      null_transform(sp->t);
01001      null_transform(sp->tr);  // cumulated transform for moving rubber bones
01002      for(i=0;i<3;i++)sp->tp[i]=sp->xyz[i];
01003      sp=sp->last;
01004    }
01005  }
01006  else if(tool == SKTWIST){
01007    LastSkeletonVertex=NULL;
01008    if(!(GetAsyncKeyState(VK_CONTROL) & 0x8000))
01009      LastSkeletonVertex=PickSkeleton(x,y,ActiveView);
01010    if(LastSkeletonVertex != NULL){
01011      DrawSkeleton(); SkSelectedNode1=LastSkeletonVertex; DrawSkeleton();
01012    }
01013  }
01014  else if(tool == SKDUPLICATE || tool == SKSELECT){
01015    LastSkeletonVertex=NULL;
01016    if(!(GetAsyncKeyState(VK_CONTROL) & 0x8000))SkToolAction(x,y); 
01017  }
01018  else if(tool == SKDELETE || tool == SKSUBDIV || tool == SKASSIGN){
01019    LastSkeletonVertex=NULL;
01020    if(!(GetAsyncKeyState(VK_CONTROL) & 0x8000))SkToolAction(x,y);
01021  }
01022  else if(tool == SKANIMATE){
01023    long x1,y1,z1;
01024    skel *sp,*sf;
01025    double d,dmin,dth;
01026    int sho,svo;
01027    sp=MainSp;  sf=NULL;
01028    dmin=(double)TVsizeX*(double)TVsizeX;
01029    dth=dmin/32/32;
01030    while(sp != NULL){
01031      GetWindowCoords(ActiveView,sp->tp[0],sp->tp[1],sp->tp[2],&sho,&svo);
01032      if( (sho > x-4) && (sho < x+4) && (svo > y-4) && (svo < y+4)){
01033        d=(double)(sp->tp[0]-NpointerX)*(double)(sp->tp[0]-NpointerX)
01034         +(double)(sp->tp[1]-NpointerY)*(double)(sp->tp[1]-NpointerY)
01035         +(double)(sp->tp[2]-NpointerZ)*(double)(sp->tp[2]-NpointerZ);
01036        if(d < dmin){
01037          dmin=d;
01038          sf=sp;
01039        }
01040      }
01041      sp=sp->last;
01042    }
01043    if(sf != NULL){
01044      LastSkeletonVertex=sf;
01045      if(sf->at != NULL){
01046        SkSelectedNode1=sf->at;
01047        SkSelectedNode2=sf;
01048      }
01049      else{
01050        SkSelectedNode1=sf;
01051        SkSelectedNode2=NULL;
01052      }
01053      DrawModel();
01054    }
01055  }
01056 }
01057 
01058 void SkToolUp(int x, int y){
01059  if(tool == SKADD){
01060    if(LastSkeletonVertex != NULL){
01061      LastSkeletonPoint[0]=NpointerX;  // Draw it away
01062      LastSkeletonPoint[1]=NpointerY;
01063      LastSkeletonPoint[2]=NpointerZ;
01064      DrawRubber3dLine(LastSkeletonPoint,LastSkeletonVertex->xyz);
01065      if(SkMovedFlag && !(GetAsyncKeyState(VK_CONTROL) & 0x8000)){
01066                        //     DrawRubber3dLine(LastSkeletonPoint,LastSkeletonVertex->xyz);
01067        SkToolAction(x,y); // make the node!!
01068      }
01069    }
01070    if(SkAssNode != NULL){
01071      DrawSkeleton();
01072      Read1String3Real("Bone Properties","Name","Weight","Range(Ruler)","Zone(Ruler)",SkAssNode->name,
01073                       &(SkAssNode->weight),&(SkAssNode->wrange),&(SkAssNode->wzone),ghwnd_main);
01074      DrawSkeleton();
01075      SkAssNode=NULL;
01076    }
01077  }
01078  else if(tool == SKRENAME){
01079    if(LastSkeletonVertex != NULL){
01080      DrawSkeleton();
01081      Read1String3Real("Bone Properties","Name","Weight","Range (Ruler)","Zone(Ruler)",LastSkeletonVertex->name,
01082                       &(LastSkeletonVertex->weight),&(LastSkeletonVertex->wrange),&(LastSkeletonVertex->wzone),ghwnd_main);
01083      DrawSkeleton();
01084    }
01085    LastSkeletonVertex=NULL;
01086  }
01087  else if(tool == SKGRAB){
01088    LastSkeletonVertex=NULL;
01089  }
01090  else if(tool == SKRUBBERBONES){ // Apply the deformation 
01091    LastSkeletonVertex=NULL;
01092    if(SkRubberBonesRotate)RubberBonesDeform(); 
01093    else                   RubberBonesDeform();
01094    SkRubberBonesRotate=FALSE;
01095    DrawModel();
01096    if(ghwndOpenGLview == NULL)Draw3dView(0,0);
01097    else PostMessage(ghwndOpenGLview,(WM_USER+2),0,0);
01098  }
01099  else if(tool == SKTWIST){
01100    LastSkeletonVertex=NULL;
01101    if(SkSelectedNode1 != NULL){
01102      DrawSkeleton(); SkSelectedNode1=NULL; DrawSkeleton();
01103    }
01104    SkSelectedNode1=NULL;
01105  }
01106  else if(tool == SKDUPLICATE && LastSkeletonVertex != NULL){
01107    LastSkeletonVertex=NULL;
01108  }
01109  else if(tool == SKSELECT && LastSkeletonVertex != NULL){
01110    int op1,op2;
01111    if(GetAsyncKeyState(VK_SHIFT) & 0x8000)op1=DESELECTED;
01112    else                                   op1=SELECTED;
01113    if(GetAsyncKeyState(VK_CONTROL) & 0x8000)op2=1;
01114    else                                     op2=0;
01115    SelectBySk(LastSkeletonVertex,op1,op2);
01116    LastSkeletonVertex=NULL;
01117  }
01118 }
01119 
01120 void SkToolMove(int x, int y){
01121  SkMovedFlag=TRUE;
01122  if(tool != SKTWIST && tool != SKANIMATE)Move3dCursor(0,x,y);
01123  if(tool == SKADD){
01124    if(LastSkeletonVertex != NULL){
01125      DrawRubber3dLine(LastSkeletonPoint,LastSkeletonVertex->xyz);
01126      LastSkeletonPoint[0]=NpointerX;
01127      LastSkeletonPoint[1]=NpointerY;
01128      LastSkeletonPoint[2]=NpointerZ;
01129      DrawRubber3dLine(LastSkeletonPoint,LastSkeletonVertex->xyz);
01130    }
01131  }
01132  else if(tool == SKGRAB){
01133    if(LastSkeletonVertex != NULL){
01134      skel *sp,*ssp,*fp;
01135      long x1,y1,z1,dx,dy,dz;
01136      DrawSkeleton();
01137      GetWorldCoords(ActiveView,&x1,&y1,&z1,x,y);
01138      sp=LastSkeletonVertex;
01139      if     (ActiveView == TRITOP  )z1=sp->xyz[2];
01140      else if(ActiveView == TRIFRONT)y1=sp->xyz[1];
01141      else if(ActiveView == TRIRIGHT)x1=sp->xyz[0];
01142      dx=x1-sp->xyz[0]; dy=y1-sp->xyz[1]; dz=z1-sp->xyz[2];
01143      if(GetAsyncKeyState(VK_SHIFT) & 0x8000){ /* drag all attached */
01144        ssp=MainSp; while(ssp != NULL){
01145          fp=ssp; while(fp != NULL){
01146            if(fp == sp){
01147              ssp->xyz[0] += dx; ssp->xyz[1] += dy; ssp->xyz[2] += dz;
01148              break;
01149            }
01150            fp=fp->at;
01151          }
01152          ssp=ssp->last;
01153        }
01154        DefaultOrientAxes(sp);
01155        GetSkeletonBoundBox(sp,0);
01156      }
01157      else{
01158        sp->xyz[0]=x1; sp->xyz[1]=y1; sp->xyz[2]=z1;
01159        ssp=MainSp; while(ssp != NULL){
01160          fp=ssp; while(fp != NULL){
01161            if(fp == sp){
01162              DefaultOrientAxes(ssp);
01163              GetSkeletonBoundBox(sp,0);
01164              break;
01165            }
01166            fp=fp->at;
01167          }
01168          ssp=ssp->last;
01169        }
01170      }
01171      DrawSkeleton();
01172    }
01173  }
01174  else if(tool == SKRUBBERBONES){ 
01175    if(SkRubberBonesRotate){   // Rotate this bone about parent in this window
01176      SkRotateRubberBones();
01177    }
01178    else if(LastSkeletonVertex != NULL){
01179      skel *sp,*ssp,*fp;
01180      long x1,y1,z1,dx,dy,dz;
01181      DrawSkeleton();
01182      GetWorldCoords(ActiveView,&x1,&y1,&z1,x,y);
01183      sp=LastSkeletonVertex;
01184      if     (ActiveView == TRITOP  )z1=sp->xyz[2];
01185      else if(ActiveView == TRIFRONT)y1=sp->xyz[1];
01186      else if(ActiveView == TRIRIGHT)x1=sp->xyz[0];
01187      dx=x1-sp->xyz[0]; dy=y1-sp->xyz[1]; dz=z1-sp->xyz[2];
01188      if(GetAsyncKeyState(VK_SHIFT) & 0x8000){ /* drag all attached */
01189        ssp=MainSp; while(ssp != NULL){
01190          fp=ssp; while(fp != NULL){
01191            if(fp == sp){
01192              ssp->xyz[0] += dx; ssp->xyz[1] += dy; ssp->xyz[2] += dz;
01193              break;
01194            }
01195            fp=fp->at;
01196          }
01197          ssp=ssp->last;
01198        }
01199        DefaultOrientAxes(sp); // may need changed if rotation
01200        GetSkeletonBoundBox(sp,0);
01201      }
01202      else if(GetAsyncKeyState(VK_CONTROL) & 0x8000){ /* move bone and parent */
01203        sp->xyz[0]=x1; sp->xyz[1]=y1; sp->xyz[2]=z1;
01204        if((ssp=sp->at) !=NULL){ ssp->xyz[0] += dx; ssp->xyz[1] += dy; ssp->xyz[2] += dz;}
01205        ssp=MainSp; while(ssp != NULL){
01206          fp=ssp; while(fp != NULL){
01207            if(fp == sp){
01208              DefaultOrientAxes(ssp);
01209              GetSkeletonBoundBox(sp,0);
01210              break;
01211            }
01212            fp=fp->at;
01213          }
01214          ssp=ssp->last;
01215        }
01216      }
01217      else{
01218        sp->xyz[0]=x1; sp->xyz[1]=y1; sp->xyz[2]=z1;
01219        ssp=MainSp; while(ssp != NULL){
01220          fp=ssp; while(fp != NULL){
01221            if(fp == sp){
01222              DefaultOrientAxes(ssp);
01223              GetSkeletonBoundBox(sp,0);
01224              break;
01225            }
01226            fp=fp->at;
01227          }
01228          ssp=ssp->last;
01229        }
01230      }
01231      DrawSkeleton();
01232    }
01233  }
01234  else if(tool == SKTWIST){
01235    if(LastSkeletonVertex != NULL)SkTwist();
01236    else Move3dCursor(0,x,y);
01237  }
01238  else if(tool == SKANIMATE){
01239    if(LastSkeletonVertex != NULL)SkPivot();
01240    else Move3dCursor(0,x,y);
01241  }
01242 }
01243 
01244 void SkToolAction(int x, int y){
01245  if(tool == SKADD){
01246    if(LastSkeletonVertex != NULL){
01247 //     DrawRubber3dLine(LastSkeletonPoint,LastSkeletonVertex->xyz);
01248      DrawSkeleton();
01249      if(IsWindow(ghwndSkEdit)){
01250        MessageBeep(MB_OK);
01251        LastSkeletonVertex=NULL;
01252        SkAssNode=MainSp;
01253      }
01254      else{
01255        CreateSkeleton(LastSkeletonVertex);
01256        LastSkeletonVertex=NULL;
01257        DefaultOrientAxes(MainSp);
01258        GetSkeletonBoundBox(MainSp,0);
01259        SkAssNode=MainSp;
01260      }
01261      DrawSkeleton();
01262      while(GetAsyncKeyState(VK_LBUTTON) & 0x8000 ||
01263            GetAsyncKeyState(VK_RBUTTON) & 0x8000){;}
01264    }
01265    else{
01266 //     LastSkeletonVertex=PickSkeleton(x,y,ActiveView);
01267    }
01268 //   if(LastSkeletonVertex != NULL){
01269 //     LastSkeletonPoint[0]=NpointerX;
01270 //     LastSkeletonPoint[1]=NpointerY;
01271 //     LastSkeletonPoint[2]=NpointerZ;
01272 //     DrawRubber3dLine(LastSkeletonPoint,LastSkeletonVertex->xyz);
01273 //   }
01274  }
01275  else if(tool == SKGRAB){
01276 //   if(LastSkeletonVertex == NULL){
01277 //     LastSkeletonVertex=PickSkeleton(x,y,ActiveView);
01278 //   }
01279  }
01280  else if(tool == SKTWIST){
01281 //   if(LastSkeletonVertex == NULL){
01282 //     LastSkeletonVertex=PickSkeleton(x,y,ActiveView);
01283 //     if(LastSkeletonVertex != NULL){
01284 //       DrawSkeleton(); SkSelectedNode1=LastSkeletonVertex; DrawSkeleton();
01285 //     }
01286 //   }
01287  }
01288  else if(tool == SKDELETE){
01289    if(IsWindow(ghwndSkEdit))MessageBeep(MB_OK);
01290    else{
01291      LastSkeletonVertex=PickSkeleton(x,y,ActiveView);
01292      if(LastSkeletonVertex != NULL && LastSkeletonVertex != FirstSp){
01293        DrawSkeleton();
01294        SkDelete(LastSkeletonVertex);
01295        DrawSkeleton();
01296      }
01297      LastSkeletonVertex=NULL;
01298    }
01299  }
01300  else if(tool == SKSUBDIV){
01301    long l,nx,ny,nz;
01302    skel *sp,*tsp,*ssp;
01303    vertex *vp;
01304    if(IsWindow(ghwndSkEdit))MessageBeep(MB_OK);
01305    else{
01306      if((sp=PickSkeleton(x,y,ActiveView)) != NULL){
01307        DrawSkeleton();
01308        if(sp == FirstSp){  // we have picked the root so add a node at the root
01309          tsp=MainSp;
01310          CreateSkeleton(FirstSp); // Create a new Skeleton point pointing at the root
01311          VECCOPY(FirstSp->xyz,MainSp->xyz)
01312          ssp=tsp; while(ssp != NULL){
01313            if(ssp->at == FirstSp)ssp->at=MainSp; // re-vector to new intermediate point
01314            ssp=ssp->last;
01315          }
01316          if((vp=MainVp) != NULL)for(l=0;l<Nvert;l++,vp++){
01317            if(vp->sp == FirstSp)vp->sp=MainSp;  // re-assing any vertices pointing at Main
01318          }
01319        }
01320        else{
01321          nx=(sp->xyz[0]+sp->at->xyz[0])/2;
01322          ny=(sp->xyz[1]+sp->at->xyz[1])/2;
01323          nz=(sp->xyz[2]+sp->at->xyz[2])/2;
01324          CreateSkeleton(sp->at); /* new node point at what sp used to point to */
01325          sp->at = MainSp;        /* point at new node */
01326          MainSp->xyz[0]=nx;
01327          MainSp->xyz[1]=ny;
01328          MainSp->xyz[2]=nz;
01329          DefaultOrientAxes(MainSp);
01330          ZeroSkeletonBoundingBox(MainSp);
01331        }
01332        DrawSkeleton();
01333      }
01334    }
01335  }
01336  else if(tool == SKASSIGN){
01337    skel   *sp;
01338    if((sp=PickSkeleton(x,y,ActiveView)) != NULL){
01339       GetSkeletonBoundBox(sp,1);
01340       FlashWindow(ghwnd_main,TRUE);
01341       SendPrgmMessage(IDS_OK,1);
01342    }
01343  }
01344  else if(tool == SKSELECT){
01345    LastSkeletonVertex=NULL;
01346    if((LastSkeletonVertex=PickSkeleton(x,y,ActiveView)) != NULL)
01347       FlashWindow(ghwnd_main,TRUE);
01348  }
01349  else if(tool == SKDUPLICATE){
01350    long delta;
01351    skel *sp;
01352    BOOL bContinue;
01353    LastSkeletonVertex=NULL;
01354    if((sp=PickSkeleton(x,y,ActiveView)) != NULL){
01355      if(sp == FirstSp)FlashWindow(ghwnd_main,TRUE);  // can't duplicate root
01356      else {
01357        DrawSkeleton();
01358        delta=TVsizeX / 10.0;
01359        CreateSkeleton(sp->at); 
01360        MainSp->xyz[0]=sp->xyz[0]+delta;
01361        MainSp->xyz[1]=sp->xyz[1];
01362        MainSp->xyz[2]=sp->xyz[2];
01363        strcpy(MainSp->name,sp->name); strcat(MainSp->name,"_c");
01364        DefaultOrientAxes(MainSp);
01365        ZeroSkeletonBoundingBox(MainSp);
01366        DuplicateSkeletonChildren(sp,MainSp,MainSp,delta); 
01367        DrawSkeleton();
01368      }
01369    }
01370  }
01371 }
01372 
01373 static void DuplicateSkeletonChildren(skel *from, skel *to, skel *OldMainSp, long delta){
01374  skel *sp;
01375  sp=FirstSp->next; while(sp != OldMainSp){
01376    if(sp->at == from){
01377      CreateSkeleton(to); 
01378      MainSp->xyz[0]=sp->xyz[0]+delta;
01379      MainSp->xyz[1]=sp->xyz[1];
01380      MainSp->xyz[2]=sp->xyz[2];
01381      strcpy(MainSp->name,sp->name); strcat(MainSp->name,"_c");
01382      DefaultOrientAxes(MainSp);
01383      DuplicateSkeletonChildren(sp,MainSp,OldMainSp,delta);    
01384    }
01385    sp=sp->next;
01386  }
01387 }
01388 
01389 
01390 // Skeleton TREEVIEW code ////////////////////////////////////////////////////////////////
01391 
01392 #define ptrNMHDR       ((LPNMHDR)lparam)
01393 #define ptrNM_TREEVIEW ((NM_TREEVIEW *)lparam)
01394 #define ptrTV_DISPINFO ((TV_DISPINFO *)lparam)
01395 
01396 #define IDM_SKTB_ADD          100
01397 #define IDM_SKTB_INSERT       101
01398 #define IDM_SKTB_DELETE       102
01399 #define IDM_SKTB_SELECT       103
01400 #define IDM_SKTB_DESELECT     104
01401 #define IDM_SKTB_HIDE         105
01402 #define IDM_SKTB_UNHIDE       106
01403 #define IDM_SKTB_ASSIGN       107
01404 #define IDM_SKTB_DEASSIGN     108
01405 
01406 static PSTR        lpszSkTreeViewClass="SkTreeViewClass";
01407 static HWND        hWndTreeView=NULL;
01408 static HWND        hTBWnd=NULL;
01409 static HIMAGELIST  hCoasterImageList=NULL;
01410 
01411 #define NTOOLBARBUTTONS 13
01412 
01413 static TBBUTTON tbb[NTOOLBARBUTTONS] = {
01414           {3,IDM_SKTB_SELECT,       TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0 },
01415           {4,IDM_SKTB_DESELECT,     TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0 },
01416           {0,0,                     TBSTATE_ENABLED,TBSTYLE_SEP,   0,0 },
01417           {2,IDM_SKTB_INSERT,       TBSTATE_ENABLED,TBSTYLE_BUTTON|
01418                                                TBSTYLE_CHECK, 0,0 },
01419           {0,0,                     TBSTATE_ENABLED,TBSTYLE_SEP,   0,0 },
01420           {5,IDM_SKTB_HIDE,         TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0 },
01421           {6,IDM_SKTB_UNHIDE,       TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0 },
01422           {0,0,                     TBSTATE_ENABLED,TBSTYLE_SEP,   0,0 },
01423           {7,IDM_SKTB_ASSIGN,       TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0 },
01424           {8,IDM_SKTB_DEASSIGN,     TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0 },
01425           {0,0,                     TBSTATE_ENABLED,TBSTYLE_SEP,   0,0 },
01426           {0,IDM_SKTB_ADD,          TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0 },
01427           {1,IDM_SKTB_DELETE,       TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0 }
01428                          };
01429 
01430 static HTREEITEM AddTreeViewItem (HWND        hWndTV,
01431                                   HTREEITEM   hParent,
01432                                   HTREEITEM   hInsertAfter,
01433                                   int         iImage,
01434                                   int         iSelectedImage,
01435                                   LPSTR       szText,
01436                                  LPARAM      lParam){
01437  TV_INSERTSTRUCT       tvIns;
01438  tvIns.item.mask           = TVIF_TEXT  | TVIF_IMAGE |
01439                          TVIF_SELECTEDIMAGE | TVIF_PARAM;
01440  tvIns.item.pszText        = szText;
01441  tvIns.item.cchTextMax     = sizeof(szText);
01442  tvIns.item.iImage         = iImage;
01443  tvIns.item.iSelectedImage = iSelectedImage;
01444  tvIns.item.lParam         = lParam;
01445  tvIns.hParent             = hParent;
01446  tvIns.hInsertAfter        = hInsertAfter;
01447  return TreeView_InsertItem(hWndTV,&tvIns);
01448 }
01449 
01450 static void AddTwigsTo(skel *parent, HWND hWndTV){
01451  skel *sp;
01452  HTREEITEM hParent;
01453  sp=FirstSp;
01454  while(sp != NULL){
01455    if(sp->at == parent){
01456      hParent=(HTREEITEM)(sp->at->lParam);
01457      sp->lParam=(LPARAM)AddTreeViewItem(hWndTV,hParent,(HTREEITEM)TVI_FIRST,
01458                                       0,1,
01459                                       (LPSTR)sp->name,
01460                                       (LPARAM)sp);
01461      AddTwigsTo(sp,hWndTV);
01462    }
01463    sp=sp->next;
01464  }
01465 }
01466 
01467 static BOOL TreeViewRecursive(skel *spTarget, skel *spDrag){
01468  skel *sp;
01469  while(spTarget != NULL){
01470    if(spTarget == spDrag)return TRUE;
01471    spTarget=spTarget->at;
01472  }
01473  return FALSE;
01474 }
01475 
01476 static BOOL TreeviewMenuCommand(HWND hWnd, WORD id){
01477  long i;
01478  BOOL bFound;
01479  vertex *vp;
01480  skel *sp,*spp;
01481  HTREEITEM hTarget;
01482  TV_ITEM  tvi;
01483  if(id == IDM_SKTB_INSERT){
01484    SkSelectFlag ^= 1;
01485    return TRUE;
01486  }
01487  if(sktool == YES){MessageBeep(MB_OK); return FALSE;}
01488  if((hTarget=TreeView_GetSelection(hWndTreeView)) == NULL)return FALSE;
01489  tvi.mask  = TVIF_PARAM;
01490  tvi.hItem = hTarget;
01491  TreeView_GetItem(hWndTreeView,&tvi);
01492  if((sp=(skel *)tvi.lParam) == NULL)return FALSE;
01493  switch (id) {
01494    case IDM_SKTB_ADD:
01495      CreateSkeleton(sp);
01496      MainSp->lParam=(LPARAM)AddTreeViewItem(hWndTreeView,hTarget,
01497                                       (HTREEITEM)TVI_FIRST,
01498                                       0,1,
01499                                       (LPSTR)MainSp->name,
01500                                       (LPARAM)MainSp);
01501      TreeView_EnsureVisible(hWndTreeView,(HTREEITEM)MainSp->lParam);
01502      TreeView_SelectItem(hWndTreeView,(HTREEITEM)MainSp->lParam);
01503      break;
01504    case IDM_SKTB_DELETE:
01505      if(sp == FirstSp)break;
01506      TreeView_DeleteItem(hWndTreeView,hTarget);
01507      while(1){
01508        bFound=FALSE;
01509        spp=FirstSp; while(spp != NULL){
01510          if(spp != sp && TreeViewRecursive(spp,sp)){
01511            SkDelete(spp);
01512            bFound=TRUE;
01513            goto BKOUT;
01514          }
01515          spp=spp->next;
01516        }
01517        BKOUT:
01518        if(!bFound)break;
01519      }
01520      SkDelete(sp);
01521      break;
01522    case IDM_SKTB_SELECT:
01523      SelectByHierarchy(sp,1);
01524      break;
01525    case IDM_SKTB_DESELECT:
01526      SelectByHierarchy(sp,2);
01527      break;
01528    case IDM_SKTB_HIDE:
01529      SelectByHierarchy(sp,3);
01530      break;
01531    case IDM_SKTB_UNHIDE:
01532      SelectByHierarchy(sp,4);
01533      break;
01534    case IDM_SKTB_ASSIGN:
01535      GetSkeletonBoundBox(sp,1);
01536      break;
01537    case IDM_SKTB_DEASSIGN:
01538      if((vp=MainVp) != NULL)for(i=0;i<Nvert;i++,vp++){
01539        if(vp->sp == sp)vp->sp=NULL;
01540      }
01541      break;
01542    default:
01543      break;
01544  }
01545  return TRUE;
01546 }
01547 
01548 static BOOL CALLBACK SkTreeViewWndProc(HWND hwnd, UINT msg, WPARAM wparam,
01549                                     LPARAM lparam ){
01550  static HIMAGELIST hDragImage=NULL;
01551  static HTREEITEM  hDragItem=NULL;
01552  static BOOL       bDragging=FALSE;
01553  static int ToolbarHeight;
01554  RECT rc,rc1;
01555  int dx,dy,x,y,xp,yp,xl,yl;
01556  DWORD dwStyle;
01557  skel *sp;
01558  switch( msg ){
01559    case WM_PAINT:
01560      PaintDialogBackground(hwnd,ghinst_main);
01561      break;
01562    case WM_INITDIALOG:
01563      SetClassLong(hwnd,GCL_HICON,
01564                  (LONG)LoadIcon(ghinst_main,"MODELERICON"));
01565      xp=GetPrivateProfileInt(IniSection,"SKPOSX",-1,IniFilename);
01566      yp=GetPrivateProfileInt(IniSection,"SKPOSY",-1,IniFilename);
01567      xl=GetPrivateProfileInt(IniSection,"SKSIZX",-1,IniFilename);
01568      yl=GetPrivateProfileInt(IniSection,"SKSIZY",-1,IniFilename);
01569      if(xp < 0 || yp < 0 || xl < 0 || yl < 0){
01570        x=200; y=40; dx=248; dy=250;
01571      }
01572      else{
01573        x=xp; y=yp; dx=xl; dy=yl;
01574      }
01575      SetWindowPos(hwnd,NULL,x,y,dx,dy,SWP_NOZORDER);
01576      //RSF   case WM_CREATE:
01577      dwStyle=WS_CHILD | WS_VISIBLE | WS_BORDER;
01578      if(Preferences.tooltips)dwStyle = dwStyle | TBSTYLE_TOOLTIPS;
01579      hTBWnd = CreateToolbarEx(hwnd,dwStyle,
01580         0,      // control identifier for the toolbar
01581         9,      // bitmaps images
01582         ghinst_main,
01583         IDBM_SKTOOLBAR,
01584         tbb,
01585         NTOOLBARBUTTONS,
01586         16,15,  // size of buttons
01587         16,15,  // size of bitmap
01588         sizeof(TBBUTTON)
01589        );
01590      if(0){dx=32; dy=32;} else {dx=16; dy=16;}
01591      hCoasterImageList=ImageList_Create(
01592                          dx,dy,
01593                          TRUE,
01594                          2,
01595                          5
01596                          );
01597      ImageList_AddIcon(hCoasterImageList,
01598                               LoadIcon(ghinst_main,"TREEVIEWICON0"));
01599      ImageList_AddIcon(hCoasterImageList,
01600                               LoadIcon(ghinst_main,"TREEVIEWICON1"));
01601      GetClientRect(hTBWnd,&rc1); ToolbarHeight=rc1.bottom+1;
01602      GetClientRect(hwnd,&rc);
01603 
01604      hWndTreeView=GetDlgItem(hwnd,DLG_SKELETON_TREEVIEW);
01605      SetWindowPos(hWndTreeView,NULL,0,ToolbarHeight,
01606                   rc.right,rc.bottom-ToolbarHeight,SWP_NOZORDER);
01607      if(hWndTreeView != NULL){
01608        TreeView_SetImageList(hWndTreeView,hCoasterImageList,0);
01609        ImageList_SetBkColor(hCoasterImageList,GetSysColor(COLOR_WINDOW));
01610        UpdateSkTreeView();
01611        sp=MainSp; while(sp != NULL){
01612         if(sp->at == FirstSp){
01613           TreeView_EnsureVisible(hWndTreeView,(HTREEITEM)(sp->lParam));
01614           TreeView_Expand(hWndTreeView,(HTREEITEM)(sp->lParam),TVE_EXPAND);
01615         }
01616         sp=sp->last;
01617        }
01618      }
01619      return TRUE; //RSF     break;
01620    case WM_DESTROY:{
01621        char str[32];
01622        GetWindowRect(hwnd,&rc);
01623        sprintf(str,"%ld",rc.left);
01624        WritePrivateProfileString(IniSection,"SKPOSX",str,IniFilename);
01625        sprintf(str,"%ld",rc.top);
01626        WritePrivateProfileString(IniSection,"SKPOSY",str,IniFilename);
01627        sprintf(str,"%ld",rc.right-rc.left);
01628        WritePrivateProfileString(IniSection,"SKSIZX",str,IniFilename);
01629        sprintf(str,"%ld",rc.bottom-rc.top);
01630        WritePrivateProfileString(IniSection,"SKSIZY",str,IniFilename);
01631        if(hCoasterImageList != NULL)ImageList_Destroy(hCoasterImageList);
01632        hCoasterImageList=NULL;
01633        hWndTreeView=NULL;
01634        DestroyWindow(hTBWnd);
01635        hTBWnd=NULL;
01636      }
01637      break;
01638    case WM_SYSCOMMAND:
01639      switch(LOWORD(wparam & 0xfff0)){
01640        case SC_CLOSE:
01641          PostMessage(ghwnd_main,WM_COMMAND,IDM_HIERARCHY_NAME,0);
01642          break;
01643        default:
01644          return FALSE;//RSF         return(DefWindowProc(hwnd,msg,wparam,lparam));
01645       }
01646       break;
01647    case WM_NOTIFY:
01648      switch (ptrNMHDR->code){
01649        case TTN_NEEDTEXT:{
01650            int idButton;
01651            LPTOOLTIPTEXT lpttt;
01652            lpttt=(LPTOOLTIPTEXT)lparam;
01653            lpttt->hinst=ghinst_main;
01654            idButton=lpttt->hdr.idFrom;
01655            switch(idButton){
01656              case IDM_SKTB_ADD:
01657                lpttt->lpszText=MAKEINTRESOURCE(IDI_TIP_K_1); break;
01658              case IDM_SKTB_DELETE:
01659                lpttt->lpszText=MAKEINTRESOURCE(IDI_TIP_K_2); break;
01660              case IDM_SKTB_INSERT:
01661                lpttt->lpszText=MAKEINTRESOURCE(IDI_TIP_K_3); break;
01662              case IDM_SKTB_SELECT:
01663                lpttt->lpszText=MAKEINTRESOURCE(IDI_TIP_K_4); break;
01664              case IDM_SKTB_DESELECT:
01665                lpttt->lpszText=MAKEINTRESOURCE(IDI_TIP_K_5); break;
01666              case IDM_SKTB_HIDE:
01667                lpttt->lpszText=MAKEINTRESOURCE(IDI_TIP_K_6); break;
01668              case IDM_SKTB_UNHIDE:
01669                lpttt->lpszText=MAKEINTRESOURCE(IDI_TIP_K_7); break;
01670              case IDM_SKTB_ASSIGN:
01671                lpttt->lpszText=MAKEINTRESOURCE(IDI_TIP_K_8); break;
01672              case IDM_SKTB_DEASSIGN:
01673                lpttt->lpszText=MAKEINTRESOURCE(IDI_TIP_K_9); break;
01674            }
01675          }
01676          break;
01677        case TVN_BEGINLABELEDIT:
01678          if ((skel *)ptrTV_DISPINFO->item.lParam == FirstSp)return 1;
01679          else return 0;  // Allow Editing
01680        case TVN_ENDLABELEDIT:
01681          if(ptrTV_DISPINFO->item.pszText != NULL){
01682            ptrTV_DISPINFO->item.mask = TVIF_TEXT;
01683            sp=(skel *)ptrTV_DISPINFO->item.lParam;
01684            strcpy(sp->name,ptrTV_DISPINFO->item.pszText);
01685            TreeView_SetItem(
01686                    ptrNMHDR->hwndFrom,      // Handle of TreeView
01687                    &(ptrTV_DISPINFO->item)  // TV_ITEM structure w/changes
01688                            );
01689            return TRUE;
01690          }
01691          break;
01692        case TVN_BEGINDRAG:
01693          if((skel *)ptrNM_TREEVIEW->itemNew.lParam != FirstSp){
01694             hDragImage = TreeView_CreateDragImage(
01695                         ptrNMHDR->hwndFrom,ptrNM_TREEVIEW->itemNew.hItem);
01696            TreeView_GetItemRect(
01697                  ptrNMHDR->hwndFrom,            // Handle of TreeView
01698                  ptrNM_TREEVIEW->itemNew.hItem, // Item in TreeView
01699                  &rc,                           // RECT to store result
01700                  FALSE
01701                  );
01702            hDragItem = ptrNM_TREEVIEW->itemNew.hItem;
01703            ImageList_SetDragCursorImage(hDragImage,0,0,0);
01704            ImageList_BeginDrag(hDragImage,0,0,0);
01705            ImageList_DragEnter(
01706                  hWndTreeView,
01707                  ptrNM_TREEVIEW->ptDrag.x,
01708                  ptrNM_TREEVIEW->ptDrag.y
01709                  );
01710            ImageList_DragShowNolock(TRUE);
01711            SetCapture(hwnd);
01712            bDragging=TRUE;
01713            return 0L;
01714          }
01715          break;
01716        default: break;
01717      }
01718      return FALSE; //RSF     return (DefWindowProc(hwnd,msg,wparam,lparam));
01719    case WM_MOUSEMOVE:
01720      if(bDragging){
01721        HTREEITEM       hTarget;
01722        TV_HITTESTINFO  tvht;
01723        y=HIWORD(lparam)-ToolbarHeight;
01724        ImageList_DragMove(LOWORD(lparam),y);
01725        tvht.pt.x = LOWORD(lparam);
01726        tvht.pt.y = y;
01727        if((hTarget = TreeView_HitTest(hWndTreeView,&tvht)) != NULL){
01728          TV_ITEM  tvi;
01729          tvi.mask  = TVIF_PARAM;
01730          tvi.hItem = hTarget;
01731          TreeView_GetItem(hWndTreeView,&tvi);
01732          if(hTarget != TreeView_GetDropHilight(hWndTreeView)){
01733            ImageList_DragShowNolock(FALSE);
01734            TreeView_SelectDropTarget(hWndTreeView,hTarget);
01735            ImageList_DragShowNolock(TRUE);
01736          }
01737          return 0L;
01738        }
01739        if(hTarget != TreeView_GetDropHilight(hWndTreeView)){
01740          ImageList_DragShowNolock(FALSE);
01741          TreeView_SelectDropTarget(hWndTreeView,NULL);
01742          ImageList_DragShowNolock(TRUE);
01743        }
01744      }
01745      break;
01746    case WM_LBUTTONUP:
01747      if(bDragging){
01748        HTREEITEM hTarget;       // Item under mouse
01749        TV_ITEM   tvi;           // Temporary Item
01750        skel      *spTarget,*spDrag;
01751        ImageList_DragLeave(hWndTreeView);
01752        ImageList_EndDrag();
01753        ReleaseCapture();
01754        bDragging = FALSE;
01755        ImageList_Destroy(hDragImage);
01756        hDragImage = NULL;
01757        if((hTarget = TreeView_GetDropHilight(hWndTreeView)) != NULL){
01758          if(hTarget != hDragItem){
01759          tvi.mask       = TVIF_PARAM;
01760          tvi.hItem      = hDragItem;
01761          TreeView_GetItem(hWndTreeView,&tvi);
01762          spDrag=(skel *)tvi.lParam;
01763          tvi.hItem      = hTarget;
01764          TreeView_GetItem(hWndTreeView,&tvi);
01765          spTarget=(skel *)tvi.lParam;
01766          if(sktool == NO && !TreeViewRecursive(spTarget,spDrag)){
01767            spDrag->at=spTarget;
01768            TreeView_DeleteItem(hWndTreeView,hDragItem);
01769            spDrag->lParam=(LPARAM)AddTreeViewItem(hWndTreeView,
01770                                       (HTREEITEM)spTarget->lParam,
01771                                       (HTREEITEM)TVI_FIRST,
01772                                       0,1,
01773                                       (LPSTR)spDrag->name,
01774                                       (LPARAM)spDrag);
01775            AddTwigsTo(spDrag,hWndTreeView);
01776          }
01777          else MessageBeep(MB_OK);
01778          }
01779        }
01780        TreeView_SelectDropTarget(hWndTreeView,NULL);
01781      }
01782      break;
01783    case WM_COMMAND:
01784      //RSF     return  on next line+1
01785      if(LOWORD(wparam) == IDOK){;}
01786      else     TreeviewMenuCommand(hwnd,LOWORD(wparam));
01787      break;
01788    case WM_SIZE:
01789      if(hTBWnd != NULL)SendMessage(hTBWnd,msg,wparam,lparam);
01790      if(hWndTreeView != NULL){
01791        SetWindowPos(hWndTreeView,NULL,
01792                     0,ToolbarHeight,
01793                     LOWORD(lparam),HIWORD(lparam)-ToolbarHeight,
01794                     SWP_NOZORDER);
01795      }
01796    default:
01797      break; //RSF    return(DefWindowProc(hwnd,msg,wparam,lparam));
01798  }
01799  return FALSE; //RSF  return ( 0L );
01800 }
01801 
01802 void SkeletonTreeView(HWND hWndParent){
01803  WNDCLASS   wc;
01804  HDC        hdc,hdcMem;
01805  RECT       rc;
01806  HBITMAP    hbm,hbmold=NULL;
01807  char       str[32];
01808  MSG        msg;
01809  int x,y,dx,dy;
01810  if(ghwndSkEdit != NULL){
01811    DestroyWindow(ghwndSkEdit);
01812    ghwndSkEdit=NULL;
01813    return;
01814  }
01815  ghwndSkEdit=CreateDialog(ghinst_main,MAKEINTRESOURCE(DLG_SKELETON),
01816                          hWndParent,(DLGPROC)SkTreeViewWndProc);
01817  UpdateWindow(ghwndSkEdit);
01818  if(ghwndSkEdit == NULL){
01819    return;
01820  }
01821  SendMessage(hTBWnd,TB_CHECKBUTTON,IDM_SKTB_INSERT,
01822             (LPARAM)MAKELONG(SkSelectFlag,0));
01823  return;
01824 }
01825 
01826 void UpdateSkTreeView(void){
01827  if(!IsWindow(hWndTreeView))return;
01828  TreeView_DeleteItem(hWndTreeView,TVI_ROOT);
01829  FirstSp->lParam=(LPARAM)AddTreeViewItem(hWndTreeView,
01830                                          TVI_ROOT,
01831                                          (HTREEITEM)TVI_FIRST,
01832                                          0,1,
01833                                          (LPSTR)FirstSp->name,
01834                                          (LPARAM)FirstSp);
01835  AddTwigsTo(FirstSp,hWndTreeView);
01836 }
01837 
01839 
01840 
01841 void SetSkToolbarState(BOOL state){
01842  int i;
01843  if(!IsWindow(ghwndSkEdit))return;
01844  for(i=0;i<NTOOLBARBUTTONS;i++)SendMessage(hTBWnd,
01845    TB_ENABLEBUTTON,(WPARAM)tbb[i].idCommand,(LPARAM)MAKELONG(state,0));
01846 }
01847 
01848 void SkeletonToolBar(HWND hWndParent){
01849  WNDCLASS   wc;
01850  HDC        hdc,hdcMem;
01851  RECT       rc;
01852  HBITMAP    hbm,hbmold=NULL;
01853  char       str[32];
01854  MSG        msg;
01855  int x,y,dx,dy;
01856  if(ghwndSkToolbar != NULL){
01857    DestroyWindow(ghwndSkToolbar);
01858    ghwndSkToolbar=NULL;
01859    return;
01860  }
01861  ghwndSkToolbar=CreateDialog(ghinst_main,MAKEINTRESOURCE(DLG_SKTOOLBAR),
01862                          hWndParent,(DLGPROC)SkToolBarDlgProc);
01863  UpdateWindow(ghwndSkToolbar);
01864  if(ghwndSkToolbar == NULL){
01865    return;
01866  }
01867  return;
01868 }
01869 
01870 static BOOL CALLBACK SkToolBarDlgProc(HWND hwnd, UINT msg, WPARAM wparam,
01871                                     LPARAM lparam ){
01872  static TBBUTTON tbtns[10] = {
01873           {0,DLG_SKTOOLBAR_BUILD,TBSTATE_ENABLED,TBSTYLE_BUTTON|
01874                                                TBSTYLE_CHECKGROUP, 0,0 },
01875           {1,DLG_SKTOOLBAR_REPOSITION,TBSTATE_ENABLED,TBSTYLE_BUTTON|
01876                                                TBSTYLE_CHECKGROUP, 0,0 },
01877           {2,DLG_SKTOOLBAR_ROTATION,TBSTATE_ENABLED,TBSTYLE_BUTTON|
01878                                                TBSTYLE_CHECKGROUP, 0,0 },
01879           {3,DLG_SKTOOLBAR_REMOVE,TBSTATE_ENABLED,TBSTYLE_BUTTON|
01880                                                TBSTYLE_CHECKGROUP, 0,0 },
01881           {4,DLG_SKTOOLBAR_INSERT,TBSTATE_ENABLED,TBSTYLE_BUTTON|
01882                                                TBSTYLE_CHECKGROUP, 0,0 },
01883           {5,DLG_SKTOOLBAR_ATTACH,TBSTATE_ENABLED,TBSTYLE_BUTTON|
01884                                                TBSTYLE_CHECKGROUP, 0,0 },
01885           {6,DLG_SKTOOLBAR_SELECT,TBSTATE_ENABLED,TBSTYLE_BUTTON|
01886                                                TBSTYLE_CHECKGROUP, 0,0 },
01887           {7,DLG_SKTOOLBAR_DUPLICATE,TBSTATE_ENABLED,TBSTYLE_BUTTON|
01888                                                TBSTYLE_CHECKGROUP, 0,0 },
01889           {8,DLG_SKTOOLBAR_RUBBERBONES,TBSTATE_ENABLED,TBSTYLE_BUTTON|
01890                                                TBSTYLE_CHECKGROUP, 0,0 },
01891           {9,DLG_SKTOOLBAR_RENAME,TBSTATE_ENABLED,TBSTYLE_BUTTON|
01892                                                TBSTYLE_CHECKGROUP, 0,0 }
01893                          };
01894  static HWND hWndTools=NULL;
01895  DWORD dwStyle;
01896  RECT rc;
01897  int x,y,xp,yp,id;
01898  switch( msg ){
01899    case WM_INITDIALOG:
01900      xp=GetPrivateProfileInt(IniSection,"SKTOOLBOXPOSX",-1,IniFilename);
01901      yp=GetPrivateProfileInt(IniSection,"SKTOOLBOXPOSY",-1,IniFilename);
01902      if(xp < 0 || yp < 0){
01903        x=200; y=40;
01904      }
01905      else{
01906        x=xp; y=yp;
01907      }
01908      dwStyle=WS_CHILD | WS_VISIBLE | WS_BORDER;
01909      if(Preferences.tooltips)dwStyle = dwStyle | TBSTYLE_TOOLTIPS;
01910      hWndTools = CreateToolbarEx(hwnd,dwStyle,
01911         0,      // control identifier for the toolbar
01912         10,      // bitmaps images
01913         ghinst_main,
01914         IDBM_SKTOOLBAR1,
01915         tbtns,
01916         10,      // no of buttons
01917         16,15,  // size of buttons
01918         16,15,  // size of bitmap
01919         sizeof(TBBUTTON)
01920        );
01921      id=DLG_SKTOOLBAR_BUILD;
01922      if     (tool == SKGRAB  )       id=DLG_SKTOOLBAR_REPOSITION;
01923      else if(tool == SKTWIST )       id=DLG_SKTOOLBAR_ROTATION;
01924      else if(tool == SKDELETE)       id=DLG_SKTOOLBAR_REMOVE;
01925      else if(tool == SKSUBDIV)       id=DLG_SKTOOLBAR_INSERT;
01926      else if(tool == SKASSIGN)       id=DLG_SKTOOLBAR_ATTACH;
01927      else if(tool == SKSELECT)       id=DLG_SKTOOLBAR_SELECT;
01928      else if(tool == SKDUPLICATE)    id=DLG_SKTOOLBAR_DUPLICATE;
01929      else if(tool == SKRUBBERBONES ) id=DLG_SKTOOLBAR_RUBBERBONES;
01930      else if(tool == SKRENAME )      id=DLG_SKTOOLBAR_RENAME;
01931      SendMessage(hWndTools,TB_CHECKBUTTON,id,MAKELONG(TRUE,0));
01932      SetWindowPos(hwnd,NULL,x,y,0,0,SWP_NOZORDER|SWP_NOSIZE);
01933      return TRUE;
01934    case WM_DESTROY:{
01935        char str[32];
01936        GetWindowRect(hwnd,&rc);
01937        sprintf(str,"%ld",rc.left);
01938        WritePrivateProfileString(IniSection,"SKTOOLBOXPOSX",str,IniFilename);
01939        sprintf(str,"%ld",rc.top);
01940        WritePrivateProfileString(IniSection,"SKTOOLBOXPOSY",str,IniFilename);
01941        if(hWndTools != NULL)DestroyWindow(hWndTools);
01942        hWndTools=NULL;
01943      }
01944      break;
01945    case WM_SYSCOMMAND:
01946      switch(LOWORD(wparam & 0xfff0)){
01947        case SC_CLOSE:
01948          PostMessage(ghwnd_main,WM_COMMAND,IDM_STOP,0);
01949          break;
01950        default:
01951          return FALSE;
01952       }
01953       break;
01954    case WM_NOTIFY:
01955      switch (ptrNMHDR->code){
01956        case TTN_NEEDTEXT:{
01957            int idButton;
01958            LPTOOLTIPTEXT lpttt;
01959            lpttt=(LPTOOLTIPTEXT)lparam;
01960            lpttt->hinst=ghinst_main;
01961            idButton=lpttt->hdr.idFrom;
01962            switch(idButton){
01963              case DLG_SKTOOLBAR_BUILD:
01964                lpttt->lpszText=MAKEINTRESOURCE(IDI_TIP_KT_1); break;
01965              case DLG_SKTOOLBAR_REPOSITION:
01966                lpttt->lpszText=MAKEINTRESOURCE(IDI_TIP_KT_2); break;
01967              case DLG_SKTOOLBAR_ROTATION:
01968                lpttt->lpszText=MAKEINTRESOURCE(IDI_TIP_KT_3); break;
01969              case DLG_SKTOOLBAR_REMOVE:
01970                lpttt->lpszText=MAKEINTRESOURCE(IDI_TIP_KT_4); break;
01971              case DLG_SKTOOLBAR_INSERT:
01972                lpttt->lpszText=MAKEINTRESOURCE(IDI_TIP_KT_5); break;
01973              case DLG_SKTOOLBAR_ATTACH:
01974                lpttt->lpszText=MAKEINTRESOURCE(IDI_TIP_KT_6); break;
01975              case DLG_SKTOOLBAR_SELECT:
01976                lpttt->lpszText=MAKEINTRESOURCE(IDI_TIP_KT_7); break;
01977              case DLG_SKTOOLBAR_DUPLICATE:
01978                lpttt->lpszText=MAKEINTRESOURCE(IDI_TIP_KT_8); break;
01979              case DLG_SKTOOLBAR_RUBBERBONES:
01980                lpttt->lpszText=MAKEINTRESOURCE(IDI_TIP_KT_9); break;
01981              case DLG_SKTOOLBAR_RENAME:
01982                lpttt->lpszText=MAKEINTRESOURCE(IDI_TIP_KT_10); break;
01983            }
01984          }
01985          break;
01986        default: break;
01987      }
01988      return FALSE;
01989    case WM_COMMAND:
01990      if(LOWORD(wparam) == IDOK){;}
01991      else if(LOWORD(wparam) == DLG_SKTOOLBAR_BUILD){
01992        PostMessage(ghwnd_main,WM_COMMAND,IDM_HIERARCHY_BUILD,0);
01993      }
01994      else if(LOWORD(wparam) == DLG_SKTOOLBAR_REPOSITION){
01995        PostMessage(ghwnd_main,WM_COMMAND,IDM_HIERARCHY_STRETCH,0);
01996      }
01997      else if(LOWORD(wparam) == DLG_SKTOOLBAR_ROTATION){
01998        PostMessage(ghwnd_main,WM_COMMAND,IDM_HIERARCHY_TWIST,0);
01999      }
02000      else if(LOWORD(wparam) == DLG_SKTOOLBAR_REMOVE){
02001        PostMessage(ghwnd_main,WM_COMMAND,IDM_HIERARCHY_REMOVE,0);
02002      }
02003      else if(LOWORD(wparam) == DLG_SKTOOLBAR_INSERT){
02004        PostMessage(ghwnd_main,WM_COMMAND,IDM_HIERARCHY_INSERT,0);
02005      }
02006      else if(LOWORD(wparam) == DLG_SKTOOLBAR_ATTACH){
02007        PostMessage(ghwnd_main,WM_COMMAND,IDM_HIERARCHY_ATTACH,0);
02008      }
02009      else if(LOWORD(wparam) == DLG_SKTOOLBAR_SELECT){
02010        PostMessage(ghwnd_main,WM_COMMAND,IDM_HIERARCHY_SELECT,0);
02011      }
02012      else if(LOWORD(wparam) == DLG_SKTOOLBAR_DUPLICATE){
02013        PostMessage(ghwnd_main,WM_COMMAND,IDM_HIERARCHY_DUPLICATE,0);
02014      }
02015      else if(LOWORD(wparam) == DLG_SKTOOLBAR_RUBBERBONES){
02016        PostMessage(ghwnd_main,WM_COMMAND,IDM_HIERARCHY_RUBBERBONES,0);
02017      }
02018      else if(LOWORD(wparam) == DLG_SKTOOLBAR_RENAME){
02019        PostMessage(ghwnd_main,WM_COMMAND,IDM_HIERARCHY_RENAME,0);
02020      }
02021      break;
02022    default:
02023      break;
02024  }
02025  return FALSE;
02026 }

Generated on Sun Apr 27 14:20:11 2014 for OpenFX by  doxygen 1.5.6