svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r22935:23022
[blender.git] / source / blender / blenkernel / intern / curve.c
index 7dd868278f4c2f71716fcd8c7aec88d9aeb44a06..228523aa661c554201b30d07230d07cb76f911ee 100644 (file)
@@ -1550,7 +1550,7 @@ void makeBevelList(Object *ob)
        BPoint *bp;
        BevList *bl, *blnew, *blnext;
        BevPoint *bevp, *bevp2, *bevp1 = NULL, *bevp0;
-       float min, inp, x1, x2, y1, y2, vec[3];
+       float min, inp, x1, x2, y1, y2, vec[3], vec_prev[3], q[4], quat[4], quat_prev[4], cross[3];
        float *coord_array, *tilt_array=NULL, *radius_array=NULL, *coord_fp, *tilt_fp=NULL, *radius_fp=NULL;
        float *v1, *v2;
        struct bevelsort *sortdata, *sd, *sd1;
@@ -1909,7 +1909,10 @@ void makeBevelList(Object *ob)
        bl= cu->bev.first;
        while(bl) {
        
-               if(bl->nr==2) { /* 2 pnt, treat separate */
+               if(bl->nr < 2) {
+                       /* do nothing */
+               }
+               else if(bl->nr==2) {    /* 2 pnt, treat separate */
                        bevp2= (BevPoint *)(bl+1);
                        bevp1= bevp2+1;
 
@@ -1923,68 +1926,169 @@ void makeBevelList(Object *ob)
                        if(cu->flag & CU_3D) {  /* 3D */
                                float quat[4], q[4];
                        
-                               vec[0]= bevp1->x - bevp2->x;
-                               vec[1]= bevp1->y - bevp2->y;
-                               vec[2]= bevp1->z - bevp2->z;
+                               VecSubf(vec, &bevp1->x, &bevp2->x);
                                
                                vectoquat(vec, 5, 1, quat);
                                
-                               Normalize(vec);
-                               q[0]= (float)cos(0.5*bevp1->alfa);
-                               x1= (float)sin(0.5*bevp1->alfa);
-                               q[1]= x1*vec[0];
-                               q[2]= x1*vec[1];
-                               q[3]= x1*vec[2];
+                               AxisAngleToQuat(q, vec, bevp1->alfa);
                                QuatMul(quat, q, quat);
                                
                                QuatToMat3(quat, bevp1->mat);
                                Mat3CpyMat3(bevp2->mat, bevp1->mat);
                        }
 
+               }       /* this has to be >2 points */
+               else if(cu->flag & CU_NO_TWIST && cu->flag & CU_3D && bl->poly != -1) {
+
+                       /* Special case, cyclic curve with no twisy. tricky... */
+
+                       float quat[4], q[4], cross[3];
+
+                       /* correcting a cyclic curve is more complicated, need to be corrected from both ends */
+                       float *quat_tmp1, *quat_tmp2; /* store a quat in the matrix temporarily */
+                       int iter_dir;
+                       BevPoint *bevp_start= (BevPoint *)(bl+1);
+
+                       /* loop over the points twice, once up, once back, accumulate the quat rotations
+                        * in both directions, then blend them in the 3rd loop and apply the tilt */
+                       for(iter_dir = 0; iter_dir < 2; iter_dir++) {
+
+                               bevp2= (BevPoint *)(bl+1);
+                               bevp1= bevp2+(bl->nr-1);
+                               bevp0= bevp1-1;
+
+                               nr= bl->nr;
+                               while(nr--) {
+       
+                                       /* Normalizes */
+                                       Vec3ToTangent(vec, &bevp0->x, &bevp1->x, &bevp2->x);
+
+                                       if(bl->nr==nr+1) { /* first time */
+                                               vectoquat(vec, 5, 1, quat);
+                                       }
+                                       else {
+                                               float angle = NormalizedVecAngle2(vec_prev, vec);
+                                       
+                                               if(angle > 0.0f) { /* otherwise we can keep as is */
+                                                       Crossf(cross, vec_prev, vec);
+                                                       AxisAngleToQuat(q, cross, angle);
+                                                       QuatMul(quat, q, quat_prev);
+                                               }
+                                               else {
+                                                       QUATCOPY(quat, quat_prev);
+                                               }
+                                       }
+                                       QUATCOPY(quat_prev, quat); /* quat_prev can't have the tilt applied */
+                                       VECCOPY(vec_prev, vec);
+
+                                       if(iter_dir==0) { /* up, first time */
+                                               quat_tmp1= (float *)bevp1->mat;
+
+                                               bevp0= bevp1;
+                                               bevp1= bevp2;
+                                               bevp2++;
+                                       }
+                                       else { /* down second time */
+                                               quat_tmp1= ((float *)bevp1->mat)+4;
+
+                                               bevp2= bevp1;
+                                               bevp1= bevp0;
+                                               bevp0--;
+
+                                               /* wrap around */
+                                               if (bevp0 < bevp_start)
+                                                       bevp0= bevp_start+(bl->nr-1);
+                                       }
+
+                                       QUATCOPY(quat_tmp1, quat);
+                               }
+                       }
+
+                       /* Now interpolate the 2 quats and apply tilt */
+
+                       bevp2= (BevPoint *)(bl+1);
+                       bevp1= bevp2+(bl->nr-1);
+                       bevp0= bevp1-1;
+
+                       nr= bl->nr;
+                       while(nr--) {
+
+                               Vec3ToTangent(vec, &bevp0->x, &bevp1->x, &bevp2->x);
+
+                               quat_tmp1= (float *)bevp1->mat;
+                               quat_tmp2= quat_tmp1+4;
+
+                               /* blend the 2 rotations gathered from both directions */
+                               QuatInterpol(quat, quat_tmp1, quat_tmp2, 1.0 - (((float)nr)/bl->nr));
+
+                               AxisAngleToQuat(q, vec, bevp1->alfa);
+                               QuatMul(quat, q, quat);
+                               QuatToMat3(quat, bevp1->mat);
+                               
+                               /* generic */
+                               x1= bevp1->x- bevp0->x;
+                               x2= bevp1->x- bevp2->x;
+                               y1= bevp1->y- bevp0->y;
+                               y2= bevp1->y- bevp2->y;
+                       
+                               calc_bevel_sin_cos(x1, y1, x2, y2, &(bevp1->sina), &(bevp1->cosa));
+                               
+                               bevp0= bevp1;
+                               bevp1= bevp2;
+                               bevp2++;
+                       }
                }
-               else if(bl->nr>2) {
+               else {
+                       /* Any curve with 3 or more points */
+
                        bevp2= (BevPoint *)(bl+1);
                        bevp1= bevp2+(bl->nr-1);
                        bevp0= bevp1-1;
 
-               
                        nr= bl->nr;
-       
                        while(nr--) {
-       
+
                                if(cu->flag & CU_3D) {  /* 3D */
-                                       float quat[4], q[4];
-                               
-                                       vec[0]= bevp2->x - bevp0->x;
-                                       vec[1]= bevp2->y - bevp0->y;
-                                       vec[2]= bevp2->z - bevp0->z;
-                                       
-                                       Normalize(vec);
 
-                                       vectoquat(vec, 5, 1, quat);
-                                       
-                                       q[0]= (float)cos(0.5*bevp1->alfa);
-                                       x1= (float)sin(0.5*bevp1->alfa);
-                                       q[1]= x1*vec[0];
-                                       q[2]= x1*vec[1];
-                                       q[3]= x1*vec[2];
+                                       /* Normalizes */
+                                       Vec3ToTangent(vec, &bevp0->x, &bevp1->x, &bevp2->x);
+
+                                       if(bl->nr==nr+1 || !(cu->flag & CU_NO_TWIST)) { /* first time */
+                                               vectoquat(vec, 5, 1, quat);
+                                       }
+                                       else {
+                                               float angle = NormalizedVecAngle2(vec_prev, vec);
+
+                                               if(angle > 0.0f) { /* otherwise we can keep as is */
+                                                       Crossf(cross, vec_prev, vec);
+                                                       AxisAngleToQuat(q, cross, angle);
+                                                       QuatMul(quat, q, quat_prev);
+                                               }
+                                               else {
+                                                       QUATCOPY(quat, quat_prev);
+                                               }
+                                       }
+                                       QUATCOPY(quat_prev, quat); /* quat_prev can't have the tilt applied */
+                                       VECCOPY(vec_prev, vec);
+
+                                       AxisAngleToQuat(q, vec, bevp1->alfa);
                                        QuatMul(quat, q, quat);
-                                       
                                        QuatToMat3(quat, bevp1->mat);
                                }
-                               
+
                                x1= bevp1->x- bevp0->x;
                                x2= bevp1->x- bevp2->x;
                                y1= bevp1->y- bevp0->y;
                                y2= bevp1->y- bevp2->y;
-                       
+
                                calc_bevel_sin_cos(x1, y1, x2, y2, &(bevp1->sina), &(bevp1->cosa));
-                               
-                               
+
+
                                bevp0= bevp1;
                                bevp1= bevp2;
                                bevp2++;
                        }
+
                        /* correct non-cyclic cases */
                        if(bl->poly== -1) {
                                if(bl->nr>2) {