5 * $Id: curve.c 13209 2008-01-11 18:02:28Z campbellbarton $
7 * ***** BEGIN GPL/BL DUAL 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. The Blender
13 * Foundation also sells licenses for use in proprietary software under
14 * the Blender License. See http://www.blender.org/BL/ for information
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software Foundation,
24 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
27 * All rights reserved.
29 * The Original Code is: all of this file.
31 * Contributor(s): none yet.
33 * ***** END GPL/BL DUAL LICENSE BLOCK *****
36 #include <math.h> // floor
44 #include "MEM_guardedalloc.h"
45 #include "BLI_blenlib.h"
46 #include "BLI_arithb.h"
48 #include "DNA_object_types.h"
49 #include "DNA_curve_types.h"
50 #include "DNA_material_types.h"
52 /* for dereferencing pointers */
54 #include "DNA_vfont_types.h"
55 #include "DNA_key_types.h"
56 #include "DNA_ipo_types.h"
58 #include "BKE_global.h"
60 #include "BKE_utildefines.h" // VECCOPY
61 #include "BKE_object.h"
63 #include "BKE_curve.h"
64 #include "BKE_displist.h"
67 #include "BKE_library.h"
73 extern ListBase editNurb
; /* editcurve.c */
76 int cu_isectLL(float *v1
, float *v2
, float *v3
, float *v4
,
78 float *labda
, float *mu
, float *vec
);
80 void unlink_curve(Curve
*cu
)
84 for(a
=0; a
<cu
->totcol
; a
++) {
85 if(cu
->mat
[a
]) cu
->mat
[a
]->id
.us
--;
88 if(cu
->vfont
) cu
->vfont
->id
.us
--;
90 if(cu
->key
) cu
->key
->id
.us
--;
92 if(cu
->ipo
) cu
->ipo
->id
.us
--;
97 /* niet curve zelf vrijgeven */
98 void free_curve(Curve
*cu
)
101 freeNurblist(&cu
->nurb
);
102 BLI_freelistN(&cu
->bev
);
103 freedisplist(&cu
->disp
);
107 if(cu
->mat
) MEM_freeN(cu
->mat
);
108 if(cu
->str
) MEM_freeN(cu
->str
);
109 if(cu
->strinfo
) MEM_freeN(cu
->strinfo
);
110 if(cu
->bb
) MEM_freeN(cu
->bb
);
111 if(cu
->path
) free_path(cu
->path
);
112 if(cu
->tb
) MEM_freeN(cu
->tb
);
115 Curve
*add_curve(char *name
, int type
)
119 cu
= alloc_libblock(&G
.main
->curve
, ID_CU
, name
);
121 cu
->size
[0]= cu
->size
[1]= cu
->size
[2]= 1.0;
122 cu
->flag
= CU_FRONT
+CU_BACK
;
124 cu
->resolu
= cu
->resolv
= 12;
127 cu
->spacing
= cu
->linedist
= 1.0;
130 cu
->texflag
= CU_AUTOSPACE
;
132 cu
->bb
= unit_boundbox();
137 Curve
*copy_curve(Curve
*cu
)
142 cun
= copy_libblock(cu
);
143 cun
->nurb
.first
= cun
->nurb
.last
= 0;
144 duplicateNurblist( &(cun
->nurb
), &(cu
->nurb
));
146 cun
->mat
= MEM_dupallocN(cu
->mat
);
147 for(a
=0; a
<cun
->totcol
; a
++) {
148 id_us_plus((ID
*)cun
->mat
[a
]);
151 cun
->str
= MEM_dupallocN(cu
->str
);
152 cun
->strinfo
= MEM_dupallocN(cu
->strinfo
);
153 cun
->tb
= MEM_dupallocN(cu
->tb
);
154 cun
->bb
= MEM_dupallocN(cu
->bb
);
156 cun
->key
= copy_key(cu
->key
);
157 if(cun
->key
) cun
->key
->from
= (ID
*)cun
;
159 cun
->disp
.first
= cun
->disp
.last
= 0;
160 cun
->bev
.first
= cun
->bev
.last
= 0;
163 /* single user ipo too */
164 if(cun
->ipo
) cun
->ipo
= copy_ipo(cun
->ipo
);
166 id_us_plus((ID
*)cun
->vfont
);
167 id_us_plus((ID
*)cun
->vfontb
);
168 id_us_plus((ID
*)cun
->vfonti
);
169 id_us_plus((ID
*)cun
->vfontbi
);
174 void make_local_curve(Curve
*cu
)
180 /* - when there are only lib users: don't do
181 * - when there are only local users: set flag
185 if(cu
->id
.lib
==0) return;
187 if(cu
->vfont
) cu
->vfont
->id
.lib
= 0;
191 cu
->id
.flag
= LIB_LOCAL
;
192 new_id(0, (ID
*)cu
, 0);
196 ob
= G
.main
->object
.first
;
199 if(ob
->id
.lib
) lib
= 1;
205 if(local
&& lib
==0) {
207 cu
->id
.flag
= LIB_LOCAL
;
208 new_id(0, (ID
*)cu
, 0);
210 else if(local
&& lib
) {
214 ob
= G
.main
->object
.first
;
229 short curve_type(Curve
*cu
)
235 for (nu
= cu
->nurb
.first
; nu
; nu
= nu
->next
) {
244 void test_curve_type(Object
*ob
)
246 ob
->type
= curve_type(ob
->data
);
249 void tex_space_curve(Curve
*cu
)
253 float *data
, min
[3], max
[3], loc
[3], size
[3];
256 if(cu
->bb
==NULL
) cu
->bb
= MEM_callocN(sizeof(BoundBox
), "boundbox");
259 INIT_MINMAX(min
, max
);
264 if(dl
->type
==DL_INDEX3
|| dl
->type
==DL_INDEX3
) tot
= dl
->nr
;
265 else tot
= dl
->nr
*dl
->parts
;
270 DO_MINMAX(data
, min
, max
);
277 min
[0] = min
[1] = min
[2] = -1.0f
;
278 max
[0] = max
[1] = max
[2] = 1.0f
;
281 loc
[0]= (min
[0]+max
[0])/2.0f
;
282 loc
[1]= (min
[1]+max
[1])/2.0f
;
283 loc
[2]= (min
[2]+max
[2])/2.0f
;
285 size
[0]= (max
[0]-min
[0])/2.0f
;
286 size
[1]= (max
[1]-min
[1])/2.0f
;
287 size
[2]= (max
[2]-min
[2])/2.0f
;
289 boundbox_set_from_min_max(bb
, min
, max
);
291 if(cu
->texflag
& CU_AUTOSPACE
) {
292 VECCOPY(cu
->loc
, loc
);
293 VECCOPY(cu
->size
, size
);
294 cu
->rot
[0]= cu
->rot
[1]= cu
->rot
[2]= 0.0;
296 if(cu
->size
[0]==0.0) cu
->size
[0]= 1.0;
297 else if(cu
->size
[0]>0.0 && cu
->size
[0]<0.00001) cu
->size
[0]= 0.00001;
298 else if(cu
->size
[0]<0.0 && cu
->size
[0]> -0.00001) cu
->size
[0]= -0.00001;
300 if(cu
->size
[1]==0.0) cu
->size
[1]= 1.0;
301 else if(cu
->size
[1]>0.0 && cu
->size
[1]<0.00001) cu
->size
[1]= 0.00001;
302 else if(cu
->size
[1]<0.0 && cu
->size
[1]> -0.00001) cu
->size
[1]= -0.00001;
304 if(cu
->size
[2]==0.0) cu
->size
[2]= 1.0;
305 else if(cu
->size
[2]>0.0 && cu
->size
[2]<0.00001) cu
->size
[2]= 0.00001;
306 else if(cu
->size
[2]<0.0 && cu
->size
[2]> -0.00001) cu
->size
[2]= -0.00001;
312 int count_curveverts(ListBase
*nurb
)
319 if(nu
->bezt
) tot
+= 3*nu
->pntsu
;
320 else if(nu
->bp
) tot
+= nu
->pntsu
*nu
->pntsv
;
329 /* **************** NURBS ROUTINES ******************** */
331 void freeNurb(Nurb
*nu
)
336 if(nu
->bezt
) MEM_freeN(nu
->bezt
);
338 if(nu
->bp
) MEM_freeN(nu
->bp
);
340 if(nu
->knotsu
) MEM_freeN(nu
->knotsu
);
342 if(nu
->knotsv
) MEM_freeN(nu
->knotsv
);
344 /* if(nu->trim.first) freeNurblist(&(nu->trim)); */
351 void freeNurblist(ListBase
*lb
)
363 lb
->first
= lb
->last
= 0;
366 Nurb
*duplicateNurb(Nurb
*nu
)
371 newnu
= (Nurb
*)MEM_mallocN(sizeof(Nurb
),"duplicateNurb");
372 if(newnu
==0) return 0;
373 memcpy(newnu
, nu
, sizeof(Nurb
));
377 (BezTriple
*)MEM_mallocN((nu
->pntsu
)* sizeof(BezTriple
),"duplicateNurb2");
378 memcpy(newnu
->bezt
, nu
->bezt
, nu
->pntsu
*sizeof(BezTriple
));
381 len
= nu
->pntsu
*nu
->pntsv
;
383 (BPoint
*)MEM_mallocN((len
)* sizeof(BPoint
),"duplicateNurb3");
384 memcpy(newnu
->bp
, nu
->bp
, len
*sizeof(BPoint
));
386 newnu
->knotsu
=newnu
->knotsv
= 0;
391 newnu
->knotsu
= MEM_mallocN(len
*sizeof(float), "duplicateNurb4");
392 memcpy(newnu
->knotsu
, nu
->knotsu
, sizeof(float)*len
);
395 if(nu
->pntsv
>1 && nu
->knotsv
) {
398 newnu
->knotsv
= MEM_mallocN(len
*sizeof(float), "duplicateNurb5");
399 memcpy(newnu
->knotsv
, nu
->knotsv
, sizeof(float)*len
);
406 void duplicateNurblist(ListBase
*lb1
, ListBase
*lb2
)
414 nun
= duplicateNurb(nu
);
415 BLI_addtail(lb1
, nun
);
421 void test2DNurb(Nurb
*nu
)
427 if( nu
->type
== CU_BEZIER
+CU_2D
) {
431 bezt
->vec
[0][2]= 0.0;
432 bezt
->vec
[1][2]= 0.0;
433 bezt
->vec
[2][2]= 0.0;
437 else if(nu
->type
& CU_2D
) {
438 a
= nu
->pntsu
*nu
->pntsv
;
447 void minmaxNurb(Nurb
*nu
, float *min
, float *max
)
453 if( (nu
->type
& 7)==CU_BEZIER
) {
457 DO_MINMAX(bezt
->vec
[0], min
, max
);
458 DO_MINMAX(bezt
->vec
[1], min
, max
);
459 DO_MINMAX(bezt
->vec
[2], min
, max
);
464 a
= nu
->pntsu
*nu
->pntsv
;
467 DO_MINMAX(bp
->vec
, min
, max
);
474 /* ~~~~~~~~~~~~~~~~~~~~Non Uniform Rational B Spline calculations ~~~~~~~~~~~ */
477 static void calcknots(float *knots
, short aantal
, short order
, short type
)
478 /* knots: number of pnts NOT corrected for cyclic */
479 /* type; 0: uniform, 1: endpoints, 2: bezier */
495 if(a
>=order
&& a
<=aantal
) k
+= 1.0;
502 knots
[a
]= (float)floor(k
);
509 if(a
>=order
&& a
<=aantal
) k
+= (0.5);
510 knots
[a
]= (float)floor(k
);
516 static void makecyclicknots(float *knots
, short pnts
, short order
)
517 /* pnts, order: number of pnts NOT corrected for cyclic */
524 /* do first long rows (order -1), remove identical knots at endpoints */
527 for(a
=1; a
<order2
; a
++) {
528 if(knots
[b
]!= knots
[b
-a
]) break;
530 if(a
==order2
) knots
[pnts
+order
-2]+= 1.0;
534 c
=pnts
+ order
+ order2
;
535 for(a
=pnts
+order2
; a
<c
; a
++) {
536 knots
[a
]= knots
[a
-1]+ (knots
[b
]-knots
[b
-1]);
542 void makeknots(Nurb
*nu
, short uv
, short type
) /* 0: uniform, 1: endpoints, 2: bezier */
544 if( (nu
->type
& 7)==CU_NURBS
) {
546 if(nu
->knotsu
) MEM_freeN(nu
->knotsu
);
548 nu
->knotsu
= MEM_callocN(4+sizeof(float)*KNOTSU(nu
), "makeknots");
549 calcknots(nu
->knotsu
, nu
->pntsu
, nu
->orderu
, type
);
550 if(nu
->flagu
& 1) makecyclicknots(nu
->knotsu
, nu
->pntsu
, nu
->orderu
);
555 if(nu
->knotsv
) MEM_freeN(nu
->knotsv
);
557 nu
->knotsv
= MEM_callocN(4+sizeof(float)*KNOTSV(nu
), "makeknots");
558 calcknots(nu
->knotsv
, nu
->pntsv
, nu
->orderv
, type
);
559 if(nu
->flagv
& 1) makecyclicknots(nu
->knotsv
, nu
->pntsv
, nu
->orderv
);
566 static void basisNurb(float t
, short order
, short pnts
, float *knots
, float *basis
, int *start
, int *end
)
569 int i
, i1
= 0, i2
= 0 ,j
, orderpluspnts
, opp2
, o2
;
571 orderpluspnts
= order
+pnts
;
572 opp2
= orderpluspnts
-1;
574 /* this is for float inaccuracy */
575 if(t
< knots
[0]) t
= knots
[0];
576 else if(t
> knots
[opp2
]) t
= knots
[opp2
];
578 /* this part is order '1' */
580 for(i
=0;i
<opp2
;i
++) {
581 if(knots
[i
]!=knots
[i
+1] && t
>= knots
[i
] && t
<=knots
[i
+1]) {
597 /* this is order 2,3,... */
598 for(j
=2; j
<=order
; j
++) {
600 if(i2
+j
>= orderpluspnts
) i2
= opp2
-j
;
602 for(i
= i1
; i
<=i2
; i
++) {
604 d
= ((t
-knots
[i
])*basis
[i
]) / (knots
[i
+j
-1]-knots
[i
]);
609 e
= ((knots
[i
+j
]-t
)*basis
[i
+1]) / (knots
[i
+j
]-knots
[i
+1]);
620 for(i
=i1
; i
<=i2
; i
++) {
623 if(*start
==1000) *start
= i
;
629 void makeNurbfaces(Nurb
*nu
, float *data
, int rowstride
)
630 /* data has to be 3*4*resolu*resolv in size, and zero-ed */
633 float *basisu
, *basis
, *basisv
, *sum
, *fp
, *in
;
634 float u
, v
, ustart
, uend
, ustep
, vstart
, vend
, vstep
, sumdiv
;
635 int i
, j
, iofs
, jofs
, cycl
, len
, resolu
, resolv
;
636 int istart
, iend
, jsta
, jen
, *jstart
, *jend
, ratcomp
;
638 if(nu
->knotsu
==0 || nu
->knotsv
==0) return;
639 if(nu
->orderu
>nu
->pntsu
) return;
640 if(nu
->orderv
>nu
->pntsv
) return;
643 /* allocate and initialize */
644 len
= nu
->pntsu
*nu
->pntsv
;
649 sum
= (float *)MEM_callocN(sizeof(float)*len
, "makeNurbfaces1");
660 i
= nu
->pntsu
*nu
->pntsv
;
663 if(bp
->vec
[3]!=1.0) {
671 ustart
= fp
[nu
->orderu
-1];
672 if(nu
->flagu
& 1) uend
= fp
[nu
->pntsu
+nu
->orderu
-1];
673 else uend
= fp
[nu
->pntsu
];
674 ustep
= (uend
-ustart
)/(resolu
-1+(nu
->flagu
& 1));
675 basisu
= (float *)MEM_mallocN(sizeof(float)*KNOTSU(nu
), "makeNurbfaces3");
678 vstart
= fp
[nu
->orderv
-1];
680 if(nu
->flagv
& 1) vend
= fp
[nu
->pntsv
+nu
->orderv
-1];
681 else vend
= fp
[nu
->pntsv
];
682 vstep
= (vend
-vstart
)/(resolv
-1+(nu
->flagv
& 1));
684 basisv
= (float *)MEM_mallocN(sizeof(float)*len
*resolv
, "makeNurbfaces3");
685 jstart
= (int *)MEM_mallocN(sizeof(float)*resolv
, "makeNurbfaces4");
686 jend
= (int *)MEM_mallocN(sizeof(float)*resolv
, "makeNurbfaces5");
688 /* precalculation of basisv and jstart,jend */
689 if(nu
->flagv
& 1) cycl
= nu
->orderv
-1;
694 basisNurb(v
, nu
->orderv
, (short)(nu
->pntsv
+cycl
), nu
->knotsv
, basis
, jstart
+resolv
, jend
+resolv
);
699 if(nu
->flagu
& 1) cycl
= nu
->orderu
-1;
705 basisNurb(u
, nu
->orderu
, (short)(nu
->pntsu
+cycl
), nu
->knotsu
, basisu
, &istart
, &iend
);
711 jsta
= jstart
[resolv
];
718 for(j
= jsta
; j
<=jen
; j
++) {
720 if(j
>=nu
->pntsv
) jofs
= (j
- nu
->pntsv
);
722 bp
= nu
->bp
+ nu
->pntsu
*jofs
+istart
-1;
724 for(i
= istart
; i
<=iend
; i
++, fp
++) {
728 bp
= nu
->bp
+ nu
->pntsu
*jofs
+iofs
;
733 *fp
= basisu
[i
]*basis
[j
]*bp
->vec
[3];
736 else *fp
= basisu
[i
]*basis
[j
];
742 for(j
= jsta
; j
<=jen
; j
++) {
743 for(i
= istart
; i
<=iend
; i
++, fp
++) {
749 /* one! (1.0) real point now */
751 for(j
= jsta
; j
<=jen
; j
++) {
753 if(j
>=nu
->pntsv
) jofs
= (j
- nu
->pntsv
);
755 bp
= nu
->bp
+ nu
->pntsu
*jofs
+istart
-1;
757 for(i
= istart
; i
<=iend
; i
++, fp
++) {
761 bp
= nu
->bp
+ nu
->pntsu
*jofs
+iofs
;
766 in
[0]+= (*fp
) * bp
->vec
[0];
767 in
[1]+= (*fp
) * bp
->vec
[1];
768 in
[2]+= (*fp
) * bp
->vec
[2];
777 if (rowstride
!=0) in
= (float*) (((unsigned char*) in
) + (rowstride
- 3*nu
->resolv
*sizeof(*in
)));
788 void makeNurbcurve(Nurb
*nu
, float *data
, int resolu
, int dim
)
789 /* data has to be dim*4*pntsu*resolu in size and zero-ed */
792 float u
, ustart
, uend
, ustep
, sumdiv
;
793 float *basisu
, *sum
, *fp
, *in
;
794 int i
, len
, istart
, iend
, cycl
;
796 if(nu
->knotsu
==0) return;
797 if(nu
->orderu
>nu
->pntsu
) return;
800 /* allocate and initialize */
803 sum
= (float *)MEM_callocN(sizeof(float)*len
, "makeNurbcurve1");
812 ustart
= fp
[nu
->orderu
-1];
813 if(nu
->flagu
& 1) uend
= fp
[nu
->pntsu
+nu
->orderu
-1];
814 else uend
= fp
[nu
->pntsu
];
815 ustep
= (uend
-ustart
)/(resolu
-1+(nu
->flagu
& 1));
816 basisu
= (float *)MEM_mallocN(sizeof(float)*KNOTSU(nu
), "makeNurbcurve3");
818 if(nu
->flagu
& 1) cycl
= nu
->orderu
-1;
825 basisNurb(u
, nu
->orderu
, (short)(nu
->pntsu
+cycl
), nu
->knotsu
, basisu
, &istart
, &iend
);
829 bp
= nu
->bp
+ istart
-1;
830 for(i
= istart
; i
<=iend
; i
++, fp
++) {
832 if(i
>=nu
->pntsu
) bp
= nu
->bp
+(i
- nu
->pntsu
);
835 *fp
= basisu
[i
]*bp
->vec
[3];
838 if(sumdiv
!=0.0) if(sumdiv
<0.999 || sumdiv
>1.001) {
839 /* is normalizing needed? */
841 for(i
= istart
; i
<=iend
; i
++, fp
++) {
846 /* one! (1.0) real point */
848 bp
= nu
->bp
+ istart
-1;
849 for(i
= istart
; i
<=iend
; i
++, fp
++) {
851 if(i
>=nu
->pntsu
) bp
= nu
->bp
+(i
- nu
->pntsu
);
856 in
[0]+= (*fp
) * bp
->vec
[0];
857 in
[1]+= (*fp
) * bp
->vec
[1];
859 in
[2]+= (*fp
) * bp
->vec
[2];
860 if(dim
==4) in
[3]+= (*fp
) * bp
->alfa
;
875 /* forward differencing method for bezier curve */
876 void forward_diff_bezier(float q0
, float q1
, float q2
, float q3
, float *p
, int it
, int stride
)
878 float rt0
,rt1
,rt2
,rt3
,f
;
885 rt2
= 3.0f
*(q0
-2.0f
*q1
+q2
)/f
;
887 rt3
= (q3
-q0
+3.0f
*(q1
-q2
))/f
;
894 for(a
=0; a
<=it
; a
++) {
903 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
905 float *make_orco_surf(Object
*ob
)
913 /* first calculate the size of the datablock */
916 /* as we want to avoid the seam in a cyclic nurbs
917 texture wrapping, reserve extra orco data space to save these extra needed
918 vertex based UV coordinates for the meridian vertices.
919 Vertices on the 0/2pi boundary are not duplicated inside the displist but later in
920 the renderface/vert construction.
922 See also convertblender.c: init_render_surf()
927 if (nu
->flagu
& CU_CYCLIC
) sizeu
++;
928 if (nu
->flagv
& CU_CYCLIC
) sizev
++;
929 if(nu
->pntsv
>1) tot
+= sizeu
* sizev
;
933 /* makeNurbfaces wants zeros */
934 data
= orco
= MEM_callocN(3*sizeof(float)*tot
, "make_orco");
941 if (nu
->flagu
& CU_CYCLIC
) sizeu
++;
942 if (nu
->flagv
& CU_CYCLIC
) sizev
++;
944 if(cu
->flag
& CU_UV_ORCO
) {
945 for(b
=0; b
< sizeu
; b
++) {
946 for(a
=0; a
< sizev
; a
++) {
948 if(sizev
<2) data
[0]= 0.0f
;
949 else data
[0]= -1.0f
+ 2.0f
*((float)a
)/(sizev
- 1);
951 if(sizeu
<2) data
[1]= 0.0f
;
952 else data
[1]= -1.0f
+ 2.0f
*((float)b
)/(sizeu
- 1);
961 float *_tdata
= MEM_callocN(nu
->resolu
*nu
->resolv
*3*sizeof(float), "temp data");
962 float *tdata
= _tdata
;
964 makeNurbfaces(nu
, tdata
, 0);
966 for(b
=0; b
<sizeu
; b
++) {
968 if (b
==sizeu
-1 && (nu
->flagu
& CU_CYCLIC
))
971 for(a
=0; a
<sizev
; a
++) {
973 if (a
==sizev
-1 && (nu
->flagv
& CU_CYCLIC
))
976 tdata
= _tdata
+ 3 * (use_b
* nu
->resolv
+ use_a
);
978 data
[0]= (tdata
[0]-cu
->loc
[0])/cu
->size
[0];
979 data
[1]= (tdata
[1]-cu
->loc
[1])/cu
->size
[1];
980 data
[2]= (tdata
[2]-cu
->loc
[2])/cu
->size
[2];
995 /* NOTE: This routine is tied to the order of vertex
996 * built by displist and as passed to the renderer.
998 float *make_orco_curve(Object
*ob
)
1000 Curve
*cu
= ob
->data
;
1006 if (!(cu
->flag
&CU_UV_ORCO
) && cu
->key
&& cu
->key
->refkey
) {
1007 cp_cu_key(cu
, cu
->key
->refkey
, 0, count_curveverts(&cu
->nurb
));
1008 makeDispListCurveTypes(ob
, 1);
1012 /* Assumes displist has been built */
1015 for (dl
=cu
->disp
.first
; dl
; dl
=dl
->next
) {
1016 if (dl
->type
==DL_INDEX3
) {
1018 } else if (dl
->type
==DL_SURF
) {
1019 /* convertblender.c uses the Surface code for creating renderfaces when cyclic U only (closed circle beveling) */
1020 if (dl
->flag
& DL_CYCL_U
) {
1021 if (dl
->flag
& DL_CYCL_V
)
1022 numVerts
+= (dl
->parts
+1)*(dl
->nr
+1);
1024 numVerts
+= dl
->parts
*(dl
->nr
+1);
1027 numVerts
+= dl
->parts
*dl
->nr
;
1031 fp
= orco
= MEM_mallocN(3*sizeof(float)*numVerts
, "cu_orco");
1032 for (dl
=cu
->disp
.first
; dl
; dl
=dl
->next
) {
1033 if (dl
->type
==DL_INDEX3
) {
1034 for (u
=0; u
<dl
->nr
; u
++, fp
+=3) {
1035 if (cu
->flag
& CU_UV_ORCO
) {
1036 fp
[0]= 2.0f
*u
/(dl
->nr
-1) - 1.0f
;
1040 VECCOPY(fp
, &dl
->verts
[u
*3]);
1042 fp
[0]= (fp
[0]-cu
->loc
[0])/cu
->size
[0];
1043 fp
[1]= (fp
[1]-cu
->loc
[1])/cu
->size
[1];
1044 fp
[2]= (fp
[2]-cu
->loc
[2])/cu
->size
[2];
1047 } else if (dl
->type
==DL_SURF
) {
1048 int sizeu
= dl
->nr
, sizev
= dl
->parts
;
1050 /* exception as handled in convertblender.c too */
1051 if (dl
->flag
& DL_CYCL_U
) {
1053 if (dl
->flag
& DL_CYCL_V
)
1057 for (u
=0; u
<sizev
; u
++) {
1058 for (v
=0; v
<sizeu
; v
++,fp
+=3) {
1059 if (cu
->flag
& CU_UV_ORCO
) {
1060 fp
[0]= 2.0f
*u
/(dl
->parts
-1) - 1.0f
;
1061 fp
[1]= 2.0f
*v
/(dl
->nr
-1) - 1.0f
;
1064 int realv
= v
% dl
->nr
;
1066 VECCOPY(fp
, &dl
->verts
[(dl
->nr
*u
+ realv
)*3]);
1068 fp
[0]= (fp
[0]-cu
->loc
[0])/cu
->size
[0];
1069 fp
[1]= (fp
[1]-cu
->loc
[1])/cu
->size
[1];
1070 fp
[2]= (fp
[2]-cu
->loc
[2])/cu
->size
[2];
1078 makeDispListCurveTypes(ob
, 0);
1085 /* ***************** BEVEL ****************** */
1087 void makebevelcurve(Object
*ob
, ListBase
*disp
)
1089 DispList
*dl
, *dlnew
;
1091 float *fp
, facx
, facy
, angle
, dangle
;
1095 disp
->first
= disp
->last
= NULL
;
1097 /* if a font object is being edited, then do nothing */
1098 if( ob
== G
.obedit
&& ob
->type
== OB_FONT
) return;
1100 if(cu
->bevobj
&& cu
->bevobj
!=ob
) {
1101 if(cu
->bevobj
->type
==OB_CURVE
) {
1102 bevcu
= cu
->bevobj
->data
;
1103 if(bevcu
->ext1
==0.0 && bevcu
->ext2
==0.0) {
1104 facx
= cu
->bevobj
->size
[0];
1105 facy
= cu
->bevobj
->size
[1];
1107 dl
= bevcu
->disp
.first
;
1109 makeDispListCurveTypes(cu
->bevobj
, 0);
1110 dl
= bevcu
->disp
.first
;
1113 if ELEM(dl
->type
, DL_POLY
, DL_SEGM
) {
1114 dlnew
= MEM_mallocN(sizeof(DispList
), "makebevelcurve1");
1116 dlnew
->verts
= MEM_mallocN(3*sizeof(float)*dl
->parts
*dl
->nr
, "makebevelcurve1");
1117 memcpy(dlnew
->verts
, dl
->verts
, 3*sizeof(float)*dl
->parts
*dl
->nr
);
1119 if(dlnew
->type
==DL_SEGM
) dlnew
->flag
|= (DL_FRONT_CURVE
|DL_BACK_CURVE
);
1121 BLI_addtail(disp
, dlnew
);
1123 nr
= dlnew
->parts
*dlnew
->nr
;
1136 else if(cu
->ext1
==0.0 && cu
->ext2
==0.0) {
1139 else if(cu
->ext2
==0.0) {
1140 dl
= MEM_callocN(sizeof(DispList
), "makebevelcurve2");
1141 dl
->verts
= MEM_mallocN(2*3*sizeof(float), "makebevelcurve2");
1142 BLI_addtail(disp
, dl
);
1145 dl
->flag
= DL_FRONT_CURVE
|DL_BACK_CURVE
;
1154 else if( (cu
->flag
& (CU_FRONT
|CU_BACK
))==0 && cu
->ext1
==0.0f
) { // we make a full round bevel in that case
1156 nr
= 4+ 2*cu
->bevresol
;
1158 dl
= MEM_callocN(sizeof(DispList
), "makebevelcurve p1");
1159 dl
->verts
= MEM_mallocN(nr
*3*sizeof(float), "makebevelcurve p1");
1160 BLI_addtail(disp
, dl
);
1163 dl
->flag
= DL_BACK_CURVE
;
1168 dangle
= (2.0f
*M_PI
/(nr
));
1169 angle
= -(nr
-1)*dangle
;
1171 for(a
=0; a
<nr
; a
++) {
1173 fp
[1]= (float)(cos(angle
)*(cu
->ext2
));
1174 fp
[2]= (float)(sin(angle
)*(cu
->ext2
)) - cu
->ext1
;
1182 /* bevel now in three parts, for proper vertex normals */
1184 dnr
= nr
= 2+ cu
->bevresol
;
1185 if( (cu
->flag
& (CU_FRONT
|CU_BACK
))==0)
1186 nr
= 3+ 2*cu
->bevresol
;
1188 dl
= MEM_callocN(sizeof(DispList
), "makebevelcurve p1");
1189 dl
->verts
= MEM_mallocN(nr
*3*sizeof(float), "makebevelcurve p1");
1190 BLI_addtail(disp
, dl
);
1193 dl
->flag
= DL_BACK_CURVE
;
1198 dangle
= (0.5*M_PI
/(dnr
-1));
1199 angle
= -(nr
-1)*dangle
;
1201 for(a
=0; a
<nr
; a
++) {
1203 fp
[1]= (float)(cos(angle
)*(cu
->ext2
));
1204 fp
[2]= (float)(sin(angle
)*(cu
->ext2
)) - cu
->ext1
;
1209 /* part 2, sidefaces */
1213 dl
= MEM_callocN(sizeof(DispList
), "makebevelcurve p2");
1214 dl
->verts
= MEM_callocN(nr
*3*sizeof(float), "makebevelcurve p2");
1215 BLI_addtail(disp
, dl
);
1226 if( (cu
->flag
& (CU_FRONT
|CU_BACK
))==0) {
1227 dl
= MEM_dupallocN(dl
);
1228 dl
->verts
= MEM_dupallocN(dl
->verts
);
1229 BLI_addtail(disp
, dl
);
1240 dnr
= nr
= 2+ cu
->bevresol
;
1241 if( (cu
->flag
& (CU_FRONT
|CU_BACK
))==0)
1242 nr
= 3+ 2*cu
->bevresol
;
1244 dl
= MEM_callocN(sizeof(DispList
), "makebevelcurve p3");
1245 dl
->verts
= MEM_mallocN(nr
*3*sizeof(float), "makebevelcurve p3");
1246 BLI_addtail(disp
, dl
);
1248 dl
->flag
= DL_FRONT_CURVE
;
1255 dangle
= (0.5*M_PI
/(dnr
-1));
1257 for(a
=0; a
<nr
; a
++) {
1259 fp
[1]= (float)(cos(angle
)*(cu
->ext2
));
1260 fp
[2]= (float)(sin(angle
)*(cu
->ext2
)) + cu
->ext1
;
1267 int cu_isectLL(float *v1
, float *v2
, float *v3
, float *v4
, short cox
, short coy
, float *labda
, float *mu
, float *vec
)
1271 0: no intersection of segments
1272 1: exact intersection of segments
1273 2: cross-intersection of segments
1277 deler
= (v1
[cox
]-v2
[cox
])*(v3
[coy
]-v4
[coy
])-(v3
[cox
]-v4
[cox
])*(v1
[coy
]-v2
[coy
]);
1278 if(deler
==0.0) return -1;
1280 *labda
= (v1
[coy
]-v3
[coy
])*(v3
[cox
]-v4
[cox
])-(v1
[cox
]-v3
[cox
])*(v3
[coy
]-v4
[coy
]);
1281 *labda
= -(*labda
/deler
);
1283 deler
= v3
[coy
]-v4
[coy
];
1285 deler
=v3
[cox
]-v4
[cox
];
1286 *mu
= -(*labda
*(v2
[cox
]-v1
[cox
])+v1
[cox
]-v3
[cox
])/deler
;
1288 *mu
= -(*labda
*(v2
[coy
]-v1
[coy
])+v1
[coy
]-v3
[coy
])/deler
;
1290 vec
[cox
]= *labda
*(v2
[cox
]-v1
[cox
])+v1
[cox
];
1291 vec
[coy
]= *labda
*(v2
[coy
]-v1
[coy
])+v1
[coy
];
1293 if(*labda
>=0.0 && *labda
<=1.0 && *mu
>=0.0 && *mu
<=1.0) {
1294 if(*labda
==0.0 || *labda
==1.0 || *mu
==0.0 || *mu
==1.0) return 1;
1301 static short bevelinside(BevList
*bl1
,BevList
*bl2
)
1303 /* is bl2 INSIDE bl1 ? with left-right method and "labda's" */
1304 /* returns '1' if correct hole */
1305 BevPoint
*bevp
, *prevbevp
;
1306 float min
,max
,vec
[3],hvec1
[3],hvec2
[3],lab
,mu
;
1307 int nr
, links
=0,rechts
=0,mode
;
1309 /* take first vertex of possible hole */
1311 bevp
= (BevPoint
*)(bl2
+1);
1315 VECCOPY(hvec2
,hvec1
);
1318 /* test it with all edges of potential surounding poly */
1319 /* count number of transitions left-right */
1321 bevp
= (BevPoint
*)(bl1
+1);
1323 prevbevp
= bevp
+(nr
-1);
1333 if(min
<=hvec1
[1] && max
>=hvec1
[1]) {
1334 /* there's a transition, calc intersection point */
1335 mode
= cu_isectLL(&(prevbevp
->x
),&(bevp
->x
),hvec1
,hvec2
,0,1,&lab
,&mu
,vec
);
1336 /* if lab==0.0 or lab==1.0 then the edge intersects exactly a transition
1337 only allow for one situation: we choose lab= 1.0
1339 if(mode
>=0 && lab
!=0.0) {
1340 if(vec
[0]<hvec1
[0]) links
++;
1349 if( (links
& 1) && (rechts
& 1) ) return 1;
1360 static int vergxcobev(const void *a1
, const void *a2
)
1362 const struct bevelsort
*x1
=a1
,*x2
=a2
;
1364 if( x1
->left
> x2
->left
) return 1;
1365 else if( x1
->left
< x2
->left
) return -1;
1369 /* this function cannot be replaced with atan2, but why? */
1371 static void calc_bevel_sin_cos(float x1
, float y1
, float x2
, float y2
, float *sina
, float *cosa
)
1373 float t01
, t02
, x3
, y3
;
1375 t01
= (float)sqrt(x1
*x1
+y1
*y1
);
1376 t02
= (float)sqrt(x2
*x2
+y2
*y2
);
1377 if(t01
==0.0) t01
= 1.0;
1378 if(t02
==0.0) t02
= 1.0;
1386 if(fabs(t02
)>=1.0) t02
= .5*M_PI
;
1387 else t02
= (saacos(t02
))/2.0f
;
1389 t02
= (float)sin(t02
);
1390 if(t02
==0.0) t02
= 1.0;
1394 if(x3
==0 && y3
==0) {
1398 t01
= (float)sqrt(x3
*x3
+y3
*y3
);
1408 static void alfa_bezpart(BezTriple
*prevbezt
, BezTriple
*bezt
, Nurb
*nu
, float *data_a
, int resolu
)
1410 BezTriple
*pprev
, *next
, *last
;
1411 float fac
, dfac
, t
[4];
1414 last
= nu
->bezt
+(nu
->pntsu
-1);
1416 /* returns a point */
1417 if(prevbezt
==nu
->bezt
) {
1418 if(nu
->flagu
& 1) pprev
= last
;
1419 else pprev
= prevbezt
;
1421 else pprev
= prevbezt
-1;
1425 if(nu
->flagu
& 1) next
= nu
->bezt
;
1431 dfac
= 1.0f
/(float)resolu
;
1433 for(a
=0; a
<resolu
; a
++, fac
+= dfac
) {
1435 set_four_ipo(fac
, t
, KEY_LINEAR
);
1437 data_a
[a
]= t
[0]*pprev
->alfa
+ t
[1]*prevbezt
->alfa
+ t
[2]*bezt
->alfa
+ t
[3]*next
->alfa
;
1441 void makeBevelList(Object
*ob
)
1444 - convert all curves to polys, with indication of resol and flags for double-vertices
1445 - possibly; do a smart vertice removal (in case Nurb)
1446 - separate in individual blicks with BoundBox
1447 - AutoHole detection
1451 BezTriple
*bezt
, *prevbezt
;
1453 BevList
*bl
, *blnew
, *blnext
;
1454 BevPoint
*bevp
, *bevp2
, *bevp1
= NULL
, *bevp0
;
1455 float *data
, *data_a
, *v1
, *v2
, min
, inp
, x1
, x2
, y1
, y2
, vec
[3];
1456 struct bevelsort
*sortdata
, *sd
, *sd1
;
1457 int a
, b
, len
, nr
, poly
, resolu
;
1459 /* this function needs an object, because of tflag and upflag */
1462 /* STEP 1: MAKE POLYS */
1464 BLI_freelistN(&(cu
->bev
));
1465 if(ob
==G
.obedit
&& ob
->type
!=OB_FONT
) nu
= editNurb
.first
;
1466 else nu
= cu
->nurb
.first
;
1470 if(G
.rendering
&& cu
->resolu_ren
!=0)
1471 resolu
= cu
->resolu_ren
;
1475 if((nu
->type
& 7)==CU_POLY
) {
1478 bl
= MEM_callocN(sizeof(BevList
)+len
*sizeof(BevPoint
), "makeBevelList");
1479 BLI_addtail(&(cu
->bev
), bl
);
1481 if(nu
->flagu
& 1) bl
->poly
= 0;
1485 bevp
= (BevPoint
*)(bl
+1);
1489 bevp
->x
= bp
->vec
[0];
1490 bevp
->y
= bp
->vec
[1];
1491 bevp
->z
= bp
->vec
[2];
1492 bevp
->alfa
= bp
->alfa
;
1498 else if((nu
->type
& 7)==CU_BEZIER
) {
1500 len
= resolu
*(nu
->pntsu
+ (nu
->flagu
& 1) -1)+1; /* in case last point is not cyclic */
1501 bl
= MEM_callocN(sizeof(BevList
)+len
*sizeof(BevPoint
), "makeBevelList");
1502 BLI_addtail(&(cu
->bev
), bl
);
1504 if(nu
->flagu
& 1) bl
->poly
= 0;
1506 bevp
= (BevPoint
*)(bl
+1);
1512 prevbezt
= nu
->bezt
+(nu
->pntsu
-1);
1519 data
= MEM_mallocN(3*sizeof(float)*(resolu
+1), "makeBevelList2");
1520 data_a
= MEM_callocN(sizeof(float)*(resolu
+1), "data_a");
1523 if(prevbezt
->h2
==HD_VECT
&& bezt
->h1
==HD_VECT
) {
1525 bevp
->x
= prevbezt
->vec
[1][0];
1526 bevp
->y
= prevbezt
->vec
[1][1];
1527 bevp
->z
= prevbezt
->vec
[1][2];
1528 bevp
->alfa
= prevbezt
->alfa
;
1536 v1
= prevbezt
->vec
[1];
1539 /* always do all three, to prevent data hanging around */
1540 forward_diff_bezier(v1
[0], v1
[3], v2
[0], v2
[3], data
, resolu
, 3);
1541 forward_diff_bezier(v1
[1], v1
[4], v2
[1], v2
[4], data
+1, resolu
, 3);
1542 forward_diff_bezier(v1
[2], v1
[5], v2
[2], v2
[5], data
+2, resolu
, 3);
1544 if((nu
->type
& CU_2D
)==0) {
1545 if(cu
->flag
& CU_3D
) {
1546 alfa_bezpart(prevbezt
, bezt
, nu
, data_a
, resolu
);
1551 /* indicate with handlecodes double points */
1552 if(prevbezt
->h1
==prevbezt
->h2
) {
1553 if(prevbezt
->h1
==0 || prevbezt
->h1
==HD_VECT
) bevp
->f1
= 1;
1556 if(prevbezt
->h1
==0 || prevbezt
->h1
==HD_VECT
) bevp
->f1
= 1;
1557 else if(prevbezt
->h2
==0 || prevbezt
->h2
==HD_VECT
) bevp
->f1
= 1;
1583 if((nu
->flagu
& 1)==0) { /* not cyclic: endpoint */
1584 bevp
->x
= prevbezt
->vec
[1][0];
1585 bevp
->y
= prevbezt
->vec
[1][1];
1586 bevp
->z
= prevbezt
->vec
[1][2];
1587 bevp
->alfa
= prevbezt
->alfa
;
1592 else if((nu
->type
& 7)==CU_NURBS
) {
1594 len
= resolu
*nu
->pntsu
;
1595 bl
= MEM_mallocN(sizeof(BevList
)+len
*sizeof(BevPoint
), "makeBevelList3");
1596 BLI_addtail(&(cu
->bev
), bl
);
1599 if(nu
->flagu
& 1) bl
->poly
= 0;
1601 bevp
= (BevPoint
*)(bl
+1);
1603 data
= MEM_callocN(4*sizeof(float)*len
, "makeBevelList4"); /* has to be zero-ed */
1604 makeNurbcurve(nu
, data
, resolu
, 4);
1613 bevp
->f1
= bevp
->f2
= 0;
1624 /* STEP 2: DOUBLE POINTS AND AUTOMATIC RESOLUTION, REDUCE DATABLOCKS */
1628 bevp1
= (BevPoint
*)(bl
+1);
1629 bevp0
= bevp1
+(nr
-1);
1632 if( fabs(bevp0
->x
-bevp1
->x
)<0.00001 ) {
1633 if( fabs(bevp0
->y
-bevp1
->y
)<0.00001 ) {
1634 if( fabs(bevp0
->z
-bevp1
->z
)<0.00001 ) {
1649 nr
= bl
->nr
- bl
->flag
+1; /* +1 because vectorbezier sets flag too */
1650 blnew
= MEM_mallocN(sizeof(BevList
)+nr
*sizeof(BevPoint
), "makeBevelList");
1651 memcpy(blnew
, bl
, sizeof(BevList
));
1653 BLI_remlink(&(cu
->bev
), bl
);
1654 BLI_insertlinkbefore(&(cu
->bev
),blnext
,blnew
); /* to make sure bevlijst is tuned with nurblist */
1655 bevp0
= (BevPoint
*)(bl
+1);
1656 bevp1
= (BevPoint
*)(blnew
+1);
1660 memcpy(bevp1
, bevp0
, sizeof(BevPoint
));
1672 /* STEP 3: COUNT POLYS TELLEN AND AUTOHOLE */
1679 bl
->gat
= 0; /* 'gat' is dutch for hole */
1685 /* find extreme left points, also test (turning) direction */
1687 sd
= sortdata
= MEM_mallocN(sizeof(struct bevelsort
)*poly
, "makeBevelList5");
1693 bevp
= (BevPoint
*)(bl
+1);
1705 bevp
= (BevPoint
*)(bl
+1);
1706 if(bevp1
== bevp
) bevp0
= bevp
+ (bl
->nr
-1);
1707 else bevp0
= bevp1
-1;
1708 bevp
= bevp
+ (bl
->nr
-1);
1709 if(bevp1
== bevp
) bevp2
= (BevPoint
*)(bl
+1);
1710 else bevp2
= bevp1
+1;
1712 inp
= (bevp1
->x
- bevp0
->x
)*(bevp0
->y
- bevp2
->y
)
1713 +(bevp0
->y
- bevp1
->y
)*(bevp0
->x
- bevp2
->x
);
1715 if(inp
>0.0) sd
->dir
= 1;
1723 qsort(sortdata
,poly
,sizeof(struct bevelsort
), vergxcobev
);
1726 for(a
=1; a
<poly
; a
++, sd
++) {
1727 bl
= sd
->bl
; /* is bl a hole? */
1728 sd1
= sortdata
+ (a
-1);
1729 for(b
=a
-1; b
>=0; b
--, sd1
--) { /* all polys to the left */
1730 if(bevelinside(sd1
->bl
, bl
)) {
1731 bl
->gat
= 1- sd1
->bl
->gat
;
1737 /* turning direction */
1738 if((cu
->flag
& CU_3D
)==0) {
1740 for(a
=0; a
<poly
; a
++, sd
++) {
1741 if(sd
->bl
->gat
==sd
->dir
) {
1743 bevp1
= (BevPoint
*)(bl
+1);
1744 bevp2
= bevp1
+ (bl
->nr
-1);
1747 SWAP(BevPoint
, *bevp1
, *bevp2
);
1754 MEM_freeN(sortdata
);
1757 /* STEP 4: COSINES */
1761 if(bl
->nr
==2) { /* 2 pnt, treat separate */
1762 bevp2
= (BevPoint
*)(bl
+1);
1765 x1
= bevp1
->x
- bevp2
->x
;
1766 y1
= bevp1
->y
- bevp2
->y
;
1768 calc_bevel_sin_cos(x1
, y1
, -x1
, -y1
, &(bevp1
->sina
), &(bevp1
->cosa
));
1769 bevp2
->sina
= bevp1
->sina
;
1770 bevp2
->cosa
= bevp1
->cosa
;
1772 if(cu
->flag
& CU_3D
) { /* 3D */
1775 vec
[0]= bevp1
->x
- bevp2
->x
;
1776 vec
[1]= bevp1
->y
- bevp2
->y
;
1777 vec
[2]= bevp1
->z
- bevp2
->z
;
1779 quat
= vectoquat(vec
, 5, 1);
1782 q
[0]= (float)cos(0.5*bevp1
->alfa
);
1783 x1
= (float)sin(0.5*bevp1
->alfa
);
1787 QuatMul(quat
, q
, quat
);
1789 QuatToMat3(quat
, bevp1
->mat
);
1790 Mat3CpyMat3(bevp2
->mat
, bevp1
->mat
);
1795 bevp2
= (BevPoint
*)(bl
+1);
1796 bevp1
= bevp2
+(bl
->nr
-1);
1804 if(cu
->flag
& CU_3D
) { /* 3D */
1807 vec
[0]= bevp2
->x
- bevp0
->x
;
1808 vec
[1]= bevp2
->y
- bevp0
->y
;
1809 vec
[2]= bevp2
->z
- bevp0
->z
;
1813 quat
= vectoquat(vec
, 5, 1);
1815 q
[0]= (float)cos(0.5*bevp1
->alfa
);
1816 x1
= (float)sin(0.5*bevp1
->alfa
);
1820 QuatMul(quat
, q
, quat
);
1822 QuatToMat3(quat
, bevp1
->mat
);
1825 x1
= bevp1
->x
- bevp0
->x
;
1826 x2
= bevp1
->x
- bevp2
->x
;
1827 y1
= bevp1
->y
- bevp0
->y
;
1828 y2
= bevp1
->y
- bevp2
->y
;
1830 calc_bevel_sin_cos(x1
, y1
, x2
, y2
, &(bevp1
->sina
), &(bevp1
->cosa
));
1837 /* correct non-cyclic cases */
1840 bevp
= (BevPoint
*)(bl
+1);
1842 bevp
->sina
= bevp1
->sina
;
1843 bevp
->cosa
= bevp1
->cosa
;
1844 Mat3CpyMat3(bevp
->mat
, bevp1
->mat
);
1845 bevp
= (BevPoint
*)(bl
+1);
1848 bevp
->sina
= bevp1
->sina
;
1849 bevp
->cosa
= bevp1
->cosa
;
1850 Mat3CpyMat3(bevp
->mat
, bevp1
->mat
);
1858 /* calculates a bevel width (radius) for a particular subdivided curve part,
1859 * based on the radius value of the surrounding CVs */
1860 float calc_curve_subdiv_radius(Curve
*cu
, Nurb
*nu
, int cursubdiv
)
1862 BezTriple
*bezt
, *beztfirst
, *beztlast
, *beztnext
, *beztprev
;
1863 BPoint
*bp
, *bpfirst
, *bplast
;
1865 float prevrad
=0.0, nextrad
=0.0, rad
=0.0, ratio
=0.0;
1866 int vectseg
=0, subdivs
=0;
1868 if((nu
==NULL
) || (nu
->pntsu
<=1)) return 1.0;
1872 if(G
.rendering
&& cu
->resolu_ren
!=0) resolu
= cu
->resolu_ren
;
1873 else resolu
= nu
->resolu
;
1875 if(((nu
->type
& 7)==CU_BEZIER
) && (bezt
!= NULL
)) {
1876 beztfirst
= nu
->bezt
;
1877 beztlast
= nu
->bezt
+ (nu
->pntsu
- 1);
1879 /* loop through the CVs to end up with a pointer to the CV before the subdiv in question, and a ratio
1880 * of how far that subdiv is between this CV and the next */
1881 while(bezt
<=beztlast
) {
1886 if (subdivs
==cursubdiv
) {
1891 /* check to see if we're looking at a vector segment (no subdivisions) */
1892 if (nu
->flagu
& CU_CYCLIC
) {
1893 if (bezt
== beztfirst
) {
1894 if ((beztlast
->h2
==HD_VECT
) && (bezt
->h1
==HD_VECT
)) vectseg
= 1;
1896 if ((beztprev
->h2
==HD_VECT
) && (bezt
->h1
==HD_VECT
)) vectseg
= 1;
1898 } else if ((bezt
->h2
==HD_VECT
) && (beztnext
->h1
==HD_VECT
)) vectseg
= 1;
1902 /* if it's NOT a vector segment, check to see if the subdiv falls within the segment */
1905 if (cursubdiv
< subdivs
) {
1906 ratio
= 1.0 - ((subdivs
- cursubdiv
)/(float)resolu
);
1910 /* must be a vector segment.. loop again! */
1917 /* Now we have a nice bezt pointer to the CV that we want. But cyclic messes it up, so must correct for that..
1918 * (cyclic goes last-> first -> first+1 -> first+2 -> ...) */
1919 if (nu
->flagu
& CU_CYCLIC
) {
1920 if (bezt
== beztfirst
) bezt
= beztlast
;
1924 /* find the radii at the bounding CVs and interpolate between them based on ratio */
1925 rad
= prevrad
= bezt
->radius
;
1927 if ((bezt
== beztlast
) && (nu
->flagu
& CU_CYCLIC
)) { /* loop around */
1929 } else if (bezt
!= beztlast
) {
1932 nextrad
= bezt
->radius
;
1935 else if( ( ((nu
->type
& 7)==CU_NURBS
) || ((nu
->type
& 7)==CU_POLY
)) && (bp
!= NULL
)) {
1936 /* follows similar algo as for bezt above */
1938 bplast
= nu
->bp
+ (nu
->pntsu
- 1);
1940 if ((nu
->type
& 7)==CU_POLY
) resolu
=1;
1943 if (subdivs
==cursubdiv
) {
1950 if (cursubdiv
< subdivs
) {
1951 ratio
= 1.0 - ((subdivs
- cursubdiv
)/(float)resolu
);
1958 if ( ((nu
->type
& 7)==CU_NURBS
) && (nu
->flagu
& CU_CYCLIC
)) {
1959 if (bp
>= bplast
) bp
= bpfirst
;
1961 } else if ( bp
>= bplast
) {
1962 /* this can happen in rare cases, refer to bug [#8596] */
1966 rad
= prevrad
= bp
->radius
;
1968 if ((bp
== bplast
) && (nu
->flagu
& CU_CYCLIC
)) { /* loop around */
1970 } else if (bp
!= bplast
) {
1973 nextrad
= bp
->radius
;
1978 if (nextrad
!= prevrad
) {
1979 /* smooth interpolation */
1980 rad
= prevrad
+ (nextrad
-prevrad
)*(3.0f
*ratio
*ratio
- 2.0f
*ratio
*ratio
*ratio
);
1989 /* ****************** HANDLES ************** */
1993 * 1: nothing, 1:auto, 2:vector, 3:aligned
1996 /* mode: is not zero when IpoCurve, is 2 when forced horizontal for autohandles */
1997 void calchandleNurb(BezTriple
*bezt
, BezTriple
*prev
, BezTriple
*next
, int mode
)
1999 float *p1
,*p2
,*p3
, pt
[3];
2000 float dx1
,dy1
,dz1
,dx
,dy
,dz
,vx
,vy
,vz
,len
,len1
,len2
;
2002 if(bezt
->h1
==0 && bezt
->h2
==0) return;
2008 pt
[0]= 2*p2
[0]- p3
[0];
2009 pt
[1]= 2*p2
[1]- p3
[1];
2010 pt
[2]= 2*p2
[2]- p3
[2];
2013 else p1
= prev
->vec
[1];
2016 pt
[0]= 2*p2
[0]- p1
[0];
2017 pt
[1]= 2*p2
[1]- p1
[1];
2018 pt
[2]= 2*p2
[2]- p1
[2];
2021 else p3
= next
->vec
[1];
2028 else len1
= (float)sqrt(dx
*dx
+dy
*dy
+dz
*dz
);
2035 else len2
= (float)sqrt(dx1
*dx1
+dy1
*dy1
+dz1
*dz1
);
2037 if(len1
==0.0f
) len1
=1.0f
;
2038 if(len2
==0.0f
) len2
=1.0f
;
2041 if(bezt
->h1
==HD_AUTO
|| bezt
->h2
==HD_AUTO
) { /* auto */
2042 vx
= dx1
/len2
+ dx
/len1
;
2043 vy
= dy1
/len2
+ dy
/len1
;
2044 vz
= dz1
/len2
+ dz
/len1
;
2045 len
= 2.5614f
*(float)sqrt(vx
*vx
+ vy
*vy
+ vz
*vz
);
2047 int leftviolate
=0, rightviolate
=0; /* for mode==2 */
2049 if(len1
>5.0f
*len2
) len1
= 5.0f
*len2
;
2050 if(len2
>5.0f
*len1
) len2
= 5.0f
*len1
;
2052 if(bezt
->h1
==HD_AUTO
) {
2054 *(p2
-3)= *p2
-vx
*len1
;
2055 *(p2
-2)= *(p2
+1)-vy
*len1
;
2056 *(p2
-1)= *(p2
+2)-vz
*len1
;
2058 if(mode
==2 && next
&& prev
) { // keep horizontal if extrema
2059 float ydiff1
= prev
->vec
[1][1] - bezt
->vec
[1][1];
2060 float ydiff2
= next
->vec
[1][1] - bezt
->vec
[1][1];
2061 if( (ydiff1
<=0.0 && ydiff2
<=0.0) || (ydiff1
>=0.0 && ydiff2
>=0.0) ) {
2062 bezt
->vec
[0][1]= bezt
->vec
[1][1];
2064 else { // handles should not be beyond y coord of two others
2066 if(prev
->vec
[1][1] > bezt
->vec
[0][1]) {
2067 bezt
->vec
[0][1]= prev
->vec
[1][1];
2072 if(prev
->vec
[1][1] < bezt
->vec
[0][1]) {
2073 bezt
->vec
[0][1]= prev
->vec
[1][1];
2080 if(bezt
->h2
==HD_AUTO
) {
2082 *(p2
+3)= *p2
+vx
*len2
;
2083 *(p2
+4)= *(p2
+1)+vy
*len2
;
2084 *(p2
+5)= *(p2
+2)+vz
*len2
;
2086 if(mode
==2 && next
&& prev
) { // keep horizontal if extrema
2087 float ydiff1
= prev
->vec
[1][1] - bezt
->vec
[1][1];
2088 float ydiff2
= next
->vec
[1][1] - bezt
->vec
[1][1];
2089 if( (ydiff1
<=0.0 && ydiff2
<=0.0) || (ydiff1
>=0.0 && ydiff2
>=0.0) ) {
2090 bezt
->vec
[2][1]= bezt
->vec
[1][1];
2092 else { // handles should not be beyond y coord of two others
2094 if(next
->vec
[1][1] < bezt
->vec
[2][1]) {
2095 bezt
->vec
[2][1]= next
->vec
[1][1];
2100 if(next
->vec
[1][1] > bezt
->vec
[2][1]) {
2101 bezt
->vec
[2][1]= next
->vec
[1][1];
2108 if(leftviolate
|| rightviolate
) { /* align left handle */
2111 VecSubf(h1
, p2
-3, p2
);
2112 VecSubf(h2
, p2
, p2
+3);
2113 len1
= Normalize(h1
);
2114 len2
= Normalize(h2
);
2119 *(p2
+3)= *(p2
) - vz
*len2
*h1
[0];
2120 *(p2
+4)= *(p2
+1) - vz
*len2
*h1
[1];
2121 *(p2
+5)= *(p2
+2) - vz
*len2
*h1
[2];
2124 *(p2
-3)= *(p2
) + vz
*len1
*h2
[0];
2125 *(p2
-2)= *(p2
+1) + vz
*len1
*h2
[1];
2126 *(p2
-1)= *(p2
+2) + vz
*len1
*h2
[2];
2133 if(bezt
->h1
==HD_VECT
) { /* vector */
2138 *(p2
-2)= *(p2
+1)-dy
;
2139 *(p2
-1)= *(p2
+2)-dz
;
2141 if(bezt
->h2
==HD_VECT
) {
2146 *(p2
+4)= *(p2
+1)+dy1
;
2147 *(p2
+5)= *(p2
+2)+dz1
;
2150 len2
= VecLenf(p2
, p2
+3);
2151 len1
= VecLenf(p2
, p2
-3);
2152 if(len1
==0.0) len1
=1.0;
2153 if(len2
==0.0) len2
=1.0;
2155 if(bezt
->f1
& 1) { /* order of calculation */
2156 if(bezt
->h2
==HD_ALIGN
) { /* aligned */
2158 p2
[3]= p2
[0]+len
*(p2
[0]-p2
[-3]);
2159 p2
[4]= p2
[1]+len
*(p2
[1]-p2
[-2]);
2160 p2
[5]= p2
[2]+len
*(p2
[2]-p2
[-1]);
2162 if(bezt
->h1
==HD_ALIGN
) {
2164 p2
[-3]= p2
[0]+len
*(p2
[0]-p2
[3]);
2165 p2
[-2]= p2
[1]+len
*(p2
[1]-p2
[4]);
2166 p2
[-1]= p2
[2]+len
*(p2
[2]-p2
[5]);
2170 if(bezt
->h1
==HD_ALIGN
) {
2172 p2
[-3]= p2
[0]+len
*(p2
[0]-p2
[3]);
2173 p2
[-2]= p2
[1]+len
*(p2
[1]-p2
[4]);
2174 p2
[-1]= p2
[2]+len
*(p2
[2]-p2
[5]);
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]);
2185 void calchandlesNurb(Nurb
*nu
) /* first, if needed, set handle flags */
2187 BezTriple
*bezt
, *prev
, *next
;
2190 if((nu
->type
& 7)!=CU_BEZIER
) return;
2191 if(nu
->pntsu
<2) return;
2195 if(nu
->flagu
& 1) prev
= bezt
+(a
-1);
2200 calchandleNurb(bezt
, prev
, next
, 0);
2203 if(nu
->flagu
& 1) next
= nu
->bezt
;
2213 void testhandlesNurb(Nurb
*nu
)
2215 /* use when something has changed with handles.
2216 it treats all BezTriples with the following rules:
2217 PHASE 1: do types have to be altered?
2218 Auto handles: become aligned when selection status is NOT(000 || 111)
2219 Vector handles: become 'nothing' when (one half selected AND other not)
2220 PHASE 2: recalculate handles
2225 if((nu
->type
& 7)!=CU_BEZIER
) return;
2231 if(bezt
->f1
& 1) flag
++;
2232 if(bezt
->f2
& 1) flag
+= 2;
2233 if(bezt
->f3
& 1) flag
+= 4;
2235 if( !(flag
==0 || flag
==7) ) {
2236 if(bezt
->h1
==HD_AUTO
) { /* auto */
2239 if(bezt
->h2
==HD_AUTO
) { /* auto */
2243 if(bezt
->h1
==HD_VECT
) { /* vector */
2244 if(flag
< 4) bezt
->h1
= 0;
2246 if(bezt
->h2
==HD_VECT
) { /* vector */
2247 if( flag
> 3) bezt
->h2
= 0;
2253 calchandlesNurb(nu
);
2256 void autocalchandlesNurb(Nurb
*nu
, int flag
)
2258 /* checks handle coordinates and calculates type */
2260 BezTriple
*bezt2
, *bezt1
, *bezt0
;
2261 int i
, align
, leftsmall
, rightsmall
;
2263 if(nu
==0 || nu
->bezt
==0) return;
2266 bezt1
= bezt2
+ (nu
->pntsu
-1);
2272 align
= leftsmall
= rightsmall
= 0;
2275 if(flag
==0 || (bezt1
->f1
& flag
) ) {
2277 /* distance too short: vectorhandle */
2278 if( VecLenf( bezt1
->vec
[1], bezt0
->vec
[1] ) < 0.0001) {
2283 /* aligned handle? */
2284 if(DistVL2Dfl(bezt1
->vec
[1], bezt1
->vec
[0], bezt1
->vec
[2]) < 0.0001) {
2286 bezt1
->h1
= HD_ALIGN
;
2288 /* or vector handle? */
2289 if(DistVL2Dfl(bezt1
->vec
[0], bezt1
->vec
[1], bezt0
->vec
[1]) < 0.0001)
2295 if(flag
==0 || (bezt1
->f3
& flag
) ) {
2297 /* distance too short: vectorhandle */
2298 if( VecLenf( bezt1
->vec
[1], bezt2
->vec
[1] ) < 0.0001) {
2303 /* aligned handle? */
2304 if(align
) bezt1
->h2
= HD_ALIGN
;
2306 /* or vector handle? */
2307 if(DistVL2Dfl(bezt1
->vec
[2], bezt1
->vec
[1], bezt2
->vec
[1]) < 0.0001)
2312 if(leftsmall
&& bezt1
->h2
==HD_ALIGN
) bezt1
->h2
= 0;
2313 if(rightsmall
&& bezt1
->h1
==HD_ALIGN
) bezt1
->h1
= 0;
2315 /* undesired combination: */
2316 if(bezt1
->h1
==HD_ALIGN
&& bezt1
->h2
==HD_VECT
) bezt1
->h1
= 0;
2317 if(bezt1
->h2
==HD_ALIGN
&& bezt1
->h1
==HD_VECT
) bezt1
->h2
= 0;
2324 calchandlesNurb(nu
);
2327 void autocalchandlesNurb_all(int flag
)
2333 autocalchandlesNurb(nu
, flag
);
2338 void sethandlesNurb(short code
)
2340 /* code==1: set autohandle */
2341 /* code==2: set vectorhandle */
2342 /* code==3 (HD_ALIGN) it toggle, vectorhandles become HD_FREE */
2343 /* code==4: sets icu flag to become IPO_AUTO_HORIZ, horizontal extremes on auto-handles */
2348 if(code
==1 || code
==2) {
2351 if( (nu
->type
& 7)==1) {
2355 if(bezt
->f1
|| bezt
->f3
) {
2356 if(bezt
->f1
) bezt
->h1
= code
;
2357 if(bezt
->f3
) bezt
->h2
= code
;
2358 if(bezt
->h1
!=bezt
->h2
) {
2359 if ELEM(bezt
->h1
, HD_ALIGN
, HD_AUTO
) bezt
->h1
= HD_FREE
;
2360 if ELEM(bezt
->h2
, HD_ALIGN
, HD_AUTO
) bezt
->h2
= HD_FREE
;
2365 calchandlesNurb(nu
);
2371 /* there is 1 handle not FREE: FREE it all, else make ALIGNED */
2375 if( (nu
->type
& 7)==1) {
2379 if(bezt
->f1
&& bezt
->h1
) ok
= 1;
2380 if(bezt
->f3
&& bezt
->h2
) ok
= 1;
2392 if( (nu
->type
& 7)==1) {
2396 if(bezt
->f1
) bezt
->h1
= ok
;
2397 if(bezt
->f3
) bezt
->h2
= ok
;
2401 calchandlesNurb(nu
);
2408 static void swapdata(void *adr1
, void *adr2
, int len
)
2416 memcpy(adr
, adr1
, len
);
2417 memcpy(adr1
, adr2
, len
);
2418 memcpy(adr2
, adr
, len
);
2423 adr
= (char *)MEM_mallocN(len
, "curve swap");
2424 memcpy(adr
, adr1
, len
);
2425 memcpy(adr1
, adr2
, len
);
2426 memcpy(adr2
, adr
, len
);
2431 void switchdirectionNurb(Nurb
*nu
)
2433 BezTriple
*bezt1
, *bezt2
;
2435 float *fp1
, *fp2
, *tempf
;
2438 if(nu
->pntsu
==1 && nu
->pntsv
==1) return;
2440 if((nu
->type
& 7)==CU_BEZIER
) {
2444 if(a
& 1) a
+= 1; /* if odd, also swap middle content */
2447 if(bezt1
!=bezt2
) SWAP(BezTriple
, *bezt1
, *bezt2
);
2449 swapdata(bezt1
->vec
[0], bezt1
->vec
[2], 12);
2450 if(bezt1
!=bezt2
) swapdata(bezt2
->vec
[0], bezt2
->vec
[2], 12);
2452 SWAP(char, bezt1
->h1
, bezt1
->h2
);
2453 SWAP(short, bezt1
->f1
, bezt1
->f3
);
2456 SWAP(char, bezt2
->h1
, bezt2
->h2
);
2457 SWAP(short, bezt2
->f1
, bezt2
->f3
);
2458 bezt1
->alfa
= -bezt1
->alfa
;
2459 bezt2
->alfa
= -bezt2
->alfa
;
2466 else if(nu
->pntsv
==1) {
2471 while(bp1
!=bp2
&& a
>0) {
2472 SWAP(BPoint
, *bp1
, *bp2
);
2474 bp1
->alfa
= -bp1
->alfa
;
2475 bp2
->alfa
= -bp2
->alfa
;
2479 if((nu
->type
& 7)==CU_NURBS
) {
2485 while(fp1
!=fp2
&& a
>0) {
2486 SWAP(float, *fp1
, *fp2
);
2491 /* and make in increasing order again */
2494 fp2
=tempf
= MEM_mallocN(sizeof(float)*a
, "switchdirect");
2496 fp2
[0]= fabs(fp1
[1]-fp1
[0]);
2507 fp1
[0]= fp1
[-1]+fp2
[0];
2516 for(b
=0; b
<nu
->pntsv
; b
++) {
2518 bp1
= nu
->bp
+b
*nu
->pntsu
;
2523 while(bp1
!=bp2
&& a
>0) {
2524 SWAP(BPoint
, *bp1
, *bp2
);
2534 float (*curve_getVertexCos(Curve
*cu
, ListBase
*lb
, int *numVerts_r
))[3]
2536 int i
, numVerts
= *numVerts_r
= count_curveverts(lb
);
2537 float *co
, (*cos
)[3] = MEM_mallocN(sizeof(*cos
)*numVerts
, "cu_vcos");
2541 for (nu
=lb
->first
; nu
; nu
=nu
->next
) {
2542 if ((nu
->type
& 7)==CU_BEZIER
) {
2543 BezTriple
*bezt
= nu
->bezt
;
2545 for (i
=0; i
<nu
->pntsu
; i
++,bezt
++) {
2546 VECCOPY(co
, bezt
->vec
[0]); co
+=3;
2547 VECCOPY(co
, bezt
->vec
[1]); co
+=3;
2548 VECCOPY(co
, bezt
->vec
[2]); co
+=3;
2551 BPoint
*bp
= nu
->bp
;
2553 for (i
=0; i
<nu
->pntsu
*nu
->pntsv
; i
++,bp
++) {
2554 VECCOPY(co
, bp
->vec
); co
+=3;
2562 void curve_applyVertexCos(Curve
*cu
, ListBase
*lb
, float (*vertexCos
)[3])
2564 float *co
= vertexCos
[0];
2568 for (nu
=lb
->first
; nu
; nu
=nu
->next
) {
2569 if ((nu
->type
& 7)==CU_BEZIER
) {
2570 BezTriple
*bezt
= nu
->bezt
;
2572 for (i
=0; i
<nu
->pntsu
; i
++,bezt
++) {
2573 VECCOPY(bezt
->vec
[0], co
); co
+=3;
2574 VECCOPY(bezt
->vec
[1], co
); co
+=3;
2575 VECCOPY(bezt
->vec
[2], co
); co
+=3;
2578 BPoint
*bp
= nu
->bp
;
2580 for (i
=0; i
<nu
->pntsu
*nu
->pntsv
; i
++,bp
++) {
2581 VECCOPY(bp
->vec
, co
); co
+=3;