Fix for bug: cross platform strand render differences with kink/branch.
[blender.git] / source / blender / blenkernel / intern / curve.c
index 9cdc8be9e57ba3aeee686a3567cd667c1bb364d1..dcd8bc6d9ebcfb51494b60bfce40f52fa1affa14 100644 (file)
@@ -112,21 +112,16 @@ void free_curve(Curve *cu)
        if(cu->tb) MEM_freeN(cu->tb);
 }
 
-Curve *add_curve(int type)
+Curve *add_curve(char *name, int type)
 {
        Curve *cu;
-       char *str;
-       
-       if(type==OB_CURVE) str= "Curve";
-       else if(type==OB_SURF) str= "Surf";
-       else str= "Text";
 
-       cu= alloc_libblock(&G.main->curve, ID_CU, str);
+       cu= alloc_libblock(&G.main->curve, ID_CU, name);
        
        cu->size[0]= cu->size[1]= cu->size[2]= 1.0;
        cu->flag= CU_FRONT+CU_BACK;
        cu->pathlen= 100;
-       cu->resolu= cu->resolv= 6;
+       cu->resolu= cu->resolv= 12;
        cu->width= 1.0;
        cu->wordspace = 1.0;
        cu->spacing= cu->linedist= 1.0;
@@ -231,28 +226,24 @@ void make_local_curve(Curve *cu)
        }
 }
 
-
-void test_curve_type(Object *ob)
+short curve_type(Curve *cu)
 {
        Nurb *nu;
-       Curve *cu;
-       
-       cu= ob->data;
        if(cu->vfont) {
-               ob->type= OB_FONT;
-               return;
+               return OB_FONT;
        }
-       else {
-               nu= cu->nurb.first;
-               while(nu) {
-                       if(nu->pntsv>1) {
-                               ob->type= OB_SURF;
-                               return;
-                       }
-                       nu= nu->next;
+       for (nu= cu->nurb.first; nu; nu= nu->next) {
+               if(nu->pntsv>1) {
+                       return OB_SURF;
                }
        }
-       ob->type= OB_CURVE;
+       
+       return OB_CURVE;
+}
+
+void test_curve_type(Object *ob)
+{      
+       ob->type = curve_type(ob->data);
 }
 
 void tex_space_curve(Curve *cu)
@@ -262,7 +253,7 @@ void tex_space_curve(Curve *cu)
        float *data, min[3], max[3], loc[3], size[3];
        int tot, doit= 0;
        
-       if(cu->bb==0) cu->bb= MEM_callocN(sizeof(BoundBox), "boundbox");
+       if(cu->bb==NULL) cu->bb= MEM_callocN(sizeof(BoundBox), "boundbox");
        bb= cu->bb;
        
        INIT_MINMAX(min, max);
@@ -333,7 +324,20 @@ int count_curveverts(ListBase *nurb)
        return tot;
 }
 
-
+int count_curveverts_without_handles(ListBase *nurb)
+{
+       Nurb *nu;
+       int tot=0;
+       
+       nu= nurb->first;
+       while(nu) {
+               if(nu->bezt) tot+= nu->pntsu;
+               else if(nu->bp) tot+= nu->pntsu*nu->pntsv;
+               
+               nu= nu->next;
+       }
+       return tot;
+}
 
 /* **************** NURBS ROUTINES ******************** */
 
@@ -483,52 +487,7 @@ void minmaxNurb(Nurb *nu, float *min, float *max)
 /* ~~~~~~~~~~~~~~~~~~~~Non Uniform Rational B Spline calculations ~~~~~~~~~~~ */
 
 
-/* actually, doubles should be used here as much as possible */
-
-void extend_spline(float * pnts, int in, int out)
-{
-       float *_pnts;
-       double * add;
-       int i, j, k, in2;
-
-       _pnts = pnts;
-       add = (double*)MEM_mallocN((in)* sizeof(double), "extend_spline");
-
-        in2 = in -1;
-
-       for (k = 3; k > 0; k--){
-               pnts = _pnts;
-
-               /* copy points to 'add' */
-               for (i = 0; i < in; i++){
-                       add[i] = *pnts;
-                       pnts += 3;
-               }
-
-               /* inverse forward differencing */
-               for (i = 0; i < in2; i++){
-                       for (j = in2; j > i; j--){
-                               add[j] -= add[j - 1];
-                       }
-               }
-
-               pnts = _pnts;
-               for (i = out; i > 0; i--){
-                       *pnts = (float)(add[0]);
-                       pnts += 3;
-                       for (j = 0; j < in2; j++){
-                               add[j] += add[j+1];
-                       }
-               }
-
-               _pnts++;
-       }
-
-       MEM_freeN(add);
-}
-
-
-void calcknots(float *knots, short aantal, short order, short type)
+static void calcknots(float *knots, short aantal, short order, short type)
 /* knots: number of pnts NOT corrected for cyclic */
 /* type;        0: uniform, 1: endpoints, 2: bezier */
 {
@@ -567,7 +526,7 @@ void calcknots(float *knots, short aantal, short order, short type)
        }
 }
 
-void makecyclicknots(float *knots, short pnts, short order)
+static void makecyclicknots(float *knots, short pnts, short order)
 /* pnts, order: number of pnts NOT corrected for cyclic */
 {
        int a, b, order2, c;
@@ -617,7 +576,7 @@ void makeknots(Nurb *nu, short uv, short type)      /* 0: uniform, 1: endpoints, 2: b
        }
 }
 
-void basisNurb(float t, short order, short pnts, float *knots, float *basis, int *start, int *end)
+static void basisNurb(float t, short order, short pnts, float *knots, float *basis, int *start, int *end)
 {
        float d, e;
        int i, i1 = 0, i2 = 0 ,j, orderpluspnts, opp2, o2;
@@ -627,7 +586,7 @@ void basisNurb(float t, short order, short pnts, float *knots, float *basis, int
 
        /* this is for float inaccuracy */
        if(t < knots[0]) t= knots[0];
-       else if(t > knots[opp2]) t= knots[opp2];
+       else if(t > knots[opp2]) t= knots[opp2]; /* Valgrind reports an error here, use a nurbs torus and change u/v res to reproduce a crash TODO*/
 
        /* this part is order '1' */
         o2 = order + 1;
@@ -839,100 +798,13 @@ void makeNurbfaces(Nurb *nu, float *data, int rowstride)
        MEM_freeN(jend);
 }
 
