7 * ***** BEGIN GPL LICENSE BLOCK *****
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24 * All rights reserved.
26 * The Original Code is: all of this file.
28 * Contributor(s): none yet.
30 * ***** END GPL LICENSE BLOCK *****
33 #include <math.h> // floor
41 #include "MEM_guardedalloc.h"
42 #include "BLI_blenlib.h"
43 #include "BLI_arithb.h"
45 #include "DNA_object_types.h"
46 #include "DNA_curve_types.h"
47 #include "DNA_material_types.h"
49 /* for dereferencing pointers */
51 #include "DNA_key_types.h"
52 #include "DNA_scene_types.h"
53 #include "DNA_vfont_types.h"
55 #include "BKE_animsys.h"
57 #include "BKE_curve.h"
58 #include "BKE_displist.h"
60 #include "BKE_global.h"
62 #include "BKE_library.h"
65 #include "BKE_object.h"
66 #include "BKE_utildefines.h" // VECCOPY
72 int cu_isectLL(float *v1, float *v2, float *v3, float *v4,
74 float *labda, float *mu, float *vec);
76 void unlink_curve(Curve *cu)
80 for(a=0; a<cu->totcol; a++) {
81 if(cu->mat[a]) cu->mat[a]->id.us--;
84 if(cu->vfont) cu->vfont->id.us--;
86 if(cu->key) cu->key->id.us--;
90 /* frees editcurve entirely */
91 void BKE_free_editfont(Curve *cu)
94 EditFont *ef= cu->editfont;
96 if(ef->oldstr) MEM_freeN(ef->oldstr);
97 if(ef->oldstrinfo) MEM_freeN(ef->oldstrinfo);
98 if(ef->textbuf) MEM_freeN(ef->textbuf);
99 if(ef->textbufinfo) MEM_freeN(ef->textbufinfo);
100 if(ef->copybuf) MEM_freeN(ef->copybuf);
101 if(ef->copybufinfo) MEM_freeN(ef->copybufinfo);
108 /* don't free curve itself */
109 void free_curve(Curve *cu)
111 freeNurblist(&cu->nurb);
112 BLI_freelistN(&cu->bev);
113 freedisplist(&cu->disp);
114 BKE_free_editfont(cu);
117 freeNurblist(cu->editnurb);
118 MEM_freeN(cu->editnurb);
123 BKE_free_animdata((ID *)cu);
125 if(cu->mat) MEM_freeN(cu->mat);
126 if(cu->str) MEM_freeN(cu->str);
127 if(cu->strinfo) MEM_freeN(cu->strinfo);
128 if(cu->bb) MEM_freeN(cu->bb);
129 if(cu->path) free_path(cu->path);
130 if(cu->tb) MEM_freeN(cu->tb);
133 Curve *add_curve(char *name, int type)
137 cu= alloc_libblock(&G.main->curve, ID_CU, name);
139 cu->size[0]= cu->size[1]= cu->size[2]= 1.0;
140 cu->flag= CU_FRONT+CU_BACK;
142 cu->resolu= cu->resolv= 12;
145 cu->spacing= cu->linedist= 1.0;
148 cu->texflag= CU_AUTOSPACE;
150 cu->bb= unit_boundbox();
153 cu->vfont= cu->vfontb= cu->vfonti= cu->vfontbi= get_builtin_font();
155 cu->str= MEM_mallocN(12, "str");
156 strcpy(cu->str, "Text");
158 cu->strinfo= MEM_callocN(12*sizeof(CharInfo), "strinfo new");
159 cu->totbox= cu->actbox= 1;
160 cu->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "textbox");
161 cu->tb[0].w = cu->tb[0].h = 0.0;
167 Curve *copy_curve(Curve *cu)
172 cun= copy_libblock(cu);
173 cun->nurb.first= cun->nurb.last= 0;
174 duplicateNurblist( &(cun->nurb), &(cu->nurb));
176 cun->mat= MEM_dupallocN(cu->mat);
177 for(a=0; a<cun->totcol; a++) {
178 id_us_plus((ID *)cun->mat[a]);
181 cun->str= MEM_dupallocN(cu->str);
182 cun->strinfo= MEM_dupallocN(cu->strinfo);
183 cun->tb= MEM_dupallocN(cu->tb);
184 cun->bb= MEM_dupallocN(cu->bb);
186 cun->key= copy_key(cu->key);
187 if(cun->key) cun->key->from= (ID *)cun;
189 cun->disp.first= cun->disp.last= 0;
190 cun->bev.first= cun->bev.last= 0;
195 #if 0 // XXX old animation system
196 /* single user ipo too */
197 if(cun->ipo) cun->ipo= copy_ipo(cun->ipo);
198 #endif // XXX old animation system
200 id_us_plus((ID *)cun->vfont);
201 id_us_plus((ID *)cun->vfontb);
202 id_us_plus((ID *)cun->vfonti);
203 id_us_plus((ID *)cun->vfontbi);
208 void make_local_curve(Curve *cu)
214 /* - when there are only lib users: don't do
215 * - when there are only local users: set flag
219 if(cu->id.lib==0) return;
221 if(cu->vfont) cu->vfont->id.lib= 0;
225 cu->id.flag= LIB_LOCAL;
226 new_id(0, (ID *)cu, 0);
230 ob= G.main->object.first;
233 if(ob->id.lib) lib= 1;
239 if(local && lib==0) {
241 cu->id.flag= LIB_LOCAL;
242 new_id(0, (ID *)cu, 0);
244 else if(local && lib) {
248 ob= G.main->object.first;
263 short curve_type(Curve *cu)
269 for (nu= cu->nurb.first; nu; nu= nu->next) {
278 void test_curve_type(Object *ob)
280 ob->type = curve_type(ob->data);
283 void tex_space_curve(Curve *cu)
287 float *fp, min[3], max[3], loc[3], size[3];
290 if(cu->bb==NULL) cu->bb= MEM_callocN(sizeof(BoundBox), "boundbox");
293 INIT_MINMAX(min, max);
298 if(dl->type==DL_INDEX3 || dl->type==DL_INDEX3) tot= dl->nr;
299 else tot= dl->nr*dl->parts;
304 DO_MINMAX(fp, min, max);
311 min[0] = min[1] = min[2] = -1.0f;
312 max[0] = max[1] = max[2] = 1.0f;
315 loc[0]= (min[0]+max[0])/2.0f;
316 loc[1]= (min[1]+max[1])/2.0f;
317 loc[2]= (min[2]+max[2])/2.0f;
319 size[0]= (max[0]-min[0])/2.0f;
320 size[1]= (max[1]-min[1])/2.0f;
321 size[2]= (max[2]-min[2])/2.0f;
323 boundbox_set_from_min_max(bb, min, max);
325 if(cu->texflag & CU_AUTOSPACE) {
326 VECCOPY(cu->loc, loc);
327 VECCOPY(cu->size, size);
328 cu->rot[0]= cu->rot[1]= cu->rot[2]= 0.0;
330 if(cu->size[0]==0.0) cu->size[0]= 1.0;
331 else if(cu->size[0]>0.0 && cu->size[0]<0.00001) cu->size[0]= 0.00001;
332 else if(cu->size[0]<0.0 && cu->size[0]> -0.00001) cu->size[0]= -0.00001;
334 if(cu->size[1]==0.0) cu->size[1]= 1.0;
335 else if(cu->size[1]>0.0 && cu->size[1]<0.00001) cu->size[1]= 0.00001;
336 else if(cu->size[1]<0.0 && cu->size[1]> -0.00001) cu->size[1]= -0.00001;
338 if(cu->size[2]==0.0) cu->size[2]= 1.0;
339 else if(cu->size[2]>0.0 && cu->size[2]<0.00001) cu->size[2]= 0.00001;
340 else if(cu->size[2]<0.0 && cu->size[2]> -0.00001) cu->size[2]= -0.00001;
346 int count_curveverts(ListBase *nurb)
353 if(nu->bezt) tot+= 3*nu->pntsu;
354 else if(nu->bp) tot+= nu->pntsu*nu->pntsv;
361 int count_curveverts_without_handles(ListBase *nurb)
368 if(nu->bezt) tot+= nu->pntsu;
369 else if(nu->bp) tot+= nu->pntsu*nu->pntsv;
376 /* **************** NURBS ROUTINES ******************** */
378 void freeNurb(Nurb *nu)
383 if(nu->bezt) MEM_freeN(nu->bezt);
385 if(nu->bp) MEM_freeN(nu->bp);
387 if(nu->knotsu) MEM_freeN(nu->knotsu);
389 if(nu->knotsv) MEM_freeN(nu->knotsv);
391 /* if(nu->trim.first) freeNurblist(&(nu->trim)); */
398 void freeNurblist(ListBase *lb)
410 lb->first= lb->last= 0;
413 Nurb *duplicateNurb(Nurb *nu)
418 newnu= (Nurb*)MEM_mallocN(sizeof(Nurb),"duplicateNurb");
419 if(newnu==0) return 0;
420 memcpy(newnu, nu, sizeof(Nurb));
424 (BezTriple*)MEM_mallocN((nu->pntsu)* sizeof(BezTriple),"duplicateNurb2");
425 memcpy(newnu->bezt, nu->bezt, nu->pntsu*sizeof(BezTriple));
428 len= nu->pntsu*nu->pntsv;
430 (BPoint*)MEM_mallocN((len)* sizeof(BPoint),"duplicateNurb3");
431 memcpy(newnu->bp, nu->bp, len*sizeof(BPoint));
433 newnu->knotsu= newnu->knotsv= NULL;
438 newnu->knotsu= MEM_mallocN(len*sizeof(float), "duplicateNurb4");
439 memcpy(newnu->knotsu, nu->knotsu, sizeof(float)*len);
442 if(nu->pntsv>1 && nu->knotsv) {
445 newnu->knotsv= MEM_mallocN(len*sizeof(float), "duplicateNurb5");
446 memcpy(newnu->knotsv, nu->knotsv, sizeof(float)*len);
453 void duplicateNurblist(ListBase *lb1, ListBase *lb2)
461 nun= duplicateNurb(nu);
462 BLI_addtail(lb1, nun);
468 void test2DNurb(Nurb *nu)
474 if( nu->type== CU_BEZIER+CU_2D ) {
478 bezt->vec[0][2]= 0.0;
479 bezt->vec[1][2]= 0.0;
480 bezt->vec[2][2]= 0.0;
484 else if(nu->type & CU_2D) {
485 a= nu->pntsu*nu->pntsv;
494 void minmaxNurb(Nurb *nu, float *min, float *max)
500 if( (nu->type & 7)==CU_BEZIER ) {
504 DO_MINMAX(bezt->vec[0], min, max);
505 DO_MINMAX(bezt->vec[1], min, max);
506 DO_MINMAX(bezt->vec[2], min, max);
511 a= nu->pntsu*nu->pntsv;
514 DO_MINMAX(bp->vec, min, max);
521 /* ~~~~~~~~~~~~~~~~~~~~Non Uniform Rational B Spline calculations ~~~~~~~~~~~ */
524 static void calcknots(float *knots, short aantal, short order, short type)
525 /* knots: number of pnts NOT corrected for cyclic */
526 /* type; 0: uniform, 1: endpoints, 2: bezier */
542 if(a>=order && a<=aantal) k+= 1.0;
546 /* Warning, the order MUST be 2 or 4, if this is not enforced, the displist will be corrupt */
550 knots[a]= (float)floor(k);
557 if(a>=order && a<=aantal) k+= (0.5);
558 knots[a]= (float)floor(k);
562 printf("bez nurb curve order is not 3 or 4, should never happen\n");
567 static void makecyclicknots(float *knots, short pnts, short order)
568 /* pnts, order: number of pnts NOT corrected for cyclic */
576 /* do first long rows (order -1), remove identical knots at endpoints */
579 for(a=1; a<order2; a++) {
580 if(knots[b]!= knots[b-a]) break;
582 if(a==order2) knots[pnts+order-2]+= 1.0;
586 c=pnts + order + order2;
587 for(a=pnts+order2; a<c; a++) {
588 knots[a]= knots[a-1]+ (knots[b]-knots[b-1]);
595 void makeknots(Nurb *nu, short uv)
597 if( (nu->type & 7)==CU_NURBS ) {
599 if(nu->knotsu) MEM_freeN(nu->knotsu);
600 if(check_valid_nurb_u(nu)) {
601 nu->knotsu= MEM_callocN(4+sizeof(float)*KNOTSU(nu), "makeknots");
602 if(nu->flagu & CU_CYCLIC) {
603 calcknots(nu->knotsu, nu->pntsu, nu->orderu, 0); /* cyclic should be uniform */
604 makecyclicknots(nu->knotsu, nu->pntsu, nu->orderu);
606 calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu>>1);
609 else nu->knotsu= NULL;
612 if(nu->knotsv) MEM_freeN(nu->knotsv);
613 if(check_valid_nurb_v(nu)) {
614 nu->knotsv= MEM_callocN(4+sizeof(float)*KNOTSV(nu), "makeknots");
615 if(nu->flagv & CU_CYCLIC) {
616 calcknots(nu->knotsv, nu->pntsv, nu->orderv, 0); /* cyclic should be uniform */
617 makecyclicknots(nu->knotsv, nu->pntsv, nu->orderv);
619 calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv>>1);
622 else nu->knotsv= NULL;
627 static void basisNurb(float t, short order, short pnts, float *knots, float *basis, int *start, int *end)
630 int i, i1 = 0, i2 = 0 ,j, orderpluspnts, opp2, o2;
632 orderpluspnts= order+pnts;
633 opp2 = orderpluspnts-1;
635 /* this is for float inaccuracy */
636 if(t < knots[0]) t= knots[0];
637 else if(t > knots[opp2]) t= knots[opp2];
639 /* this part is order '1' */
641 for(i=0;i<opp2;i++) {
642 if(knots[i]!=knots[i+1] && t>= knots[i] && t<=knots[i+1]) {
658 /* this is order 2,3,... */
659 for(j=2; j<=order; j++) {
661 if(i2+j>= orderpluspnts) i2= opp2-j;
663 for(i= i1; i<=i2; i++) {
665 d= ((t-knots[i])*basis[i]) / (knots[i+j-1]-knots[i]);
670 e= ((knots[i+j]-t)*basis[i+1]) / (knots[i+j]-knots[i+1]);
681 for(i=i1; i<=i2; i++) {
684 if(*start==1000) *start= i;
690 void makeNurbfaces(Nurb *nu, float *coord_array, int rowstride)
691 /* coord_array has to be 3*4*resolu*resolv in size, and zero-ed */
694 float *basisu, *basis, *basisv, *sum, *fp, *in;
695 float u, v, ustart, uend, ustep, vstart, vend, vstep, sumdiv;
696 int i, j, iofs, jofs, cycl, len, resolu, resolv;
697 int istart, iend, jsta, jen, *jstart, *jend, ratcomp;
699 int totu = nu->pntsu*nu->resolu, totv = nu->pntsv*nu->resolv;
701 if(nu->knotsu==NULL || nu->knotsv==NULL) return;
702 if(nu->orderu>nu->pntsu) return;
703 if(nu->orderv>nu->pntsv) return;
704 if(coord_array==NULL) return;
706 /* allocate and initialize */
712 sum= (float *)MEM_callocN(sizeof(float)*len, "makeNurbfaces1");
721 i= nu->pntsu*nu->pntsv;
724 if(bp->vec[3]!=1.0) {
732 ustart= fp[nu->orderu-1];
733 if(nu->flagu & CU_CYCLIC) uend= fp[nu->pntsu+nu->orderu-1];
734 else uend= fp[nu->pntsu];
735 ustep= (uend-ustart)/((nu->flagu & CU_CYCLIC) ? totu : totu - 1);
737 basisu= (float *)MEM_mallocN(sizeof(float)*KNOTSU(nu), "makeNurbfaces3");
740 vstart= fp[nu->orderv-1];
742 if(nu->flagv & CU_CYCLIC) vend= fp[nu->pntsv+nu->orderv-1];
743 else vend= fp[nu->pntsv];
744 vstep= (vend-vstart)/((nu->flagv & CU_CYCLIC) ? totv : totv - 1);
747 basisv= (float *)MEM_mallocN(sizeof(float)*len*totv, "makeNurbfaces3");
748 jstart= (int *)MEM_mallocN(sizeof(float)*totv, "makeNurbfaces4");
749 jend= (int *)MEM_mallocN(sizeof(float)*totv, "makeNurbfaces5");
751 /* precalculation of basisv and jstart,jend */
752 if(nu->flagv & CU_CYCLIC) cycl= nu->orderv-1;
758 basisNurb(v, nu->orderv, (short)(nu->pntsv+cycl), nu->knotsv, basis, jstart+resolv, jend+resolv);
763 if(nu->flagu & CU_CYCLIC) cycl= nu->orderu-1;
770 basisNurb(u, nu->orderu, (short)(nu->pntsu+cycl), nu->knotsu, basisu, &istart, &iend);
776 jsta= jstart[resolv];
783 for(j= jsta; j<=jen; j++) {
785 if(j>=nu->pntsv) jofs= (j - nu->pntsv);
787 bp= nu->bp+ nu->pntsu*jofs+istart-1;
789 for(i= istart; i<=iend; i++, fp++) {
793 bp= nu->bp+ nu->pntsu*jofs+iofs;
798 *fp= basisu[i]*basis[j]*bp->vec[3];
801 else *fp= basisu[i]*basis[j];
807 for(j= jsta; j<=jen; j++) {
808 for(i= istart; i<=iend; i++, fp++) {
814 /* one! (1.0) real point now */
816 for(j= jsta; j<=jen; j++) {
818 if(j>=nu->pntsv) jofs= (j - nu->pntsv);
820 bp= nu->bp+ nu->pntsu*jofs+istart-1;
822 for(i= istart; i<=iend; i++, fp++) {
826 bp= nu->bp+ nu->pntsu*jofs+iofs;
831 in[0]+= (*fp) * bp->vec[0];
832 in[1]+= (*fp) * bp->vec[1];
833 in[2]+= (*fp) * bp->vec[2];
842 if (rowstride!=0) in = (float*) (((unsigned char*) in) + (rowstride - 3*totv*sizeof(*in)));
853 void makeNurbcurve(Nurb *nu, float *coord_array, float *tilt_array, float *radius_array, int resolu)
854 /* coord_array has to be 3*4*pntsu*resolu in size and zero-ed
855 * tilt_array and radius_array will be written to if valid */
858 float u, ustart, uend, ustep, sumdiv;
859 float *basisu, *sum, *fp;
860 float *coord_fp= coord_array, *tilt_fp= tilt_array, *radius_fp= radius_array;
861 int i, len, istart, iend, cycl;
863 if(nu->knotsu==NULL) return;
864 if(nu->orderu>nu->pntsu) return;
865 if(coord_array==0) return;
867 /* allocate and initialize */
870 sum= (float *)MEM_callocN(sizeof(float)*len, "makeNurbcurve1");
872 resolu= (resolu*SEGMENTSU(nu));
880 ustart= fp[nu->orderu-1];
881 if(nu->flagu & CU_CYCLIC) uend= fp[nu->pntsu+nu->orderu-1];
882 else uend= fp[nu->pntsu];
883 ustep= (uend-ustart)/(resolu - ((nu->flagu & CU_CYCLIC) ? 0 : 1));
885 basisu= (float *)MEM_mallocN(sizeof(float)*KNOTSU(nu), "makeNurbcurve3");
887 if(nu->flagu & CU_CYCLIC) cycl= nu->orderu-1;
893 basisNurb(u, nu->orderu, (short)(nu->pntsu+cycl), nu->knotsu, basisu, &istart, &iend);
897 bp= nu->bp+ istart-1;
898 for(i= istart; i<=iend; i++, fp++) {
900 if(i>=nu->pntsu) bp= nu->bp+(i - nu->pntsu);
903 *fp= basisu[i]*bp->vec[3];
906 if(sumdiv!=0.0) if(sumdiv<0.999 || sumdiv>1.001) {
907 /* is normalizing needed? */
909 for(i= istart; i<=iend; i++, fp++) {
914 /* one! (1.0) real point */
916 bp= nu->bp+ istart-1;
917 for(i= istart; i<=iend; i++, fp++) {
919 if(i>=nu->pntsu) bp= nu->bp+(i - nu->pntsu);
924 coord_fp[0]+= (*fp) * bp->vec[0];
925 coord_fp[1]+= (*fp) * bp->vec[1];
926 coord_fp[2]+= (*fp) * bp->vec[2];
929 (*tilt_fp) += (*fp) * bp->alfa;
932 (*radius_fp) += (*fp) * bp->radius;
939 if (tilt_fp) tilt_fp++;
940 if (radius_fp) radius_fp++;
950 /* forward differencing method for bezier curve */
951 void forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
953 float rt0,rt1,rt2,rt3,f;
960 rt2= 3.0f*(q0-2.0f*q1+q2)/f;
962 rt3= (q3-q0+3.0f*(q1-q2))/f;
969 for(a=0; a<=it; a++) {
978 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
980 float *make_orco_surf(Object *ob)
986 float *fp, *coord_array;
988 /* first calculate the size of the datablock */
991 /* as we want to avoid the seam in a cyclic nurbs
992 texture wrapping, reserve extra orco data space to save these extra needed
993 vertex based UV coordinates for the meridian vertices.
994 Vertices on the 0/2pi boundary are not duplicated inside the displist but later in
995 the renderface/vert construction.
997 See also convertblender.c: init_render_surf()
1000 sizeu = nu->pntsu*nu->resolu;
1001 sizev = nu->pntsv*nu->resolv;
1002 if (nu->flagu & CU_CYCLIC) sizeu++;
1003 if (nu->flagv & CU_CYCLIC) sizev++;
1004 if(nu->pntsv>1) tot+= sizeu * sizev;
1008 /* makeNurbfaces wants zeros */
1009 fp= coord_array= MEM_callocN(3*sizeof(float)*tot, "make_orco");
1014 sizeu = nu->pntsu*nu->resolu;
1015 sizev = nu->pntsv*nu->resolv;
1016 if (nu->flagu & CU_CYCLIC) sizeu++;
1017 if (nu->flagv & CU_CYCLIC) sizev++;
1019 if(cu->flag & CU_UV_ORCO) {
1020 for(b=0; b< sizeu; b++) {
1021 for(a=0; a< sizev; a++) {
1023 if(sizev <2) fp[0]= 0.0f;
1024 else fp[0]= -1.0f + 2.0f*((float)a)/(sizev - 1);
1026 if(sizeu <2) fp[1]= 0.0f;
1027 else fp[1]= -1.0f + 2.0f*((float)b)/(sizeu - 1);
1036 float *_tdata= MEM_callocN((nu->pntsu*nu->resolu) * (nu->pntsv*nu->resolv) *3*sizeof(float), "temp data");
1037 float *tdata= _tdata;
1039 makeNurbfaces(nu, tdata, 0);
1041 for(b=0; b<sizeu; b++) {
1043 if (b==sizeu-1 && (nu->flagu & CU_CYCLIC))
1046 for(a=0; a<sizev; a++) {
1048 if (a==sizev-1 && (nu->flagv & CU_CYCLIC))
1051 tdata = _tdata + 3 * (use_b * (nu->pntsv*nu->resolv) + use_a);
1053 fp[0]= (tdata[0]-cu->loc[0])/cu->size[0];
1054 fp[1]= (tdata[1]-cu->loc[1])/cu->size[1];
1055 fp[2]= (tdata[2]-cu->loc[2])/cu->size[2];
1070 /* NOTE: This routine is tied to the order of vertex
1071 * built by displist and as passed to the renderer.
1073 float *make_orco_curve(Scene *scene, Object *ob)
1075 Curve *cu = ob->data;
1078 float *fp, *coord_array;
1081 if (!(cu->flag&CU_UV_ORCO) && cu->key && cu->key->refkey) {
1082 cp_cu_key(cu, cu->key->refkey, 0, count_curveverts(&cu->nurb));
1083 makeDispListCurveTypes(scene, ob, 1);
1087 /* Assumes displist has been built */
1090 for (dl=cu->disp.first; dl; dl=dl->next) {
1091 if (dl->type==DL_INDEX3) {
1093 } else if (dl->type==DL_SURF) {
1094 /* convertblender.c uses the Surface code for creating renderfaces when cyclic U only (closed circle beveling) */
1095 if (dl->flag & DL_CYCL_U) {
1096 if (dl->flag & DL_CYCL_V)
1097 numVerts += (dl->parts+1)*(dl->nr+1);
1099 numVerts += dl->parts*(dl->nr+1);
1102 numVerts += dl->parts*dl->nr;
1106 fp= coord_array= MEM_mallocN(3*sizeof(float)*numVerts, "cu_orco");
1107 for (dl=cu->disp.first; dl; dl=dl->next) {
1108 if (dl->type==DL_INDEX3) {
1109 for (u=0; u<dl->nr; u++, fp+=3) {
1110 if (cu->flag & CU_UV_ORCO) {
1111 fp[0]= 2.0f*u/(dl->nr-1) - 1.0f;
1115 VECCOPY(fp, &dl->verts[u*3]);
1117 fp[0]= (fp[0]-cu->loc[0])/cu->size[0];
1118 fp[1]= (fp[1]-cu->loc[1])/cu->size[1];
1119 fp[2]= (fp[2]-cu->loc[2])/cu->size[2];
1122 } else if (dl->type==DL_SURF) {
1123 int sizeu= dl->nr, sizev= dl->parts;
1125 /* exception as handled in convertblender.c too */
1126 if (dl->flag & DL_CYCL_U) {
1128 if (dl->flag & DL_CYCL_V)
1132 for (u=0; u<sizev; u++) {
1133 for (v=0; v<sizeu; v++,fp+=3) {
1134 if (cu->flag & CU_UV_ORCO) {
1135 fp[0]= 2.0f*u/(dl->parts-1) - 1.0f;
1136 fp[1]= 2.0f*v/(dl->nr-1) - 1.0f;
1140 int realv= v % dl->nr;
1141 int realu= u % dl->parts;
1143 vert= dl->verts + 3*(dl->nr*realu + realv);
1146 fp[0]= (fp[0]-cu->loc[0])/cu->size[0];
1147 fp[1]= (fp[1]-cu->loc[1])/cu->size[1];
1148 fp[2]= (fp[2]-cu->loc[2])/cu->size[2];
1156 makeDispListCurveTypes(scene, ob, 0);
1163 /* ***************** BEVEL ****************** */
1165 void makebevelcurve(Scene *scene, Object *ob, ListBase *disp)
1167 DispList *dl, *dlnew;
1169 float *fp, facx, facy, angle, dangle;
1173 disp->first = disp->last = NULL;
1175 /* if a font object is being edited, then do nothing */
1176 // XXX if( ob == obedit && ob->type == OB_FONT ) return;
1178 if(cu->bevobj && cu->bevobj!=ob) {
1179 if(cu->bevobj->type==OB_CURVE) {
1180 bevcu= cu->bevobj->data;
1181 if(bevcu->ext1==0.0 && bevcu->ext2==0.0) {
1182 facx= cu->bevobj->size[0];
1183 facy= cu->bevobj->size[1];
1185 dl= bevcu->disp.first;
1187 makeDispListCurveTypes(scene, cu->bevobj, 0);
1188 dl= bevcu->disp.first;
1191 if ELEM(dl->type, DL_POLY, DL_SEGM) {
1192 dlnew= MEM_mallocN(sizeof(DispList), "makebevelcurve1");
1194 dlnew->verts= MEM_mallocN(3*sizeof(float)*dl->parts*dl->nr, "makebevelcurve1");
1195 memcpy(dlnew->verts, dl->verts, 3*sizeof(float)*dl->parts*dl->nr);
1197 if(dlnew->type==DL_SEGM) dlnew->flag |= (DL_FRONT_CURVE|DL_BACK_CURVE);
1199 BLI_addtail(disp, dlnew);
1201 nr= dlnew->parts*dlnew->nr;
1214 else if(cu->ext1==0.0 && cu->ext2==0.0) {
1217 else if(cu->ext2==0.0) {
1218 dl= MEM_callocN(sizeof(DispList), "makebevelcurve2");
1219 dl->verts= MEM_mallocN(2*3*sizeof(float), "makebevelcurve2");
1220 BLI_addtail(disp, dl);
1223 dl->flag= DL_FRONT_CURVE|DL_BACK_CURVE;
1232 else if( (cu->flag & (CU_FRONT|CU_BACK))==0 && cu->ext1==0.0f) { // we make a full round bevel in that case
1234 nr= 4+ 2*cu->bevresol;
1236 dl= MEM_callocN(sizeof(DispList), "makebevelcurve p1");
1237 dl->verts= MEM_mallocN(nr*3*sizeof(float), "makebevelcurve p1");
1238 BLI_addtail(disp, dl);
1241 dl->flag= DL_BACK_CURVE;
1246 dangle= (2.0f*M_PI/(nr));
1247 angle= -(nr-1)*dangle;
1249 for(a=0; a<nr; a++) {
1251 fp[1]= (float)(cos(angle)*(cu->ext2));
1252 fp[2]= (float)(sin(angle)*(cu->ext2)) - cu->ext1;
1260 /* bevel now in three parts, for proper vertex normals */
1262 dnr= nr= 2+ cu->bevresol;
1263 if( (cu->flag & (CU_FRONT|CU_BACK))==0)
1264 nr= 3+ 2*cu->bevresol;
1266 dl= MEM_callocN(sizeof(DispList), "makebevelcurve p1");
1267 dl->verts= MEM_mallocN(nr*3*sizeof(float), "makebevelcurve p1");
1268 BLI_addtail(disp, dl);
1271 dl->flag= DL_BACK_CURVE;
1276 dangle= (0.5*M_PI/(dnr-1));
1277 angle= -(nr-1)*dangle;
1279 for(a=0; a<nr; a++) {
1281 fp[1]= (float)(cos(angle)*(cu->ext2));
1282 fp[2]= (float)(sin(angle)*(cu->ext2)) - cu->ext1;
1287 /* part 2, sidefaces */
1291 dl= MEM_callocN(sizeof(DispList), "makebevelcurve p2");
1292 dl->verts= MEM_callocN(nr*3*sizeof(float), "makebevelcurve p2");
1293 BLI_addtail(disp, dl);
1304 if( (cu->flag & (CU_FRONT|CU_BACK))==0) {
1305 dl= MEM_dupallocN(dl);
1306 dl->verts= MEM_dupallocN(dl->verts);
1307 BLI_addtail(disp, dl);
1318 dnr= nr= 2+ cu->bevresol;
1319 if( (cu->flag & (CU_FRONT|CU_BACK))==0)
1320 nr= 3+ 2*cu->bevresol;
1322 dl= MEM_callocN(sizeof(DispList), "makebevelcurve p3");
1323 dl->verts= MEM_mallocN(nr*3*sizeof(float), "makebevelcurve p3");
1324 BLI_addtail(disp, dl);
1326 dl->flag= DL_FRONT_CURVE;
1333 dangle= (0.5*M_PI/(dnr-1));
1335 for(a=0; a<nr; a++) {
1337 fp[1]= (float)(cos(angle)*(cu->ext2));
1338 fp[2]= (float)(sin(angle)*(cu->ext2)) + cu->ext1;
1345 int cu_isectLL(float *v1, float *v2, float *v3, float *v4, short cox, short coy, float *labda, float *mu, float *vec)
1349 0: no intersection of segments
1350 1: exact intersection of segments
1351 2: cross-intersection of segments
1355 deler= (v1[cox]-v2[cox])*(v3[coy]-v4[coy])-(v3[cox]-v4[cox])*(v1[coy]-v2[coy]);
1356 if(deler==0.0) return -1;
1358 *labda= (v1[coy]-v3[coy])*(v3[cox]-v4[cox])-(v1[cox]-v3[cox])*(v3[coy]-v4[coy]);
1359 *labda= -(*labda/deler);
1361 deler= v3[coy]-v4[coy];
1363 deler=v3[cox]-v4[cox];
1364 *mu= -(*labda*(v2[cox]-v1[cox])+v1[cox]-v3[cox])/deler;
1366 *mu= -(*labda*(v2[coy]-v1[coy])+v1[coy]-v3[coy])/deler;
1368 vec[cox]= *labda*(v2[cox]-v1[cox])+v1[cox];
1369 vec[coy]= *labda*(v2[coy]-v1[coy])+v1[coy];
1371 if(*labda>=0.0 && *labda<=1.0 && *mu>=0.0 && *mu<=1.0) {
1372 if(*labda==0.0 || *labda==1.0 || *mu==0.0 || *mu==1.0) return 1;
1379 static short bevelinside(BevList *bl1,BevList *bl2)
1381 /* is bl2 INSIDE bl1 ? with left-right method and "labda's" */
1382 /* returns '1' if correct hole */
1383 BevPoint *bevp, *prevbevp;
1384 float min,max,vec[3],hvec1[3],hvec2[3],lab,mu;
1385 int nr, links=0,rechts=0,mode;
1387 /* take first vertex of possible hole */
1389 bevp= (BevPoint *)(bl2+1);
1393 VECCOPY(hvec2,hvec1);
1396 /* test it with all edges of potential surounding poly */
1397 /* count number of transitions left-right */
1399 bevp= (BevPoint *)(bl1+1);
1401 prevbevp= bevp+(nr-1);
1411 if(min<=hvec1[1] && max>=hvec1[1]) {
1412 /* there's a transition, calc intersection point */
1413 mode= cu_isectLL(&(prevbevp->x),&(bevp->x),hvec1,hvec2,0,1,&lab,&mu,vec);
1414 /* if lab==0.0 or lab==1.0 then the edge intersects exactly a transition
1415 only allow for one situation: we choose lab= 1.0
1417 if(mode>=0 && lab!=0.0) {
1418 if(vec[0]<hvec1[0]) links++;
1427 if( (links & 1) && (rechts & 1) ) return 1;
1438 static int vergxcobev(const void *a1, const void *a2)
1440 const struct bevelsort *x1=a1,*x2=a2;
1442 if( x1->left > x2->left ) return 1;
1443 else if( x1->left < x2->left) return -1;
1447 /* this function cannot be replaced with atan2, but why? */
1449 static void calc_bevel_sin_cos(float x1, float y1, float x2, float y2, float *sina, float *cosa)
1451 float t01, t02, x3, y3;
1453 t01= (float)sqrt(x1*x1+y1*y1);
1454 t02= (float)sqrt(x2*x2+y2*y2);
1455 if(t01==0.0) t01= 1.0;
1456 if(t02==0.0) t02= 1.0;
1464 if(fabs(t02)>=1.0) t02= .5*M_PI;
1465 else t02= (saacos(t02))/2.0f;
1467 t02= (float)sin(t02);
1468 if(t02==0.0) t02= 1.0;
1472 if(x3==0 && y3==0) {
1476 t01= (float)sqrt(x3*x3+y3*y3);
1486 static void alfa_bezpart(BezTriple *prevbezt, BezTriple *bezt, Nurb *nu, float *tilt_array, float *radius_array, int resolu)
1488 BezTriple *pprev, *next, *last;
1489 float fac, dfac, t[4];
1492 last= nu->bezt+(nu->pntsu-1);
1494 /* returns a point */
1495 if(prevbezt==nu->bezt) {
1496 if(nu->flagu & CU_CYCLIC) pprev= last;
1497 else pprev= prevbezt;
1499 else pprev= prevbezt-1;
1503 if(nu->flagu & CU_CYCLIC) next= nu->bezt;
1509 dfac= 1.0f/(float)resolu;
1511 for(a=0; a<resolu; a++, fac+= dfac) {
1513 if (nu->tilt_interp==3) { /* May as well support for tilt also 2.47 ease interp */
1514 tilt_array[a] = prevbezt->alfa + (bezt->alfa - prevbezt->alfa)*(3.0f*fac*fac - 2.0f*fac*fac*fac);
1516 set_four_ipo(fac, t, nu->tilt_interp);
1517 tilt_array[a]= t[0]*pprev->alfa + t[1]*prevbezt->alfa + t[2]*bezt->alfa + t[3]*next->alfa;
1522 if (nu->radius_interp==3) {
1523 /* Support 2.47 ease interp
1524 * Note! - this only takes the 2 points into account,
1525 * giving much more localized results to changes in radius, sometimes you want that */
1526 radius_array[a] = prevbezt->radius + (bezt->radius - prevbezt->radius)*(3.0f*fac*fac - 2.0f*fac*fac*fac);
1529 /* reuse interpolation from tilt if we can */
1530 if (tilt_array==NULL || nu->tilt_interp != nu->radius_interp) {
1531 set_four_ipo(fac, t, nu->radius_interp);
1533 radius_array[a]= t[0]*pprev->radius + t[1]*prevbezt->radius + t[2]*bezt->radius + t[3]*next->radius;
1539 void makeBevelList(Object *ob)
1542 - convert all curves to polys, with indication of resol and flags for double-vertices
1543 - possibly; do a smart vertice removal (in case Nurb)
1544 - separate in individual blicks with BoundBox
1545 - AutoHole detection
1549 BezTriple *bezt, *prevbezt;
1551 BevList *bl, *blnew, *blnext;
1552 BevPoint *bevp, *bevp2, *bevp1 = NULL, *bevp0;
1553 float min, inp, x1, x2, y1, y2, vec[3];
1554 float *coord_array, *tilt_array=NULL, *radius_array=NULL, *coord_fp, *tilt_fp=NULL, *radius_fp=NULL;
1556 struct bevelsort *sortdata, *sd, *sd1;
1557 int a, b, nr, poly, resolu, len=0;
1558 int do_tilt, do_radius;
1560 /* this function needs an object, because of tflag and upflag */
1563 /* do we need to calculate the radius for each point? */
1564 /* do_radius = (cu->bevobj || cu->taperobj || (cu->flag & CU_FRONT) || (cu->flag & CU_BACK)) ? 0 : 1; */
1566 /* STEP 1: MAKE POLYS */
1568 BLI_freelistN(&(cu->bev));
1569 if(cu->editnurb && ob->type!=OB_FONT) nu= cu->editnurb->first;
1570 else nu= cu->nurb.first;
1574 /* check if we will calculate tilt data */
1575 do_tilt = CU_DO_TILT(cu, nu);
1576 do_radius = CU_DO_RADIUS(cu, nu); /* normal display uses the radius, better just to calculate them */
1578 /* check we are a single point? also check we are not a surface and that the orderu is sane,
1579 * enforced in the UI but can go wrong possibly */
1580 if(!check_valid_nurb_u(nu)) {
1581 bl= MEM_callocN(sizeof(BevList)+1*sizeof(BevPoint), "makeBevelList1");
1582 BLI_addtail(&(cu->bev), bl);
1585 if(G.rendering && cu->resolu_ren!=0)
1586 resolu= cu->resolu_ren;
1590 if((nu->type & 7)==CU_POLY) {
1592 bl= MEM_callocN(sizeof(BevList)+len*sizeof(BevPoint), "makeBevelList2");
1593 BLI_addtail(&(cu->bev), bl);
1595 if(nu->flagu & CU_CYCLIC) bl->poly= 0;
1599 bevp= (BevPoint *)(bl+1);
1603 bevp->x= bp->vec[0];
1604 bevp->y= bp->vec[1];
1605 bevp->z= bp->vec[2];
1606 bevp->alfa= bp->alfa;
1607 bevp->radius= bp->radius;
1613 else if((nu->type & 7)==CU_BEZIER) {
1615 len= resolu*(nu->pntsu+ (nu->flagu & CU_CYCLIC) -1)+1; /* in case last point is not cyclic */
1616 bl= MEM_callocN(sizeof(BevList)+len*sizeof(BevPoint), "makeBevelBPoints");
1617 BLI_addtail(&(cu->bev), bl);
1619 if(nu->flagu & CU_CYCLIC) bl->poly= 0;
1621 bevp= (BevPoint *)(bl+1);
1625 if(nu->flagu & CU_CYCLIC) {
1627 prevbezt= nu->bezt+(nu->pntsu-1);
1634 coord_array= coord_fp= MEM_mallocN(3*sizeof(float)*(resolu+1), "makeBevelCoords");
1637 tilt_array= tilt_fp= MEM_callocN(sizeof(float)*(resolu+1), "makeBevelTilt");
1640 radius_array= radius_fp= MEM_callocN(sizeof(float)*(resolu+1), "nakeBevelRadius");
1643 if(prevbezt->h2==HD_VECT && bezt->h1==HD_VECT) {
1645 bevp->x= prevbezt->vec[1][0];
1646 bevp->y= prevbezt->vec[1][1];
1647 bevp->z= prevbezt->vec[1][2];
1648 bevp->alfa= prevbezt->alfa;
1649 bevp->radius= prevbezt->radius;
1657 v1= prevbezt->vec[1];
1660 /* always do all three, to prevent data hanging around */
1661 forward_diff_bezier(v1[0], v1[3], v2[0], v2[3], coord_array, resolu, 3);
1662 forward_diff_bezier(v1[1], v1[4], v2[1], v2[4], coord_array+1, resolu, 3);
1663 forward_diff_bezier(v1[2], v1[5], v2[2], v2[5], coord_array+2, resolu, 3);
1665 if (do_tilt || do_radius)
1666 alfa_bezpart(prevbezt, bezt, nu, tilt_array, radius_array, resolu);
1668 /* indicate with handlecodes double points */
1669 if(prevbezt->h1==prevbezt->h2) {
1670 if(prevbezt->h1==0 || prevbezt->h1==HD_VECT) bevp->f1= SELECT;
1673 if(prevbezt->h1==0 || prevbezt->h1==HD_VECT) bevp->f1= SELECT;
1674 else if(prevbezt->h2==0 || prevbezt->h2==HD_VECT) bevp->f1= SELECT;
1679 coord_fp = coord_array;
1680 tilt_fp = tilt_array;
1681 radius_fp = radius_array;
1684 bevp->x= coord_fp[0];
1685 bevp->y= coord_fp[1];
1686 bevp->z= coord_fp[2];
1690 bevp->alfa= *tilt_fp;
1695 bevp->radius= *radius_fp;
1707 MEM_freeN(coord_array);
1708 if (do_tilt) MEM_freeN(tilt_array);
1709 if (do_radius) MEM_freeN(radius_array);
1710 coord_array = tilt_array = radius_array = NULL;
1712 if((nu->flagu & CU_CYCLIC)==0) { /* not cyclic: endpoint */
1713 bevp->x= prevbezt->vec[1][0];
1714 bevp->y= prevbezt->vec[1][1];
1715 bevp->z= prevbezt->vec[1][2];
1716 bevp->alfa= prevbezt->alfa;
1717 bevp->radius= prevbezt->radius;
1721 else if((nu->type & 7)==CU_NURBS) {
1723 len= (resolu*SEGMENTSU(nu));
1725 bl= MEM_callocN(sizeof(BevList)+len*sizeof(BevPoint), "makeBevelList3");
1726 BLI_addtail(&(cu->bev), bl);
1729 if(nu->flagu & CU_CYCLIC) bl->poly= 0;
1731 bevp= (BevPoint *)(bl+1);
1733 coord_array= coord_fp= MEM_callocN(3*sizeof(float)*len, "makeBevelCoords"); /* has to be zero-ed */
1736 tilt_array= tilt_fp= MEM_callocN(sizeof(float)*len, "makeBevelTilt");
1739 radius_array= radius_fp= MEM_callocN(sizeof(float)*len, "nakeBevelRadius");
1741 makeNurbcurve(nu, coord_array, tilt_array, radius_array, resolu);
1744 bevp->x= coord_fp[0];
1745 bevp->y= coord_fp[1];
1746 bevp->z= coord_fp[2];
1750 bevp->alfa= *tilt_fp;
1755 bevp->radius= *radius_fp;
1760 bevp->f1= bevp->f2= 0;
1763 MEM_freeN(coord_array);
1764 if (do_tilt) MEM_freeN(tilt_array);
1765 if (do_radius) MEM_freeN(radius_array);
1766 coord_array = tilt_array = radius_array = NULL;
1773 /* STEP 2: DOUBLE POINTS AND AUTOMATIC RESOLUTION, REDUCE DATABLOCKS */
1776 if (bl->nr) { /* null bevel items come from single points */
1778 bevp1= (BevPoint *)(bl+1);
1779 bevp0= bevp1+(nr-1);
1782 if( fabs(bevp0->x-bevp1->x)<0.00001 ) {
1783 if( fabs(bevp0->y-bevp1->y)<0.00001 ) {
1784 if( fabs(bevp0->z-bevp1->z)<0.00001 ) {
1799 if(bl->nr && bl->flag) {
1800 nr= bl->nr- bl->flag+1; /* +1 because vectorbezier sets flag too */
1801 blnew= MEM_mallocN(sizeof(BevList)+nr*sizeof(BevPoint), "makeBevelList4");
1802 memcpy(blnew, bl, sizeof(BevList));
1804 BLI_remlink(&(cu->bev), bl);
1805 BLI_insertlinkbefore(&(cu->bev),blnext,blnew); /* to make sure bevlijst is tuned with nurblist */
1806 bevp0= (BevPoint *)(bl+1);
1807 bevp1= (BevPoint *)(blnew+1);
1811 memcpy(bevp1, bevp0, sizeof(BevPoint));
1823 /* STEP 3: COUNT POLYS TELLEN AND AUTOHOLE */
1827 if(bl->nr && bl->poly>=0) {
1830 bl->gat= 0; /* 'gat' is dutch for hole */
1836 /* find extreme left points, also test (turning) direction */
1838 sd= sortdata= MEM_mallocN(sizeof(struct bevelsort)*poly, "makeBevelList5");
1844 bevp= (BevPoint *)(bl+1);
1856 bevp= (BevPoint *)(bl+1);
1857 if(bevp1== bevp) bevp0= bevp+ (bl->nr-1);
1858 else bevp0= bevp1-1;
1859 bevp= bevp+ (bl->nr-1);
1860 if(bevp1== bevp) bevp2= (BevPoint *)(bl+1);
1861 else bevp2= bevp1+1;
1863 inp= (bevp1->x- bevp0->x)*(bevp0->y- bevp2->y)
1864 +(bevp0->y- bevp1->y)*(bevp0->x- bevp2->x);
1866 if(inp>0.0) sd->dir= 1;
1874 qsort(sortdata,poly,sizeof(struct bevelsort), vergxcobev);
1877 for(a=1; a<poly; a++, sd++) {
1878 bl= sd->bl; /* is bl a hole? */
1879 sd1= sortdata+ (a-1);
1880 for(b=a-1; b>=0; b--, sd1--) { /* all polys to the left */
1881 if(bevelinside(sd1->bl, bl)) {
1882 bl->gat= 1- sd1->bl->gat;
1888 /* turning direction */
1889 if((cu->flag & CU_3D)==0) {
1891 for(a=0; a<poly; a++, sd++) {
1892 if(sd->bl->gat==sd->dir) {
1894 bevp1= (BevPoint *)(bl+1);
1895 bevp2= bevp1+ (bl->nr-1);
1898 SWAP(BevPoint, *bevp1, *bevp2);
1905 MEM_freeN(sortdata);
1908 /* STEP 4: COSINES */
1912 if(bl->nr==2) { /* 2 pnt, treat separate */
1913 bevp2= (BevPoint *)(bl+1);
1916 x1= bevp1->x- bevp2->x;
1917 y1= bevp1->y- bevp2->y;
1919 calc_bevel_sin_cos(x1, y1, -x1, -y1, &(bevp1->sina), &(bevp1->cosa));
1920 bevp2->sina= bevp1->sina;
1921 bevp2->cosa= bevp1->cosa;
1923 if(cu->flag & CU_3D) { /* 3D */
1924 float quat[4], q[4];
1926 vec[0]= bevp1->x - bevp2->x;
1927 vec[1]= bevp1->y - bevp2->y;
1928 vec[2]= bevp1->z - bevp2->z;
1930 vectoquat(vec, 5, 1, quat);
1933 q[0]= (float)cos(0.5*bevp1->alfa);
1934 x1= (float)sin(0.5*bevp1->alfa);
1938 QuatMul(quat, q, quat);
1940 QuatToMat3(quat, bevp1->mat);
1941 Mat3CpyMat3(bevp2->mat, bevp1->mat);
1946 bevp2= (BevPoint *)(bl+1);
1947 bevp1= bevp2+(bl->nr-1);
1955 if(cu->flag & CU_3D) { /* 3D */
1956 float quat[4], q[4];
1958 vec[0]= bevp2->x - bevp0->x;
1959 vec[1]= bevp2->y - bevp0->y;
1960 vec[2]= bevp2->z - bevp0->z;
1964 vectoquat(vec, 5, 1, quat);
1966 q[0]= (float)cos(0.5*bevp1->alfa);
1967 x1= (float)sin(0.5*bevp1->alfa);
1971 QuatMul(quat, q, quat);
1973 QuatToMat3(quat, bevp1->mat);
1976 x1= bevp1->x- bevp0->x;
1977 x2= bevp1->x- bevp2->x;
1978 y1= bevp1->y- bevp0->y;
1979 y2= bevp1->y- bevp2->y;
1981 calc_bevel_sin_cos(x1, y1, x2, y2, &(bevp1->sina), &(bevp1->cosa));
1988 /* correct non-cyclic cases */
1991 bevp= (BevPoint *)(bl+1);
1993 bevp->sina= bevp1->sina;
1994 bevp->cosa= bevp1->cosa;
1995 Mat3CpyMat3(bevp->mat, bevp1->mat);
1996 bevp= (BevPoint *)(bl+1);
1999 bevp->sina= bevp1->sina;
2000 bevp->cosa= bevp1->cosa;
2001 Mat3CpyMat3(bevp->mat, bevp1->mat);
2009 /* ****************** HANDLES ************** */
2013 * 1: nothing, 1:auto, 2:vector, 3:aligned
2016 /* mode: is not zero when FCurve, is 2 when forced horizontal for autohandles */
2017 void calchandleNurb(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode)
2019 float *p1,*p2,*p3, pt[3];
2020 float dx1,dy1,dz1,dx,dy,dz,vx,vy,vz,len,len1,len2;
2022 if(bezt->h1==0 && bezt->h2==0) return;
2028 pt[0]= 2*p2[0]- p3[0];
2029 pt[1]= 2*p2[1]- p3[1];
2030 pt[2]= 2*p2[2]- p3[2];
2033 else p1= prev->vec[1];
2036 pt[0]= 2*p2[0]- p1[0];
2037 pt[1]= 2*p2[1]- p1[1];
2038 pt[2]= 2*p2[2]- p1[2];
2041 else p3= next->vec[1];
2048 else len1= (float)sqrt(dx*dx+dy*dy+dz*dz);
2055 else len2= (float)sqrt(dx1*dx1+dy1*dy1+dz1*dz1);
2057 if(len1==0.0f) len1=1.0f;
2058 if(len2==0.0f) len2=1.0f;
2061 if(bezt->h1==HD_AUTO || bezt->h2==HD_AUTO) { /* auto */
2062 vx= dx1/len2 + dx/len1;
2063 vy= dy1/len2 + dy/len1;
2064 vz= dz1/len2 + dz/len1;
2065 len= 2.5614f*(float)sqrt(vx*vx + vy*vy + vz*vz);
2067 int leftviolate=0, rightviolate=0; /* for mode==2 */
2069 if(len1>5.0f*len2) len1= 5.0f*len2;
2070 if(len2>5.0f*len1) len2= 5.0f*len1;
2072 if(bezt->h1==HD_AUTO) {
2074 *(p2-3)= *p2-vx*len1;
2075 *(p2-2)= *(p2+1)-vy*len1;
2076 *(p2-1)= *(p2+2)-vz*len1;
2078 if(mode==2 && next && prev) { // keep horizontal if extrema
2079 float ydiff1= prev->vec[1][1] - bezt->vec[1][1];
2080 float ydiff2= next->vec[1][1] - bezt->vec[1][1];
2081 if( (ydiff1<=0.0 && ydiff2<=0.0) || (ydiff1>=0.0 && ydiff2>=0.0) ) {
2082 bezt->vec[0][1]= bezt->vec[1][1];
2084 else { // handles should not be beyond y coord of two others
2086 if(prev->vec[1][1] > bezt->vec[0][1]) {
2087 bezt->vec[0][1]= prev->vec[1][1];
2092 if(prev->vec[1][1] < bezt->vec[0][1]) {
2093 bezt->vec[0][1]= prev->vec[1][1];
2100 if(bezt->h2==HD_AUTO) {
2102 *(p2+3)= *p2+vx*len2;
2103 *(p2+4)= *(p2+1)+vy*len2;
2104 *(p2+5)= *(p2+2)+vz*len2;
2106 if(mode==2 && next && prev) { // keep horizontal if extrema
2107 float ydiff1= prev->vec[1][1] - bezt->vec[1][1];
2108 float ydiff2= next->vec[1][1] - bezt->vec[1][1];
2109 if( (ydiff1<=0.0 && ydiff2<=0.0) || (ydiff1>=0.0 && ydiff2>=0.0) ) {
2110 bezt->vec[2][1]= bezt->vec[1][1];
2112 else { // handles should not be beyond y coord of two others
2114 if(next->vec[1][1] < bezt->vec[2][1]) {
2115 bezt->vec[2][1]= next->vec[1][1];
2120 if(next->vec[1][1] > bezt->vec[2][1]) {
2121 bezt->vec[2][1]= next->vec[1][1];
2128 if(leftviolate || rightviolate) { /* align left handle */
2131 VecSubf(h1, p2-3, p2);
2132 VecSubf(h2, p2, p2+3);
2133 len1= Normalize(h1);
2134 len2= Normalize(h2);
2139 *(p2+3)= *(p2) - vz*len2*h1[0];
2140 *(p2+4)= *(p2+1) - vz*len2*h1[1];
2141 *(p2+5)= *(p2+2) - vz*len2*h1[2];
2144 *(p2-3)= *(p2) + vz*len1*h2[0];
2145 *(p2-2)= *(p2+1) + vz*len1*h2[1];
2146 *(p2-1)= *(p2+2) + vz*len1*h2[2];
2153 if(bezt->h1==HD_VECT) { /* vector */
2158 *(p2-2)= *(p2+1)-dy;
2159 *(p2-1)= *(p2+2)-dz;
2161 if(bezt->h2==HD_VECT) {
2166 *(p2+4)= *(p2+1)+dy1;
2167 *(p2+5)= *(p2+2)+dz1;
2170 len2= VecLenf(p2, p2+3);
2171 len1= VecLenf(p2, p2-3);
2172 if(len1==0.0) len1=1.0;
2173 if(len2==0.0) len2=1.0;
2175 if(bezt->f1 & SELECT) { /* order of calculation */
2176 if(bezt->h2==HD_ALIGN) { /* aligned */
2178 p2[3]= p2[0]+len*(p2[0]-p2[-3]);
2179 p2[4]= p2[1]+len*(p2[1]-p2[-2]);
2180 p2[5]= p2[2]+len*(p2[2]-p2[-1]);
2182 if(bezt->h1==HD_ALIGN) {
2184 p2[-3]= p2[0]+len*(p2[0]-p2[3]);
2185 p2[-2]= p2[1]+len*(p2[1]-p2[4]);
2186 p2[-1]= p2[2]+len*(p2[2]-p2[5]);
2190 if(bezt->h1==HD_ALIGN) {
2192 p2[-3]= p2[0]+len*(p2[0]-p2[3]);
2193 p2[-2]= p2[1]+len*(p2[1]-p2[4]);
2194 p2[-1]= p2[2]+len*(p2[2]-p2[5]);
2196 if(bezt->h2==HD_ALIGN) { /* aligned */
2198 p2[3]= p2[0]+len*(p2[0]-p2[-3]);
2199 p2[4]= p2[1]+len*(p2[1]-p2[-2]);
2200 p2[5]= p2[2]+len*(p2[2]-p2[-1]);
2205 void calchandlesNurb(Nurb *nu) /* first, if needed, set handle flags */
2207 BezTriple *bezt, *prev, *next;
2210 if((nu->type & 7)!=CU_BEZIER) return;
2211 if(nu->pntsu<2) return;
2215 if(nu->flagu & CU_CYCLIC) prev= bezt+(a-1);
2220 calchandleNurb(bezt, prev, next, 0);
2223 if(nu->flagu & CU_CYCLIC) next= nu->bezt;
2233 void testhandlesNurb(Nurb *nu)
2235 /* use when something has changed with handles.
2236 it treats all BezTriples with the following rules:
2237 PHASE 1: do types have to be altered?
2238 Auto handles: become aligned when selection status is NOT(000 || 111)
2239 Vector handles: become 'nothing' when (one half selected AND other not)
2240 PHASE 2: recalculate handles
2245 if((nu->type & 7)!=CU_BEZIER) return;
2251 if(bezt->f1 & SELECT) flag++;
2252 if(bezt->f2 & SELECT) flag += 2;
2253 if(bezt->f3 & SELECT) flag += 4;
2255 if( !(flag==0 || flag==7) ) {
2256 if(bezt->h1==HD_AUTO) { /* auto */
2259 if(bezt->h2==HD_AUTO) { /* auto */
2263 if(bezt->h1==HD_VECT) { /* vector */
2264 if(flag < 4) bezt->h1= 0;
2266 if(bezt->h2==HD_VECT) { /* vector */
2267 if( flag > 3) bezt->h2= 0;
2273 calchandlesNurb(nu);
2276 void autocalchandlesNurb(Nurb *nu, int flag)
2278 /* checks handle coordinates and calculates type */
2280 BezTriple *bezt2, *bezt1, *bezt0;
2281 int i, align, leftsmall, rightsmall;
2283 if(nu==0 || nu->bezt==0) return;
2286 bezt1 = bezt2 + (nu->pntsu-1);
2292 align= leftsmall= rightsmall= 0;
2295 if(flag==0 || (bezt1->f1 & flag) ) {
2297 /* distance too short: vectorhandle */
2298 if( VecLenf( bezt1->vec[1], bezt0->vec[1] ) < 0.0001) {
2303 /* aligned handle? */
2304 if(DistVL2Dfl(bezt1->vec[1], bezt1->vec[0], bezt1->vec[2]) < 0.0001) {
2306 bezt1->h1= HD_ALIGN;
2308 /* or vector handle? */
2309 if(DistVL2Dfl(bezt1->vec[0], bezt1->vec[1], bezt0->vec[1]) < 0.0001)
2315 if(flag==0 || (bezt1->f3 & flag) ) {
2317 /* distance too short: vectorhandle */
2318 if( VecLenf( bezt1->vec[1], bezt2->vec[1] ) < 0.0001) {
2323 /* aligned handle? */
2324 if(align) bezt1->h2= HD_ALIGN;
2326 /* or vector handle? */
2327 if(DistVL2Dfl(bezt1->vec[2], bezt1->vec[1], bezt2->vec[1]) < 0.0001)
2332 if(leftsmall && bezt1->h2==HD_ALIGN) bezt1->h2= 0;
2333 if(rightsmall && bezt1->h1==HD_ALIGN) bezt1->h1= 0;
2335 /* undesired combination: */
2336 if(bezt1->h1==HD_ALIGN && bezt1->h2==HD_VECT) bezt1->h1= 0;
2337 if(bezt1->h2==HD_ALIGN && bezt1->h1==HD_VECT) bezt1->h2= 0;
2344 calchandlesNurb(nu);
2347 void autocalchandlesNurb_all(ListBase *editnurb, int flag)
2351 nu= editnurb->first;
2353 autocalchandlesNurb(nu, flag);
2358 void sethandlesNurb(ListBase *editnurb, short code)
2360 /* code==1: set autohandle */
2361 /* code==2: set vectorhandle */
2362 /* code==3 (HD_ALIGN) it toggle, vectorhandles become HD_FREE */
2363 /* code==4: sets icu flag to become IPO_AUTO_HORIZ, horizontal extremes on auto-handles */
2364 /* code==5: Set align, like 3 but no toggle */
2365 /* code==6: Clear align, like 3 but no toggle */
2370 if(code==1 || code==2) {
2371 nu= editnurb->first;
2373 if( (nu->type & 7)==CU_BEZIER) {
2377 if((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
2378 if(bezt->f1 & SELECT) bezt->h1= code;
2379 if(bezt->f3 & SELECT) bezt->h2= code;
2380 if(bezt->h1!=bezt->h2) {
2381 if ELEM(bezt->h1, HD_ALIGN, HD_AUTO) bezt->h1= HD_FREE;
2382 if ELEM(bezt->h2, HD_ALIGN, HD_AUTO) bezt->h2= HD_FREE;
2387 calchandlesNurb(nu);
2393 /* there is 1 handle not FREE: FREE it all, else make ALIGNED */
2395 nu= editnurb->first;
2398 } else if (code == 6) {
2403 if( (nu->type & 7)==CU_BEZIER) {
2407 if((bezt->f1 & SELECT) && bezt->h1) ok= 1;
2408 if((bezt->f3 & SELECT) && bezt->h2) ok= 1;
2418 nu= editnurb->first;
2420 if( (nu->type & 7)==CU_BEZIER) {
2424 if(bezt->f1 & SELECT) bezt->h1= ok;
2425 if(bezt->f3 & SELECT) bezt->h2= ok;
2429 calchandlesNurb(nu);
2436 static void swapdata(void *adr1, void *adr2, int len)
2444 memcpy(adr, adr1, len);
2445 memcpy(adr1, adr2, len);
2446 memcpy(adr2, adr, len);
2451 adr= (char *)MEM_mallocN(len, "curve swap");
2452 memcpy(adr, adr1, len);
2453 memcpy(adr1, adr2, len);
2454 memcpy(adr2, adr, len);
2459 void switchdirectionNurb(Nurb *nu)
2461 BezTriple *bezt1, *bezt2;
2463 float *fp1, *fp2, *tempf;
2466 if(nu->pntsu==1 && nu->pntsv==1) return;
2468 if((nu->type & 7)==CU_BEZIER) {
2472 if(a & 1) a+= 1; /* if odd, also swap middle content */
2475 if(bezt1!=bezt2) SWAP(BezTriple, *bezt1, *bezt2);
2477 swapdata(bezt1->vec[0], bezt1->vec[2], 12);
2478 if(bezt1!=bezt2) swapdata(bezt2->vec[0], bezt2->vec[2], 12);
2480 SWAP(char, bezt1->h1, bezt1->h2);
2481 SWAP(short, bezt1->f1, bezt1->f3);
2484 SWAP(char, bezt2->h1, bezt2->h2);
2485 SWAP(short, bezt2->f1, bezt2->f3);
2486 bezt1->alfa= -bezt1->alfa;
2487 bezt2->alfa= -bezt2->alfa;
2494 else if(nu->pntsv==1) {
2499 while(bp1!=bp2 && a>0) {
2500 SWAP(BPoint, *bp1, *bp2);
2502 bp1->alfa= -bp1->alfa;
2503 bp2->alfa= -bp2->alfa;
2507 if((nu->type & 7)==CU_NURBS) {
2513 while(fp1!=fp2 && a>0) {
2514 SWAP(float, *fp1, *fp2);
2519 /* and make in increasing order again */
2522 fp2=tempf= MEM_mallocN(sizeof(float)*a, "switchdirect");
2524 fp2[0]= fabs(fp1[1]-fp1[0]);
2535 fp1[0]= fp1[-1]+fp2[0];
2544 for(b=0; b<nu->pntsv; b++) {
2546 bp1= nu->bp+b*nu->pntsu;
2551 while(bp1!=bp2 && a>0) {
2552 SWAP(BPoint, *bp1, *bp2);
2562 float (*curve_getVertexCos(Curve *cu, ListBase *lb, int *numVerts_r))[3]
2564 int i, numVerts = *numVerts_r = count_curveverts(lb);
2565 float *co, (*cos)[3] = MEM_mallocN(sizeof(*cos)*numVerts, "cu_vcos");
2569 for (nu=lb->first; nu; nu=nu->next) {
2570 if ((nu->type & 7)==CU_BEZIER) {
2571 BezTriple *bezt = nu->bezt;
2573 for (i=0; i<nu->pntsu; i++,bezt++) {
2574 VECCOPY(co, bezt->vec[0]); co+=3;
2575 VECCOPY(co, bezt->vec[1]); co+=3;
2576 VECCOPY(co, bezt->vec[2]); co+=3;
2579 BPoint *bp = nu->bp;
2581 for (i=0; i<nu->pntsu*nu->pntsv; i++,bp++) {
2582 VECCOPY(co, bp->vec); co+=3;
2590 void curve_applyVertexCos(Curve *cu, ListBase *lb, float (*vertexCos)[3])
2592 float *co = vertexCos[0];
2596 for (nu=lb->first; nu; nu=nu->next) {
2597 if ((nu->type & 7)==CU_BEZIER) {
2598 BezTriple *bezt = nu->bezt;
2600 for (i=0; i<nu->pntsu; i++,bezt++) {
2601 VECCOPY(bezt->vec[0], co); co+=3;
2602 VECCOPY(bezt->vec[1], co); co+=3;
2603 VECCOPY(bezt->vec[2], co); co+=3;
2606 BPoint *bp = nu->bp;
2608 for (i=0; i<nu->pntsu*nu->pntsv; i++,bp++) {
2609 VECCOPY(bp->vec, co); co+=3;
2615 int check_valid_nurb_u( struct Nurb *nu )
2617 if (nu==NULL) return 0;
2618 if (nu->pntsu <= 1) return 0;
2619 if ((nu->type & 7)!=CU_NURBS) return 1; /* not a nurb, lets assume its valid */
2621 if (nu->pntsu < nu->orderu) return 0;
2622 if (((nu->flag & CU_CYCLIC)==0) && ((nu->flagu>>1) & 2)) { /* Bezier U Endpoints */
2623 if (nu->orderu==4) {
2624 if (nu->pntsu < 5) return 0; /* bezier with 4 orderu needs 5 points */
2625 } else if (nu->orderu != 3) return 0; /* order must be 3 or 4 */
2629 int check_valid_nurb_v( struct Nurb *nu)
2631 if (nu==NULL) return 0;
2632 if (nu->pntsv <= 1) return 0;
2633 if ((nu->type & 7)!=CU_NURBS) return 1; /* not a nurb, lets assume its valid */
2635 if (nu->pntsv < nu->orderv) return 0;
2636 if (((nu->flag & CU_CYCLIC)==0) && ((nu->flagv>>1) & 2)) { /* Bezier V Endpoints */
2637 if (nu->orderv==4) {
2638 if (nu->pntsv < 5) return 0; /* bezier with 4 orderu needs 5 points */
2639 } else if (nu->orderv != 3) return 0; /* order must be 3 or 4 */
2644 int clamp_nurb_order_u( struct Nurb *nu )
2647 if(nu->pntsu<nu->orderu) {
2648 nu->orderu= nu->pntsu;
2651 if(((nu->flag & CU_CYCLIC)==0) && (nu->flagu>>1)&2) {
2652 CLAMP(nu->orderu, 3,4);
2658 int clamp_nurb_order_v( struct Nurb *nu)
2661 if(nu->pntsv<nu->orderv) {
2662 nu->orderv= nu->pntsv;
2665 if(((nu->flag & CU_CYCLIC)==0) && (nu->flagv>>1)&2) {
2666 CLAMP(nu->orderv, 3,4);