-
-void makeNurbcurve_forw(Nurb *nu, float *data)
-/* *data: has to be 3*4*pntsu*resolu in size and zero-ed */
-{
-       BPoint *bp;
-       float *basisu, *sum, *fp,  *in;
-       float u, ustart, uend, ustep, sumdiv;
-       int i, j, k, len, resolu, istart, iend;
-       int wanted, org;
-
-       if(nu->knotsu==0) return;
-       if(data==0) return;
-
-       /* allocate and init */
-       len= nu->pntsu;
-       if(len==0) return;
-       sum= (float *)MEM_callocN(sizeof(float)*len, "makeNurbcurve1");
-
-       resolu= nu->resolu*nu->pntsu;
-       if(resolu==0) {
-               MEM_freeN(sum);
-               return;
-       }
-
-       fp= nu->knotsu;
-       ustart= fp[nu->orderu-1];
-       uend= fp[nu->pntsu];
-       ustep= (uend-ustart)/(resolu-1);
-       basisu= (float *)MEM_mallocN(sizeof(float)*(nu->orderu+nu->pntsu), "makeNurbcurve3");
-
-       in= data;
-       u= ustart;
-       for (k = nu->orderu - 1; k < nu->pntsu; k++){
-
-               wanted = (int)((nu->knotsu[k+1] - nu->knotsu[k]) / ustep);
-               org = 4;        /* equal to order */
-               if (org > wanted) org = wanted;
-
-               for (j = org; j > 0; j--){
-
-                       basisNurb(u, nu->orderu, nu->pntsu, nu->knotsu, basisu, &istart, &iend);
-                       /* calc sum */
-                       sumdiv= 0.0;
-                       fp= sum;
-                       for(i= istart; i<=iend; i++, fp++) {
-                               /* do the rational component */
-                               *fp= basisu[i];
-                               sumdiv+= *fp;
-                       }
-                       if(sumdiv!=0.0) if(sumdiv<0.999 || sumdiv>1.001) {
-                               /* is this normalizing needed? */
-                               fp= sum;
-                               for(i= istart; i<=iend; i++, fp++) {
-                                       *fp/= sumdiv;
-                               }
-                       }
-
-                       /* one! (1.0) real point */
-                       fp= sum;
-                       bp= nu->bp+ istart;
-                       for(i= istart; i<=iend; i++, bp++, fp++) {
-
-                               if(*fp!=0.0) {
-                                       in[0]+= (*fp) * bp->vec[0];
-                                       in[1]+= (*fp) * bp->vec[1];
-                                       in[2]+= (*fp) * bp->vec[2];
-                               }
-                       }
-
-                       in+=3;
-
-                       u+= ustep;
-               }
-
-               if (wanted > org){
-                       extend_spline(in - 3 * org, org, wanted);
-                       in += 3 * (wanted - org);
-                       u += ustep * (wanted - org);
-               }
-       }
-
-       /* free */
-       MEM_freeN(sum);
-       MEM_freeN(basisu);
-}
-
-
-void makeNurbcurve(Nurb *nu, float *data, int dim)
+void makeNurbcurve(Nurb *nu, float *data, int resolu, int dim)
 /* data has to be dim*4*pntsu*resolu in size and zero-ed */
 {
        BPoint *bp;
        float u, ustart, uend, ustep, sumdiv;
        float *basisu, *sum, *fp,  *in;
-       int i, len, resolu, istart, iend, cycl;
+       int i, len, istart, iend, cycl;
 
        if(nu->knotsu==0) return;
        if(nu->orderu>nu->pntsu) return;
@@ -943,7 +815,7 @@ void makeNurbcurve(Nurb *nu, float *data, int dim)
        if(len==0) return;
        sum= (float *)MEM_callocN(sizeof(float)*len, "makeNurbcurve1");
 
-       resolu= nu->resolu*nu->pntsu;
+       resolu*= nu->pntsu;
        if(resolu==0) {
                MEM_freeN(sum);
                return;
@@ -1045,30 +917,47 @@ void forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int i
 
 float *make_orco_surf(Object *ob)
 {
-       Curve *cu = ob->data;
+       Curve *cu= ob->data;
        Nurb *nu;
        int a, b, tot=0;
-       int sizeu, sizev;// ###
-       float *data;
-       float *orco;
-
-               /* first calculate the size of the datablock */
-       for (nu=cu->nurb.first; nu; nu=nu->next) {
-               sizeu = nu->resolu; sizev = nu->resolv;
-               if(nu->pntsv>1) tot+= sizeu * sizev;
+       int sizeu, sizev;
+       float *data, *orco;
+       
+       /* first calculate the size of the datablock */
+       nu= cu->nurb.first;
+       while(nu) {
+               /* as we want to avoid the seam in a cyclic nurbs
+               texture wrapping, reserve extra orco data space to save these extra needed
+               vertex based UV coordinates for the meridian vertices.
+               Vertices on the 0/2pi boundary are not duplicated inside the displist but later in
+               the renderface/vert construction.
+               
+               See also convertblender.c: init_render_surf()
+               */
+               
+               sizeu = nu->resolu; 
+               sizev = nu->resolv;
+               if (nu->flagu & CU_CYCLIC) sizeu++;
+               if (nu->flagv & CU_CYCLIC) sizev++;
+               if(nu->pntsv>1) tot+= sizeu * sizev;
+               
+               nu= nu->next;
        }
-                               /* makeNurbfaces wants zeros */
+       /* makeNurbfaces wants zeros */
        data= orco= MEM_callocN(3*sizeof(float)*tot, "make_orco");
-
-       for (nu=cu->nurb.first; nu; nu=nu->next) {
+       
+       nu= cu->nurb.first;
+       while(nu) {
                if(nu->pntsv>1) {
                        sizeu = nu->resolu;
                        sizev = nu->resolv;
+                       if (nu->flagu & CU_CYCLIC) sizeu++;
+                       if (nu->flagv & CU_CYCLIC) sizev++;
                        
                        if(cu->flag & CU_UV_ORCO) {
                                for(b=0; b< sizeu; b++) {
                                        for(a=0; a< sizev; a++) {
-                                       
+                                               
                                                if(sizev <2) data[0]= 0.0f;
                                                else data[0]= -1.0f + 2.0f*((float)a)/(sizev - 1);
                                                
@@ -1076,26 +965,42 @@ float *make_orco_surf(Object *ob)
                                                else data[1]= -1.0f + 2.0f*((float)b)/(sizeu - 1);
                                                
                                                data[2]= 0.0;
-               
+                                               
                                                data+= 3;
                                        }
                                }
                        }
                        else {
-                               makeNurbfaces(nu, data, sizeof(*data)*sizev*3);
-
+                               float *_tdata= MEM_callocN(nu->resolu*nu->resolv*3*sizeof(float), "temp data");
+                               float *tdata= _tdata;
+                               
+                               makeNurbfaces(nu, tdata, 0);
+                               
                                for(b=0; b<sizeu; b++) {
+                                       int use_b= b;
+                                       if (b==sizeu-1 && (nu->flagu & CU_CYCLIC))
+                                               use_b= 0;
+                                       
                                        for(a=0; a<sizev; a++) {
-                                               data = orco + 3 * (b * sizev + a);
-                                               data[0]= (data[0]-cu->loc[0])/cu->size[0];
-                                               data[1]= (data[1]-cu->loc[1])/cu->size[1];
-                                               data[2]= (data[2]-cu->loc[2])/cu->size[2];
+                                               int use_a= a;
+                                               if (a==sizev-1 && (nu->flagv & CU_CYCLIC))
+                                                       use_a= 0;
+                                               
+                                               tdata = _tdata + 3 * (use_b * nu->resolv + use_a);
+                                               
+                                               data[0]= (tdata[0]-cu->loc[0])/cu->size[0];
+                                               data[1]= (tdata[1]-cu->loc[1])/cu->size[1];
+                                               data[2]= (tdata[2]-cu->loc[2])/cu->size[2];
+                                               data+= 3;
                                        }
                                }
+                               
+                               MEM_freeN(_tdata);
                        }
                }
+               nu= nu->next;
        }
-
+       
        return orco;
 }
 
@@ -1117,23 +1022,30 @@ float *make_orco_curve(Object *ob)
                remakeDisp = 1;
        }
 
-               /* Assumes displist has been built */
+       /* Assumes displist has been built */
 
        numVerts = 0;
        for (dl=cu->disp.first; dl; dl=dl->next) {
                if (dl->type==DL_INDEX3) {
                        numVerts += dl->nr;
                } else if (dl->type==DL_SURF) {
-                       numVerts += dl->parts*dl->nr;
+                       /* convertblender.c uses the Surface code for creating renderfaces when cyclic U only (closed circle beveling) */
+                       if (dl->flag & DL_CYCL_U) {
+                               if (dl->flag & DL_CYCL_V)
+                                       numVerts += (dl->parts+1)*(dl->nr+1);
+                               else
+                                       numVerts += dl->parts*(dl->nr+1);
+                       }
+                       else
+                               numVerts += dl->parts*dl->nr;
                }
        }
 
        fp= orco= MEM_mallocN(3*sizeof(float)*numVerts, "cu_orco");
-
        for (dl=cu->disp.first; dl; dl=dl->next) {
                if (dl->type==DL_INDEX3) {
-                       for (u=0; u<dl->nr; u++,fp+=3) {
-                               if (cu->flag&CU_UV_ORCO) {
+                       for (u=0; u<dl->nr; u++, fp+=3) {
+                               if (cu->flag & CU_UV_ORCO) {
                                        fp[0]= 2.0f*u/(dl->nr-1) - 1.0f;
                                        fp[1]= 0.0;
                                        fp[2]= 0.0;
@@ -1146,14 +1058,25 @@ float *make_orco_curve(Object *ob)
                                }
                        }
                } else if (dl->type==DL_SURF) {
-                       for (u=0; u<dl->parts; u++) {
-                               for (v=0; v<dl->nr; v++,fp+=3) {
-                                       if (cu->flag&CU_UV_ORCO) {
+                       int sizeu= dl->nr, sizev= dl->parts;
+                       
+                       /* exception as handled in convertblender.c too */
+                       if (dl->flag & DL_CYCL_U) {
+                               sizeu++;
+                               if (dl->flag & DL_CYCL_V)
+                                       sizev++;
+                       }
+                       
+                       for (u=0; u<sizev; u++) {
+                               for (v=0; v<sizeu; v++,fp+=3) {
+                                       if (cu->flag & CU_UV_ORCO) {
                                                fp[0]= 2.0f*u/(dl->parts-1) - 1.0f;
                                                fp[1]= 2.0f*v/(dl->nr-1) - 1.0f;
                                                fp[2]= 0.0;
                                        } else {
-                                               VECCOPY(fp, &dl->verts[(dl->nr*u + v)*3]);
+                                               int realv= v % dl->nr;
+
+                                               VECCOPY(fp, &dl->verts[(dl->nr*u + realv)*3]);
 
                                                fp[0]= (fp[0]-cu->loc[0])/cu->size[0];
                                                fp[1]= (fp[1]-cu->loc[1])/cu->size[1];
@@ -1178,12 +1101,15 @@ void makebevelcurve(Object *ob, ListBase *disp)
 {
        DispList *dl, *dlnew;
        Curve *bevcu, *cu;
-       float *fp, facx, facy, hoek, dhoek;
+       float *fp, facx, facy, angle, dangle;
        int nr, a;
 
        cu= ob->data;
-
        disp->first = disp->last = NULL;
+
+       /* if a font object is being edited, then do nothing */
+       if( ob == G.obedit && ob->type == OB_FONT ) return;
+
        if(cu->bevobj && cu->bevobj!=ob) {
                if(cu->bevobj->type==OB_CURVE) {
                        bevcu= cu->bevobj->data;
@@ -1238,13 +1164,38 @@ void makebevelcurve(Object *ob, ListBase *disp)
                fp[3]= fp[4]= 0.0;
                fp[5]= cu->ext1;
        }
+       else if( (cu->flag & (CU_FRONT|CU_BACK))==0 && cu->ext1==0.0f)  { // we make a full round bevel in that case
+               
+               nr= 4+ 2*cu->bevresol;
+                  
+               dl= MEM_callocN(sizeof(DispList), "makebevelcurve p1");
+               dl->verts= MEM_mallocN(nr*3*sizeof(float), "makebevelcurve p1");
+               BLI_addtail(disp, dl);
+               dl->type= DL_POLY;
+               dl->parts= 1;
+               dl->flag= DL_BACK_CURVE;
+               dl->nr= nr;
+
+               /* a circle */
+               fp= dl->verts;
+               dangle= (2.0f*M_PI/(nr));
+               angle= -(nr-1)*dangle;
+               
+               for(a=0; a<nr; a++) {
+                       fp[0]= 0.0;
+                       fp[1]= (float)(cos(angle)*(cu->ext2));
+                       fp[2]= (float)(sin(angle)*(cu->ext2)) - cu->ext1;
+                       angle+= dangle;
+                       fp+= 3;
+               }
+       }
        else {
                short dnr;
                
                /* bevel now in three parts, for proper vertex normals */
                /* part 1 */
                dnr= nr= 2+ cu->bevresol;
-               if( (cu->flag & (CU_FRONT|CU_BACK))==0) // we make a full round bevel in that case
+               if( (cu->flag & (CU_FRONT|CU_BACK))==0)
                        nr= 3+ 2*cu->bevresol;
                   
                dl= MEM_callocN(sizeof(DispList), "makebevelcurve p1");
@@ -1257,14 +1208,14 @@ void makebevelcurve(Object *ob, ListBase *disp)
 
                /* half a circle */
                fp= dl->verts;
-               dhoek= (0.5*M_PI/(dnr-1));
-               hoek= -(nr-1)*dhoek;
+               dangle= (0.5*M_PI/(dnr-1));
+               angle= -(nr-1)*dangle;
                
                for(a=0; a<nr; a++) {
                        fp[0]= 0.0;
-                       fp[1]= (float)(cos(hoek)*(cu->ext2));
-                       fp[2]= (float)(sin(hoek)*(cu->ext2)) - cu->ext1;
-                       hoek+= dhoek;
+                       fp[1]= (float)(cos(angle)*(cu->ext2));
+                       fp[2]= (float)(sin(angle)*(cu->ext2)) - cu->ext1;
+                       angle+= dangle;
                        fp+= 3;
                }
                
@@ -1313,14 +1264,14 @@ void makebevelcurve(Object *ob, ListBase *disp)
                
                /* half a circle */
                fp= dl->verts;
-               hoek= 0.0;
-               dhoek= (0.5*M_PI/(dnr-1));
+               angle= 0.0;
+               dangle= (0.5*M_PI/(dnr-1));
                
                for(a=0; a<nr; a++) {
                        fp[0]= 0.0;
-                       fp[1]= (float)(cos(hoek)*(cu->ext2));
-                       fp[2]= (float)(sin(hoek)*(cu->ext2)) + cu->ext1;
-                       hoek+= dhoek;
+                       fp[1]= (float)(cos(angle)*(cu->ext2));
+                       fp[2]= (float)(sin(angle)*(cu->ext2)) + cu->ext1;
+                       angle+= dangle;
                        fp+= 3;
                }
        }
@@ -1360,7 +1311,7 @@ int cu_isectLL(float *v1, float *v2, float *v3, float *v4, short cox, short coy,
 }
 
 
-short bevelinside(BevList *bl1,BevList *bl2)
+static short bevelinside(BevList *bl1,BevList *bl2)
 {
        /* is bl2 INSIDE bl1 ? with left-right method and "labda's" */
        /* returns '1' if correct hole  */
@@ -1419,7 +1370,7 @@ struct bevelsort {
        int dir;
 };
 
-int vergxcobev(const void *a1, const void *a2)
+static int vergxcobev(const void *a1, const void *a2)
 {
        const struct bevelsort *x1=a1,*x2=a2;
 
@@ -1430,7 +1381,7 @@ int vergxcobev(const void *a1, const void *a2)
 
 /* this function cannot be replaced with atan2, but why? */
 
-void calc_bevel_sin_cos(float x1, float y1, float x2, float y2, float *sina, float *cosa)
+static void calc_bevel_sin_cos(float x1, float y1, float x2, float y2, float *sina, float *cosa)
 {
        float t01, t02, x3, y3;
 
@@ -1467,7 +1418,7 @@ void calc_bevel_sin_cos(float x1, float y1, float x2, float y2, float *sina, flo
 
 }
 
-void alfa_bezpart(BezTriple *prevbezt, BezTriple *bezt, Nurb *nu, float *data_a)
+static void alfa_bezpart(BezTriple *prevbezt, BezTriple *bezt, Nurb *nu, float *data_a, int resolu)
 {
        BezTriple *pprev, *next, *last;
        float fac, dfac, t[4];
@@ -1490,11 +1441,11 @@ void alfa_bezpart(BezTriple *prevbezt, BezTriple *bezt, Nurb *nu, float *data_a)
        else next= bezt+1;
        
        fac= 0.0;
-       dfac= 1.0f/(float)nu->resolu;
+       dfac= 1.0f/(float)resolu;
        
-       for(a=0; a<nu->resolu; a++, fac+= dfac) {
+       for(a=0; a<resolu; a++, fac+= dfac) {
                
-               set_four_ipo(fac, t, KEY_BSPLINE);
+               set_four_ipo(fac, t, nu->tilt_interp);
                
                data_a[a]= t[0]*pprev->alfa + t[1]*prevbezt->alfa + t[2]*bezt->alfa + t[3]*next->alfa;
        }
@@ -1516,7 +1467,7 @@ void makeBevelList(Object *ob)
        BevPoint *bevp, *bevp2, *bevp1 = NULL, *bevp0;
        float  *data, *data_a, *v1, *v2, min, inp, x1, x2, y1, y2, vec[3];
        struct bevelsort *sortdata, *sd, *sd1;
-       int a, b, len, nr, poly;
+       int a, b, nr, poly, resolu, len=0;
 
        /* this function needs an object, because of tflag and upflag */
        cu= ob->data;
@@ -1524,14 +1475,21 @@ void makeBevelList(Object *ob)
        /* STEP 1: MAKE POLYS  */
 
        BLI_freelistN(&(cu->bev));
-       if(ob==G.obedit) nu= editNurb.first;
+       if(ob==G.obedit && ob->type!=OB_FONT) nu= editNurb.first;
        else nu= cu->nurb.first;
        
        while(nu) {
-               if(nu->pntsu>1) {
-               
+               if(nu->pntsu<=1) {
+                       bl= MEM_callocN(sizeof(BevList)+1*sizeof(BevPoint), "makeBevelList");
+                       BLI_addtail(&(cu->bev), bl);
+                       bl->nr= 0;
+               } else {
+                       if(G.rendering && cu->resolu_ren!=0) 
+                               resolu= cu->resolu_ren;
+                       else
+                               resolu= nu->resolu;
+                       
                        if((nu->type & 7)==CU_POLY) {
-       
                                len= nu->pntsu;
                                bl= MEM_callocN(sizeof(BevList)+len*sizeof(BevPoint), "makeBevelList");
                                BLI_addtail(&(cu->bev), bl);
@@ -1555,7 +1513,7 @@ void makeBevelList(Object *ob)
                        }
                        else if((nu->type & 7)==CU_BEZIER) {
        
-                               len= nu->resolu*(nu->pntsu+ (nu->flagu & 1) -1)+1;      /* in case last point is not cyclic */
+                               len= resolu*(nu->pntsu+ (nu->flagu & 1) -1)+1;  /* in case last point is not cyclic */
                                bl= MEM_callocN(sizeof(BevList)+len*sizeof(BevPoint), "makeBevelList");
                                BLI_addtail(&(cu->bev), bl);
        
@@ -1574,8 +1532,8 @@ void makeBevelList(Object *ob)
                                        bezt++;
                                }
                                
-                               data= MEM_mallocN(3*sizeof(float)*(nu->resolu+1), "makeBevelList2");
-                               data_a= MEM_callocN(sizeof(float)*(nu->resolu+1), "data_a");
+                               data= MEM_mallocN(3*sizeof(float)*(resolu+1), "makeBevelList2");
+                               data_a= MEM_callocN(sizeof(float)*(resolu+1), "data_a");
                                
                                while(a--) {
                                        if(prevbezt->h2==HD_VECT && bezt->h1==HD_VECT) {
@@ -1584,7 +1542,7 @@ void makeBevelList(Object *ob)
                                                bevp->y= prevbezt->vec[1][1];
                                                bevp->z= prevbezt->vec[1][2];
                                                bevp->alfa= prevbezt->alfa;
-                                               bevp->f1= 1;
+                                               bevp->f1= SELECT;
                                                bevp->f2= 0;
                                                bevp++;
                                                bl->nr++;
@@ -1595,13 +1553,13 @@ void makeBevelList(Object *ob)
                                                v2= bezt->vec[0];
                                                
                                                /* always do all three, to prevent data hanging around */
-                                               forward_diff_bezier(v1[0], v1[3], v2[0], v2[3], data, nu->resolu, 3);
-                                               forward_diff_bezier(v1[1], v1[4], v2[1], v2[4], data+1, nu->resolu, 3);
-                                               forward_diff_bezier(v1[2], v1[5], v2[2], v2[5], data+2, nu->resolu, 3);
+                                               forward_diff_bezier(v1[0], v1[3], v2[0], v2[3], data, resolu, 3);
+                                               forward_diff_bezier(v1[1], v1[4], v2[1], v2[4], data+1, resolu, 3);
+                                               forward_diff_bezier(v1[2], v1[5], v2[2], v2[5], data+2, resolu, 3);
                                                
                                                if((nu->type & CU_2D)==0) {
                                                        if(cu->flag & CU_3D) {
-                                                               alfa_bezpart(prevbezt, bezt, nu, data_a);
+                                                               alfa_bezpart(prevbezt, bezt, nu, data_a, resolu);
                                                        }
                                                }
                                                
@@ -1617,7 +1575,7 @@ void makeBevelList(Object *ob)
                                                
                                                v1= data;
                                                v2= data_a;
-                                               nr= nu->resolu;
+                                               nr= resolu;
                                                
                                                while(nr--) {
                                                        bevp->x= v1[0]; 
@@ -1628,7 +1586,7 @@ void makeBevelList(Object *ob)
                                                        v1+=3;
                                                        v2++;
                                                }
-                                               bl->nr+= nu->resolu;
+                                               bl->nr+= resolu;
        
                                        }
                                        prevbezt= bezt;
@@ -1642,13 +1600,14 @@ void makeBevelList(Object *ob)
                                        bevp->x= prevbezt->vec[1][0];
                                        bevp->y= prevbezt->vec[1][1];
                                        bevp->z= prevbezt->vec[1][2];
+                                       bevp->alfa= prevbezt->alfa;
                                        bl->nr++;
                                }
        
                        }
                        else if((nu->type & 7)==CU_NURBS) {
                                if(nu->pntsv==1) {
-                                       len= nu->resolu*nu->pntsu;
+                                       len= resolu*nu->pntsu;
                                        bl= MEM_mallocN(sizeof(BevList)+len*sizeof(BevPoint), "makeBevelList3");
                                        BLI_addtail(&(cu->bev), bl);
                                        bl->nr= len;
@@ -1658,7 +1617,7 @@ void makeBevelList(Object *ob)
                                        bevp= (BevPoint *)(bl+1);
        
                                        data= MEM_callocN(4*sizeof(float)*len, "makeBevelList4");    /* has to be zero-ed */
-                                       makeNurbcurve(nu, data, 4);
+                                       makeNurbcurve(nu, data, resolu, 4);
                                        
                                        v1= data;
                                        while(len--) {
@@ -1681,28 +1640,30 @@ void makeBevelList(Object *ob)
        /* STEP 2: DOUBLE POINTS AND AUTOMATIC RESOLUTION, REDUCE DATABLOCKS */
        bl= cu->bev.first;
        while(bl) {
-               nr= bl->nr;
-               bevp1= (BevPoint *)(bl+1);
-               bevp0= bevp1+(nr-1);
-               nr--;
-               while(nr--) {
-                       if( fabs(bevp0->x-bevp1->x)<0.00001 ) {
-                               if( fabs(bevp0->y-bevp1->y)<0.00001 ) {
-                                       if( fabs(bevp0->z-bevp1->z)<0.00001 ) {
-                                               bevp0->f2= 1;
-                                               bl->flag++;
+               if (bl->nr) { /* null bevel items come from single points */
+                       nr= bl->nr;
+                       bevp1= (BevPoint *)(bl+1);
+                       bevp0= bevp1+(nr-1);
+                       nr--;
+                       while(nr--) {
+                               if( fabs(bevp0->x-bevp1->x)<0.00001 ) {
+                                       if( fabs(bevp0->y-bevp1->y)<0.00001 ) {
+                                               if( fabs(bevp0->z-bevp1->z)<0.00001 ) {
+                                                       bevp0->f2= SELECT;
+                                                       bl->flag++;
+                                               }
                                        }
                                }
+                               bevp0= bevp1;
+                               bevp1++;
                        }
-                       bevp0= bevp1;
-                       bevp1++;
                }
                bl= bl->next;
        }
        bl= cu->bev.first;
        while(bl) {
                blnext= bl->next;
-               if(bl->flag) {
+               if(bl->nr && bl->flag) {
                        nr= bl->nr- bl->flag+1; /* +1 because vectorbezier sets flag too */
                        blnew= MEM_mallocN(sizeof(BevList)+nr*sizeof(BevPoint), "makeBevelList");
                        memcpy(blnew, bl, sizeof(BevList));
@@ -1730,7 +1691,7 @@ void makeBevelList(Object *ob)
        bl= cu->bev.first;
        poly= 0;
        while(bl) {
-               if(bl->poly>=0) {
+               if(bl->nr && bl->poly>=0) {
                        poly++;
                        bl->poly= poly;
                        bl->gat= 0;     /* 'gat' is dutch for hole */
@@ -1827,15 +1788,15 @@ void makeBevelList(Object *ob)
                        bevp2->cosa= bevp1->cosa;
 
                        if(cu->flag & CU_3D) {  /* 3D */
-                               float *quat, q[4];
+                               float quat[4], q[4];
                        
                                vec[0]= bevp1->x - bevp2->x;
                                vec[1]= bevp1->y - bevp2->y;
                                vec[2]= bevp1->z - bevp2->z;
                                
-                               quat= vectoquat(vec, 5, 1);
+                               vectoquat(vec, 5, 1, quat);
                                
-                               Normalise(vec);
+                               Normalize(vec);
                                q[0]= (float)cos(0.5*bevp1->alfa);
                                x1= (float)sin(0.5*bevp1->alfa);
                                q[1]= x1*vec[0];
@@ -1859,15 +1820,15 @@ void makeBevelList(Object *ob)
                        while(nr--) {
        
                                if(cu->flag & CU_3D) {  /* 3D */
-                                       float *quat, q[4];
+                                       float quat[4], q[4];
                                
                                        vec[0]= bevp2->x - bevp0->x;
                                        vec[1]= bevp2->y - bevp0->y;
                                        vec[2]= bevp2->z - bevp0->z;
                                        
-                                       Normalise(vec);
+                                       Normalize(vec);
 
-                                       quat= vectoquat(vec, 5, 1);
+                                       vectoquat(vec, 5, 1, quat);
                                        
                                        q[0]= (float)cos(0.5*bevp1->alfa);
                                        x1= (float)sin(0.5*bevp1->alfa);
@@ -1912,6 +1873,134 @@ void makeBevelList(Object *ob)
        }
 }
 
+/* calculates a bevel width (radius) for a particular subdivided curve part,
+ * based on the radius value of the surrounding CVs */
+float calc_curve_subdiv_radius(Curve *cu, Nurb *nu, int cursubdiv)
+{
+       BezTriple *bezt, *beztfirst, *beztlast, *beztnext, *beztprev;
+       BPoint *bp, *bpfirst, *bplast;
+       int resolu;
+       float prevrad=0.0, nextrad=0.0, rad=0.0, ratio=0.0;
+       int vectseg=0, subdivs=0;
+       
+       if((nu==NULL) || (nu->pntsu<=1)) return 1.0; 
+       bezt= nu->bezt;
+       bp = nu->bp;
+       
+       if(G.rendering && cu->resolu_ren!=0) resolu= cu->resolu_ren;
+       else resolu= nu->resolu;
+       
+       if(((nu->type & 7)==CU_BEZIER) && (bezt != NULL)) {
+               beztfirst = nu->bezt;
+               beztlast = nu->bezt + (nu->pntsu - 1);
+               
+               /* loop through the CVs to end up with a pointer to the CV before the subdiv in question, and a ratio
+                * of how far that subdiv is between this CV and the next */
+               while(bezt<=beztlast) {
+                       beztnext = bezt+1;
+                       beztprev = bezt-1;
+                       vectseg=0;
+                       
+                       if (subdivs==cursubdiv) {
+                               ratio= 0.0;
+                               break;
+                       }
+
+                       /* check to see if we're looking at a vector segment (no subdivisions) */
+                       if (nu->flagu & CU_CYCLIC) {
+                               if (bezt == beztfirst) {
+                                       if ((beztlast->h2==HD_VECT) && (bezt->h1==HD_VECT)) vectseg = 1;
+                               } else {
+                                       if ((beztprev->h2==HD_VECT) && (bezt->h1==HD_VECT)) vectseg = 1;
+                               }
+                       } else if ((bezt->h2==HD_VECT) && (beztnext->h1==HD_VECT)) vectseg = 1;
+                       
+                       
+                       if (vectseg==0) {
+                               /* if it's NOT a vector segment, check to see if the subdiv falls within the segment */
+                               subdivs += resolu;
+                               
+                               if (cursubdiv < subdivs) {
+                                       ratio = 1.0 - ((subdivs - cursubdiv)/(float)resolu);
+                                       break;
+                               }
+                       } else {
+                               /* must be a vector segment.. loop again! */
+                               subdivs += 1;
+                       } 
+                       
+                       bezt++;
+               }
+               
+               /* Now we have a nice bezt pointer to the CV that we want. But cyclic messes it up, so must correct for that..
+                * (cyclic goes last-> first -> first+1 -> first+2 -> ...) */
+               if (nu->flagu & CU_CYCLIC) {
+                       if (bezt == beztfirst) bezt = beztlast;
+                       else bezt--;
+               }
+                
+               /* find the radii at the bounding CVs and interpolate between them based on ratio */
+               rad = prevrad = bezt->radius;
+               
+               if ((bezt == beztlast) && (nu->flagu & CU_CYCLIC)) { /* loop around */
+                       bezt= beztfirst;
+               } else if (bezt != beztlast) {
+                       bezt++;
+               }
+               nextrad = bezt->radius;
+               
+       }
+       else if( ( ((nu->type & 7)==CU_NURBS) || ((nu->type & 7)==CU_POLY)) && (bp != NULL)) {
+               /* follows similar algo as for bezt above */
+               bpfirst = nu->bp;
+               bplast = nu->bp + (nu->pntsu - 1);
+               
+               if ((nu->type & 7)==CU_POLY) resolu=1;
+               
+               while(bp<=bplast) {
+                       if (subdivs==cursubdiv) {
+                               ratio= 0.0;
+                               break;
+                       }
+                       
+                       subdivs += resolu;
+
+                       if (cursubdiv < subdivs) {
+                               ratio = 1.0 - ((subdivs - cursubdiv)/(float)resolu);
+                               break;
+                       }
+
+                       bp++;
+               }
+               
+               if ( ((nu->type & 7)==CU_NURBS) && (nu->flagu & CU_CYCLIC)) {
+                       if (bp >= bplast) bp = bpfirst;
+                       else bp++;
+               }
+               
+               rad = prevrad = bp->radius;
+               
+               if ((bp == bplast) && (nu->flagu & CU_CYCLIC)) { /* loop around */
+                       bp= bpfirst;
+               } else if (bp != bplast) {
+                       bp++;
+               }
+               nextrad = bp->radius;
+               
+       }
+       
+       
+       if (nextrad != prevrad) {
+               /* smooth interpolation */
+               rad = prevrad + (nextrad-prevrad)*(3.0f*ratio*ratio - 2.0f*ratio*ratio*ratio);
+       }
+
+       if (rad > 0.0) 
+               return rad;
+       else
+               return 1.0;
+}
+
 /* ****************** HANDLES ************** */
 
 /*
@@ -1922,7 +2011,7 @@ void makeBevelList(Object *ob)
 /* mode: is not zero when IpoCurve, is 2 when forced horizontal for autohandles */
 void calchandleNurb(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode)
 {
-       float *p1,*p2,*p3,pt[3];
+       float *p1,*p2,*p3, pt[3];
        float dx1,dy1,dz1,dx,dy,dz,vx,vy,vz,len,len1,len2;
 
        if(bezt->h1==0 && bezt->h2==0) return;
@@ -1946,29 +2035,19 @@ void calchandleNurb(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode)
        }
        else p3= next->vec[1];
 
-       if(mode && bezt->h1==HD_AUTO && prev) {
-               dx= p2[0] - (p1[0]+p1[3])/2.0f;
-               dy= p2[1] - (p1[1]+p1[4])/2.0f;
-               dz= p2[2] - (p1[2]+p1[5])/2.0f;
-       }
-       else {
-               dx= p2[0]- p1[0];
-               dy= p2[1]- p1[1];
-               dz= p2[2]- p1[2];
-       }
-       len1= (float)sqrt(dx*dx+dy*dy+dz*dz);
+       dx= p2[0]- p1[0];
+       dy= p2[1]- p1[1];
+       dz= p2[2]- p1[2];
        
-       if(mode && bezt->h2==HD_AUTO && next) {
-               dx1= (p3[0]+p3[-3])/2.0f - p2[0];
-               dy1= (p3[1]+p3[-2])/2.0f - p2[1];
-               dz1= (p3[2]+p3[-1])/2.0f - p2[2];
-       }
-       else {
-               dx1= p3[0]- p2[0];
-               dy1= p3[1]- p2[1];
-               dz1= p3[2]- p2[2];
-       }
-       len2= (float)sqrt(dx1*dx1+dy1*dy1+dz1*dz1);
+       if(mode) len1= dx;
+       else len1= (float)sqrt(dx*dx+dy*dy+dz*dz);
+       
+       dx1= p3[0]- p2[0];
+       dy1= p3[1]- p2[1];
+       dz1= p3[2]- p2[2];
+       
+       if(mode) len2= dx1;
+       else len2= (float)sqrt(dx1*dx1+dy1*dy1+dz1*dz1);
 
        if(len1==0.0f) len1=1.0f;
        if(len2==0.0f) len2=1.0f;
@@ -2046,8 +2125,8 @@ void calchandleNurb(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode)
                                
                                VecSubf(h1, p2-3, p2);
                                VecSubf(h2, p2, p2+3);
-                               len1= Normalise(h1);
-                               len2= Normalise(h2);
+                               len1= Normalize(h1);
+                               len2= Normalize(h2);
                                
                                vz= INPR(h1, h2);
                                
@@ -2088,7 +2167,7 @@ void calchandleNurb(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode)
        if(len1==0.0) len1=1.0;
        if(len2==0.0) len2=1.0;
 
-       if(bezt->f1 & 1) { /* order of calculation */
+       if(bezt->f1 & SELECT) { /* order of calculation */
                if(bezt->h2==HD_ALIGN) {        /* aligned */
                        len= len2/len1;
                        p2[3]= p2[0]+len*(p2[0]-p2[-3]);
@@ -2123,7 +2202,7 @@ void calchandlesNurb(Nurb *nu) /* first, if needed, set handle flags */
        BezTriple *bezt, *prev, *next;
        short a;
 
-       if((nu->type & 7)!=1) return;
+       if((nu->type & 7)!=CU_BEZIER) return;
        if(nu->pntsu<2) return;
        
        a= nu->pntsu;
@@ -2164,9 +2243,9 @@ void testhandlesNurb(Nurb *nu)
        a= nu->pntsu;
        while(a--) {
                flag= 0;
-               if(bezt->f1 & 1) flag++;
-               if(bezt->f2 & 1) flag += 2;
-               if(bezt->f3 & 1) flag += 4;
+               if(bezt->f1 & SELECT) flag++;
+               if(bezt->f2 & SELECT) flag += 2;
+               if(bezt->f3 & SELECT) flag += 4;
 
                if( !(flag==0 || flag==7) ) {
                        if(bezt->h1==HD_AUTO) {   /* auto */
@@ -2277,6 +2356,8 @@ void sethandlesNurb(short code)
        /* code==2: set vectorhandle */
        /* code==3 (HD_ALIGN) it toggle, vectorhandles become HD_FREE */
        /* code==4: sets icu flag to become IPO_AUTO_HORIZ, horizontal extremes on auto-handles */
+       /* code==5: Set align, like 3 but no toggle */
+       /* code==6: Clear align, like 3 but no toggle */
        Nurb *nu;
        BezTriple *bezt;
        short a, ok=0;
@@ -2307,22 +2388,28 @@ void sethandlesNurb(short code)
                /* there is 1 handle not FREE: FREE it all, else make ALIGNED  */
                
                nu= editNurb.first;
-               while(nu) {
-                       if( (nu->type & 7)==1) {
-                               bezt= nu->bezt;
-                               a= nu->pntsu;
-                               while(a--) {
-                                       if(bezt->f1 && bezt->h1) ok= 1;
-                                       if(bezt->f3 && bezt->h2) ok= 1;
-                                       if(ok) break;
-                                       bezt++;
+               if (code == 5) {
+                       ok = HD_ALIGN;
+               } else if (code == 6) {
+                       ok = HD_FREE;
+               } else {
+                       /* Toggle */
+                       while(nu) {
+                               if( (nu->type & 7)==1) {
+                                       bezt= nu->bezt;
+                                       a= nu->pntsu;
+                                       while(a--) {
+                                               if(bezt->f1 && bezt->h1) ok= 1;
+                                               if(bezt->f3 && bezt->h2) ok= 1;
+                                               if(ok) break;
+                                               bezt++;
+                                       }
                                }
+                               nu= nu->next;
                        }
-                       nu= nu->next;
+                       if(ok) ok= HD_FREE;
+                       else ok= HD_ALIGN;
                }
-               if(ok) ok= HD_FREE;
-               else ok= HD_ALIGN;
-               
                nu= editNurb.first;
                while(nu) {
                        if( (nu->type & 7)==1) {
@@ -2341,7 +2428,7 @@ void sethandlesNurb(short code)
        }
 }
 
-void swapdata(void *adr1, void *adr2, int len)
+static void swapdata(void *adr1, void *adr2, int len)
 {
 
        if(len<=0) return;